Posted by mazet on 02 Jun 2021 in C
Shell
/* -*- Mode: C; indent-tabs-mode: t; c-basic-offset: 4; tab-width: 4 -*- */ | |
| |
/* depend: */ | |
/* cflags: */ | |
/* linker: */ | |
| |
#include <getopt.h> | |
#include <signal.h> | |
#include <stdio.h> | |
#include <stdlib.h> | |
//#include <sys/types.h> | |
#include <sys/wait.h> | |
#include <unistd.h> | |
| |
/* macros */ | |
| |
#define CEIL(x, y) (((x) + (y) - 1) / (y)) | |
#define MIN(x, y) (((x) < (y)) ? (x) : (y)) | |
#define MAX(x, y) (((x) > (y)) ? (x) : (y)) | |
#define VERBOSE(level, statement...) do { if (level <= verbose) { statement; } } while(0) | |
| |
/* gobal variables */ | |
| |
char *progname = NULL; | |
int verbose = 0; | |
| |
/* help function */ | |
| |
void usage (int ret) | |
{ | |
FILE *fd = ret ? stderr : stdout; | |
fprintf (fd, "usage: %s\n", progname); | |
fprintf (fd, " -h : help message\n"); | |
fprintf (fd, " -r : respawn on error\n"); | |
fprintf (fd, " -v : verbose level (%d)\n", verbose); | |
| |
exit (ret); | |
} | |
| |
/* child functions */ | |
| |
void signal_hello (int signal) { | |
printf ("child received signal %d, abnormal exit\n", signal); | |
fflush (stdout); | |
exit (1); | |
} | |
| |
void signal_stop (int signal) { | |
printf ("child received signal %d, stop process\n", signal); | |
fflush (stdout); | |
exit (0); | |
} | |
| |
int main_child (int argc, char *argv[]) { | |
/* start slave */ | |
signal (SIGUSR1, signal_hello); | |
signal (SIGUSR2, signal_stop); | |
while (1) { | |
usleep (100000); | |
} | |
return 0; | |
} | |
| |
/* master functions */ | |
| |
int main(int argc, char *argv[]) { | |
int respawn = 0; | |
| |
progname = argv[0]; | |
| |
int c; | |
while ((c = getopt(argc, argv, "hrv:")) != EOF) { | |
switch (c) { | |
case 'r': | |
respawn = 1; | |
case 'v': | |
verbose = atoi (optarg); | |
break; | |
case 'h': | |
default: | |
usage (c != 'h'); | |
} | |
} | |
if (argc - optind != 0) { | |
fprintf (stderr, "%s: invalid option -- %s\n", progname, argv[optind]); | |
usage (1); | |
} | |
| |
/* no respawn */ | |
if (!respawn) { | |
return main_child(argc, argv); | |
} | |
| |
/* fork and respawn */ | |
int rc = -1; | |
while (rc) { | |
int pid = fork (); | |
if (pid == 0) { | |
return main_child(argc, argv); | |
} | |
printf ("child %d started\n", pid); | |
fflush (stdout); | |
| |
wait (&rc); | |
printf ("child %d (rc %d) dead\n", pid, rc); | |
fflush (stdout); | |
if (rc) { | |
printf ("respawn child\n"); | |
fflush (stdout); | |
} | |
} | |
| |
return 0; | |
} | |
| |
/* test: ./dameon -h */ | |
/* test: ./daemon | tee daemon.output& sleep 1; kill -USR1 $(awk '/started/ {p=$2} END {print p}' daemon.output); sleep 1; killall -9 ./daemon; [ x$(grep -c started daemon.output) = x1 ] && grep -q received daemon.output */ | |
/* test: ./daemon -r | tee daemon.output& sleep 1; kill -USR1 $(awk '/started/ {p=$2} END {print p}' daemon.output); sleep 1; killall -9 ./daemon; [ x$(grep -c started daemon.output) = x2 ] && grep -q received daemon.output */ | |
/* test: ./daemon -r | tee daemon.output& sleep 1; kill -ABRT $(awk '/started/ {p=$2} END {print p}' daemon.output); sleep 1; killall -9 ./daemon; test x$(grep -c started daemon.output) = x2 */ | |
/* test: ./daemon -r | tee daemon.output& sleep 1; kill -USR2 $(awk '/started/ {p=$2} END {print p}' daemon.output); sleep 1; killall -9 ./daemon; test x$(grep -c started daemon.output) = x1 */ |