1 /* Gateway Resource Monitor
5 * Revision 1.7 1995/05/03 12:18:46 adam
6 * This code ran on dtbsun. Minor changes.
8 * Revision 1.6 1995/05/03 09:16:17 adam
11 * Revision 1.5 1995/05/03 07:37:42 adam
12 * CCL commands stop/continue implemented. New functions gw_res_{int,bool}
13 * are used when possible.
15 * Revision 1.4 1995/05/02 15:26:00 adam
16 * Monitor observes death of child (email kernel). The number
17 * of simultanous processes is controlled now. Email requests are
18 * queued if necessary. This scheme should only be forced if no kernels
21 * Revision 1.3 1995/05/02 07:20:10 adam
22 * Use pid of exited child to close fifos.
24 * Revision 1.2 1995/05/01 16:26:57 adam
25 * More work on resource monitor.
27 * Revision 1.1 1995/05/01 12:43:36 adam
28 * First work on resource monitor program.
45 #include <sys/types.h>
57 #define MONITOR_FIFO_S "fifo.s.m"
58 #define MONITOR_FIFO_C "fifo.c.m"
60 static char *module = "monitor";
61 static jmp_buf retry_jmp;
63 static GwRes monitor_res = NULL;
64 static int no_process = 0;
65 static int max_process = 1;
66 static int got_sighup = 0;
67 static int got_term = 0;
68 static int got_int = 0;
69 const char *default_res = "default.res";
72 * reread_resources: reread monitor resources. The static variable,
73 * max_process, is updated.
75 static void reread_resources (void)
78 gw_res_close (monitor_res);
79 monitor_res = gw_res_init ();
80 if (gw_res_merge (monitor_res, default_res))
82 gw_log (GW_LOG_WARN, module, "Couldn't read resource file %s",
86 max_process = gw_res_int (monitor_res, "gw.max.process", 10);
90 int id; /* email user-id */
91 pid_t pid; /* pid of email kernel child */
92 GIP gip; /* fifo information */
93 struct str_queue *queue; /* message queue */
94 struct ke_info *next; /* link to next */
97 /* list of email kernel infos */
98 static struct ke_info *ke_info_list = NULL;
101 * ke_info_add: add/lookup of email kernel info.
102 * id: email user-id to search for.
103 * return: pointer to info structure.
105 struct ke_info *ke_info_add (int id)
107 struct ke_info **kip;
109 for (kip = &ke_info_list; *kip; kip= &(*kip)->next)
110 if ((*kip)->id == id)
112 *kip = malloc (sizeof(**kip));
117 (*kip)->queue = NULL;
121 static void ke_info_del (void)
125 assert (ke_info_list);
127 str_queue_rm (&ki->queue);
128 ke_info_list = ki->next;
133 * catch_child: catch SIGCHLD. Set email kernel pid to -1
134 * to indicate that child has exited
136 static void catch_child (int num)
141 while ((pid=waitpid (-1, 0, WNOHANG)) > 0)
143 for (ki = ke_info_list; ki; ki = ki->next)
148 signal (SIGCHLD, catch_child);
152 * catch_int: catch SIGHUP.
154 static void catch_hup (int num)
157 signal (SIGHUP, catch_hup);
161 * catch_int: catch SIGTERM.
163 static void catch_term (int num)
166 signal (SIGTERM, catch_term);
170 * catch_int: catch SIGINT.
172 static void catch_int (int num)
175 signal (SIGINT, catch_int);
179 * pipe_handle: handle SIGPIPE when transferring message to kernel
181 static void pipe_handle (int dummy)
183 longjmp (retry_jmp, 1);
187 * start_kernel: start email kernel.
188 * argc: argc of email kernel
189 * argv: argv of email kernel
191 * return: pid of email kernel child
193 static pid_t start_kernel (int argc, char **argv, int id)
198 char userid_option[20];
200 argv_p = malloc (sizeof(*argv_p)*(argc+2));
203 gw_log (GW_LOG_FATAL|GW_LOG_ERRNO, module, "malloc fail");
206 argv_p[0] = "kernel";
207 for (i = 1; i<argc; i++)
209 sprintf (userid_option, "-i%d", id);
210 argv_p[i++] = userid_option;
213 gw_log (GW_LOG_DEBUG, module, "Starting kernel");
217 gw_log (GW_LOG_FATAL|GW_LOG_ERRNO, module, "fork");
222 execv ("kernel", argv_p);
223 gw_log (GW_LOG_FATAL|GW_LOG_ERRNO, module, "execvp");
230 * deliver: deliver message to child (email kernel).
231 * argc: exec argc to child (if it need to be started)
232 * argv: exec argv to child (if it need to be started)
234 * queue: message queue to be transferred
235 * gip: pointer to FIFO info. if *gip is NULL prior invocation
236 * it will be created (initialized) and the pointer will be
238 * pidp: pointer to pid. Will hold process-id of child (if it need to
240 * dont_exec: if non-zero a child will never be started; otherwise child
241 * will be started if not already running.
242 * return: 0 if message couldn't be transferred, i.e. dont_exec is non-zero
243 * and the child is not already running.
244 * 1 if message was transferred and the child was already running.
245 * 2 if message was transferred and the child was started and
246 * dont_exec was zero.
247 * 3 serious error. Permissions denied or kernel couldn't be
250 static int deliver (int argc, char **argv, int id, struct str_queue *queue,
251 GIP *gip, pid_t *pidp, int dont_exec)
256 char fifo_server_name[128];
257 char fifo_client_name[128];
261 sprintf (fifo_server_name, "fifo.s.%d", id);
262 sprintf (fifo_client_name, "fifo.c.%d", id);
266 *gip = gipc_initialize (fifo_client_name);
268 oldsig = signal (SIGPIPE, pipe_handle);
272 { /* assume child is running */
273 gipc_close (*gip); /* shut down existing FIFOs */
274 r = gipc_open (*gip, fifo_server_name, 0); /* try re-open ... */
277 { /* assume child is NOT running */
281 { /* we aren't allowed to start */
282 signal (SIGPIPE, oldsig);
285 mknod (fifo_server_name, S_IFIFO|0666, 0);
286 pid = start_kernel (argc, argv, id);
287 if (pidp) /* set pid of child */
289 r = gipc_open (*gip, fifo_server_name, 1);
292 { /* message couldn't be transferred */
293 signal (SIGPIPE, oldsig);
294 gw_log (GW_LOG_WARN, module, "Cannot start kernel");
297 if (r < 0) /* gipc_open fail? */
300 gw_log (GW_LOG_DEBUG|GW_LOG_ERRNO, module, "r==-2");
302 gw_log (GW_LOG_DEBUG|GW_LOG_ERRNO, module, "r==-1");
304 gw_log (GW_LOG_WARN|GW_LOG_ERRNO, module, "gipc_open");
305 longjmp (retry_jmp, 1); /* yet another pass */
307 index = 0; /* transfer. may be interrupted */
308 while ((msg = str_queue_get (queue, index++)))
309 gip_wline (*gip, msg);
310 signal (SIGPIPE, oldsig);
311 return pass; /* successful transfer */
315 * monitor_events: Event loop of monitor
316 * argc: argc of monitor (used in exec of Email kernel children)
317 * argv: argv of monitor (used in exec of Email kernel children)
319 static void monitor_events (int argc, char **argv)
325 char command[128], *cp;
327 gip_m = gips_initialize (MONITOR_FIFO_S);
328 r = gips_open (gip_m, MONITOR_FIFO_C);
329 gip_m_fd = gip_infileno (gip_m);
330 open (MONITOR_FIFO_S, O_WRONLY);
341 gw_log (GW_LOG_STAT, module, "Got SIGHUP. Reading resources");
347 gw_log (GW_LOG_STAT, module, "Got SIGTERM. Exiting...");
348 unlink (MONITOR_FIFO_S);
349 unlink (MONITOR_FIFO_C);
354 gw_log (GW_LOG_STAT, module, "Got SIGINT. Exiting...");
355 unlink (MONITOR_FIFO_S);
356 unlink (MONITOR_FIFO_C);
359 /* deliver any unsent messages to Email kernels */
360 for (ki = ke_info_list; ki; ki = ki->next)
364 gw_log (GW_LOG_DEBUG, module, "Transfer mail to %d", ki->id);
365 r = deliver (argc, argv, ki->id, ki->queue, &ki->gip, &ki->pid,
366 no_process >= max_process);
367 if (r == 2) /* new child was spawned? */
369 if (r == 1 || r == 2) /* transfer at all? */
370 str_queue_rm (&ki->queue);
373 FD_SET (gip_m_fd, &set_r);
374 gw_log (GW_LOG_DEBUG, module, "set gip_m_fd %d", gip_m_fd);
377 for (ki = ke_info_list; ki; ki = ki->next)
383 { /* child has exited */
384 gw_log (GW_LOG_DEBUG, module, "Close of %d", ki->id);
385 gipc_close (ki->gip);
386 gipc_destroy (ki->gip);
389 else if ((fd = gip_infileno (ki->gip)) != -1)
390 { /* read select on child FIFO */
391 gw_log (GW_LOG_DEBUG, module, "set fd %d", fd);
398 gw_log (GW_LOG_DEBUG, module, "Cur/Max processes %d/%d",
399 no_process, max_process);
400 gw_log (GW_LOG_DEBUG, module, "IPC select");
401 r = select (fd_max+1, &set_r, NULL, NULL, NULL);
405 { /* select aborted. And it was not due to interrupt */
406 gw_log (GW_LOG_FATAL|GW_LOG_ERRNO, module, "select");
409 /* select was interrupted. Probably child has died */
410 gw_log (GW_LOG_DEBUG|GW_LOG_ERRNO, module, "select");
412 /* go through list of Email kernels. See if any message has arrived */
413 gw_log (GW_LOG_DEBUG, module, "Testing ke_info_list");
414 for (ki = ke_info_list; ki; ki = ki->next)
417 if (ki->gip && (fd = gip_infileno (ki->gip)) != -1)
419 gw_log (GW_LOG_DEBUG, module, "Test of %d", fd);
420 if (FD_ISSET (fd, &set_r))
422 if (lgets (line_buf, sizeof(line_buf)-1, fd))
424 gw_log (GW_LOG_DEBUG, module, "IPC: %s", line_buf);
428 gw_log (GW_LOG_DEBUG, module, "Close of %d", ki->id);
429 gipc_close (ki->gip);
430 gipc_destroy (ki->gip);
436 /* see if any message from eti has arrived */
437 gw_log (GW_LOG_DEBUG, module, "Testing gip_m_fd %d", gip_m_fd);
438 if (FD_ISSET (gip_m_fd, &set_r))
440 gw_log (GW_LOG_DEBUG, module, "Reading from %d", gip_m_fd);
441 if (!(lgets (command, sizeof(command)-1, gip_m_fd)))
443 gw_log (GW_LOG_FATAL, module, "Unexpected close");
446 gw_log (GW_LOG_DEBUG, module, "Done");
447 if ((cp = strchr (command, '\n')))
449 gw_log (GW_LOG_DEBUG, module, "IPC: %s", command);
450 if (!memcmp (command, "eti ", 4))
452 int id = atoi (command+4);
453 struct ke_info *new_k;
455 new_k = ke_info_add (id);
456 gw_log (GW_LOG_DEBUG, module, "Incoming mail %d", id);
460 if (!(new_k->queue = str_queue_mk ()))
462 gw_log (GW_LOG_FATAL|GW_LOG_ERRNO, module,
467 str_queue_enq (new_k->queue, "mail\n");
468 while (lgets (line_buf, sizeof(line_buf)-1, gip_m_fd))
469 str_queue_enq (new_k->queue, line_buf);
470 str_queue_enq (new_k->queue, "\001");
477 * main: main of monitor
479 int main (int argc, char **argv)
484 while (++argno < argc)
486 if (argv[argno][0] == '-')
488 switch (argv[argno][1])
491 fprintf (stderr, "monitor [option..] [resource]\n");
492 fprintf (stderr, "If no resource file is given");
493 fprintf (stderr, " default.res is used\n");
494 fprintf (stderr, "Options are transferred to kernel\n");
497 gw_log_level (GW_LOG_ALL & ~RES_DEBUG);
500 gw_log_level (GW_LOG_ALL);
505 default_res = argv[argno];
508 signal (SIGCHLD, catch_child);
509 signal (SIGHUP, catch_hup);
510 signal (SIGTERM, catch_term);
511 signal (SIGINT, catch_int);
513 gw_log_file (GW_LOG_ALL, "monitor.log");
515 monitor_events (argc, argv);