acl: cli addition to set macip rules
[vpp.git] / src / plugins / fateshare / vpp_fateshare_monitor.c
1 #include <stdio.h>
2 #include <stdlib.h>
3 #include <unistd.h>
4
5 #include <sys/types.h>
6 #include <sys/wait.h>
7 #ifdef __linux__
8 #include <sys/prctl.h> // prctl(), PR_SET_PDEATHSIG
9 #else
10 #include <signal.h>
11 #include <sys/procctl.h>
12 #endif /* __linux__ */
13
14 #include <sys/stat.h>
15 #include <fcntl.h>
16 #include <limits.h>
17
18 typedef struct
19 {
20   pid_t pid;
21   char *cmd;
22 } child_record_t;
23
24 int n_children = 0;
25 child_record_t *children = NULL;
26
27 static void
28 child_handler (int sig)
29 {
30   pid_t pid;
31   int status;
32
33   while ((pid = waitpid (-1, &status, WNOHANG)) > 0)
34     {
35       int i;
36       printf ("fateshare: pid %d quit with status %d\n", pid, status);
37       for (i = 0; i < n_children; i++)
38         {
39           if (children[i].pid == pid)
40             {
41               children[i].pid = 0;
42             }
43         }
44     }
45 }
46
47 static void
48 term_handler (int sig)
49 {
50   int i;
51
52   printf ("fateshare: terminating!\n");
53   for (i = 0; i < n_children; i++)
54     {
55       kill (-children[i].pid, SIGTERM);
56     }
57   exit (0);
58 }
59
60 static void
61 hup_handler (int sig)
62 {
63   int i;
64
65   printf ("fateshare: terminating all the child processes!\n");
66   for (i = 0; i < n_children; i++)
67     {
68       kill (-children[i].pid, SIGTERM);
69     }
70 }
71
72 pid_t
73 launch_command (char *scmd, char *logname_base)
74 {
75   pid_t ppid_before_fork = getpid ();
76   pid_t cpid = fork ();
77   if (cpid == -1)
78     {
79       perror ("fork");
80       sleep (1);
81       return 0;
82     }
83   if (cpid)
84     {
85       /* parent */
86       return cpid;
87     }
88
89   /* child */
90 #ifdef __linux__
91   int r = prctl (PR_SET_PDEATHSIG, SIGTERM);
92   if (r == -1)
93     {
94       perror ("prctl");
95       sleep (5);
96       exit (1);
97     }
98 #else
99   int r, s = SIGTERM;
100
101   r = procctl (P_PID, 0, PROC_PDEATHSIG_CTL, &s);
102   if (r == -1)
103     {
104       perror ("procctl");
105       exit (1);
106     }
107 #endif /* __linux__ */
108
109   if (getppid () != ppid_before_fork)
110     {
111       sleep (5);
112       exit (1);
113     }
114
115   int r1 = setpgid (getpid (), 0);
116   if (r1 != 0)
117     {
118       perror ("setpgid error");
119       sleep (5);
120       exit (1);
121     }
122
123   int fd = open ("/dev/null", O_RDONLY);
124   if (fd < 0)
125     {
126       sleep (5);
127       exit (1);
128     }
129   while (fd >= 0)
130     {
131       close (fd);
132       fd--;
133     }
134   fd = open ("/dev/null", O_RDONLY);
135   if (fd < 0)
136     {
137       sleep (5);
138       exit (1);
139     }
140   dup2 (fd, 0);
141
142   char logname_stdout[PATH_MAX];
143   char logname_stderr[PATH_MAX];
144
145   snprintf (logname_stdout, PATH_MAX - 1, "%s-stdout.txt", logname_base);
146   snprintf (logname_stderr, PATH_MAX - 1, "%s-stderr.txt", logname_base);
147
148   printf ("LOG STDOUT %s: %s\n", scmd, logname_stdout);
149   printf ("LOG STDERR %s: %s\n", scmd, logname_stderr);
150
151   fd = open ((char *) logname_stdout, O_APPEND | O_RDWR | O_CREAT, 0777);
152   if (fd < 0)
153     {
154       sleep (5);
155       exit (1);
156     }
157   dup2 (fd, 1);
158   fd = open ((char *) logname_stderr, O_APPEND | O_RDWR | O_CREAT, 0777);
159   if (fd < 0)
160     {
161       sleep (5);
162       exit (1);
163     }
164   dup2 (fd, 2);
165
166   char *argv[] = { (char *) scmd, 0 };
167   int res = execv (argv[0], argv);
168   if (res != 0)
169     {
170       perror ("execve");
171     }
172   sleep (10);
173
174   exit (42);
175 }
176
177 int
178 main (int argc, char **argv)
179 {
180   pid_t ppid = getppid ();
181   int i = 0;
182   if (argc < 3)
183     {
184       printf ("usage: %s <parent_pid> <logfile-basename>\n", argv[0]);
185       exit (1);
186     }
187   char *errptr = 0;
188   pid_t parent_pid = strtoll (argv[1], &errptr, 10);
189   char *logname_base = argv[2];
190
191   printf ("DEBUG: pid %d starting for parent pid %d\n", getpid (), ppid);
192   printf ("DEBUG: parent pid: %d\n", parent_pid);
193   printf ("DEBUG: base log name: %s\n", logname_base);
194   if (*errptr)
195     {
196       printf ("%s is not a valid parent pid\n", errptr);
197       exit (2);
198     }
199
200 #ifdef __linux__
201   int r = prctl (PR_SET_PDEATHSIG, SIGTERM);
202   if (r == -1)
203     {
204       perror (0);
205       exit (1);
206     }
207 #else
208   int r, s = SIGTERM;
209
210   r = procctl (P_PID, 0, PROC_PDEATHSIG_CTL, &s);
211   if (r == -1)
212     {
213       perror ("procctl");
214       exit (1);
215     }
216 #endif /* __linux__ */
217
218   /* Establish handler. */
219   struct sigaction sa;
220   sigemptyset (&sa.sa_mask);
221   sa.sa_flags = 0;
222   sa.sa_handler = child_handler;
223
224   sigaction (SIGCHLD, &sa, NULL);
225
226   sigemptyset (&sa.sa_mask);
227   sa.sa_flags = 0;
228   sa.sa_handler = term_handler;
229
230   sigaction (SIGTERM, &sa, NULL);
231
232   sigemptyset (&sa.sa_mask);
233   sa.sa_flags = 0;
234   sa.sa_handler = hup_handler;
235
236   sigaction (SIGHUP, &sa, NULL);
237
238   if (getppid () != parent_pid)
239     {
240       printf ("parent process unexpectedly finished\n");
241       exit (3);
242     }
243
244   argc -= 3; /* skip over argv0, ppid, and log base */
245   argv += 3;
246
247   n_children = argc;
248   printf ("DEBUG: total %d children\n", n_children);
249   children = calloc (n_children, sizeof (children[0]));
250   for (i = 0; i < n_children; i++)
251     {
252       /* argv persists, so we can just use that pointer */
253       children[i].cmd = argv[i];
254       children[i].pid = launch_command (children[i].cmd, logname_base);
255       printf ("DEBUG: child %d (%s): initial launch pid %d\n", i,
256               children[i].cmd, children[i].pid);
257     }
258
259   while (1)
260     {
261       sleep (1);
262       pid_t curr_ppid = getppid ();
263       printf ("pid: %d, current ppid %d, original ppid %d\n", getpid (),
264               curr_ppid, ppid);
265       if (curr_ppid != ppid)
266         {
267           printf ("current ppid %d != original ppid %d - force quit\n",
268                   curr_ppid, ppid);
269           fflush (stdout);
270           exit (1);
271         }
272       int restarted = 0;
273       for (i = 0; i < n_children; i++)
274         {
275           if (children[i].pid == 0)
276             {
277               printf ("child %s exited, restarting\n", children[i].cmd);
278               restarted = 1;
279               children[i].pid = launch_command (children[i].cmd, logname_base);
280             }
281         }
282       if (restarted)
283         {
284           sleep (1);
285         }
286
287       fflush (stdout);
288     }
289 }