1 /* This file is part of the Project Athena Zephyr Notification System.
2 * It is one of the source files comprising zwgc, the Zephyr WindowGram
5 * Created by: Marc Horowitz <marc@athena.mit.edu>
7 * $Id: main.c,v 1.36 1999/01/22 23:20:22 ghudson Exp $
9 * Copyright (c) 1989 by the Massachusetts Institute of Technology.
10 * For copying and distribution information, see the file
19 #if (!defined(lint) && !defined(SABER))
20 static const char rcsid_main_c[] = "$Id: main.c,v 1.36 1999/01/22 23:20:22 ghudson Exp $";
24 #include <sys/socket.h>
25 #include <sys/resource.h>
26 #include <zephyr/mit-copyright.h>
27 #include <zephyr/zephyr.h>
29 #include "new_memory.h"
36 #include "subscriptions.h"
40 #include "variables.h"
43 extern void notice_handler();
44 static void process_notice(), setup_signals(), detach(), signal_exit();
46 static void notice_callback();
50 * Global zwgc-wide variables:
57 static char *zwgc_version_string = "1.0";
60 * description_filename_override - <<<>>>
63 static char *description_filename_override = NULL;
66 * progname - <<<>>> export!
69 char *progname = NULL;
72 * subscriptions_filename_override - <<<>>> export!
75 char *subscriptions_filename_override = NULL;
78 * location_override - <<<>>> export!
81 char *location_override = NULL;
85 * achannel - <<<>>> export!
88 ares_channel achannel;
91 /****************************************************************************/
93 /* Code to deal with reading in the description file: */
95 /****************************************************************************/
98 * program - this holds a pointer to the node representation of the
99 * description file once it has been read in.
102 static struct _Node *program = NULL;
108 static void fake_startup_packet()
114 var_set_variable("version", zwgc_version_string);
116 (void) memset(¬ice, 0, sizeof(notice));
118 notice.z_version = "";
119 notice.z_class = "WG_CTL_CLASS";
120 notice.z_class_inst = "WG_CTL_USER<<<>>>";
121 notice.z_opcode = "WG_STARTUP";
122 notice.z_default_format = "Zwgc mark II version $version now running...\n";
123 notice.z_recipient = "";
124 notice.z_sender = "ZWGC";
125 gettimeofday(¬ice.z_time,&tz);
127 notice.z_kind = ACKED;
128 notice.z_auth = ZAUTH_YES;
129 sprintf(msgbuf,"Zwgc mark II version %s now running...",
130 zwgc_version_string);
131 notice.z_message = msgbuf;
132 notice.z_message_len = strlen(notice.z_message)+1;
134 process_notice(¬ice, NULL);
137 static void read_in_description_file()
142 /* var_clear_all_variables(); <<<>>> */
144 sprintf(defdesc, "%s/zephyr/%s", DATADIR, DEFDESC);
145 input_file = locate_file(description_filename_override, USRDESC, defdesc);
147 program = parse_file(input_file);
151 fake_startup_packet();
154 /****************************************************************************/
156 /* Code to deal with argument parsing & overall control: */
158 /****************************************************************************/
162 * Effects: Prints out an usage message on stderr then exits the
163 * program with error code 1.
170 zwgc: usage: zwgc [-debug] [-f <filename>] [-subfile <filename>]\n\
171 [-ttymode] [-nofork] [-reenter] [-loc text]\n\
172 [-default <driver>] {-disable <driver>}*\n\
173 [output driver options]\n");
176 zwgc: usage: zwgc [-f <filename>] [-subfile <filename>]\n\
177 [-ttymode] [-nofork] [-reenter] [-loc text]\n\
178 [-default <driver>] {-disable <driver>}*\n\
179 [output driver options]\n");
188 static void run_initprogs()
191 * This code stolen from old zwgc: yuck. Clean up & fix. <<<>>>
192 * Should this fork instead of just systeming?
196 char *progname = ZGetVariable("initprogs");
201 status = system(progname);
203 perror("zwgc initprog exec");
204 fprintf(stderr,"zwgc initprog of <%s> failed: no shell.\n",
206 } else if (status!=-1 && status>>8) {
207 perror("zwgc initprog exec");
208 fprintf(stderr,"zwgc initprog of <%s> failed with status [%d].\n",
209 progname, status>>8);
214 * main -- the program entry point. Does parsing & top level control.
222 register char **current;
232 * Process "-f <filename>", "-subfile <filename>", "-nofork",
233 * "-reenter" (which is ignored) and (if DEBUG) "-debug"
234 * arguments, removing then from argc, argv:
236 for (new=current=argv+1; *current; current++) {
237 if (string_Eq(*current, "-debug")) {
242 } else if (string_Eq(*current, "-f")) {
243 argc -= 2; current++;
246 description_filename_override = *current;
247 } else if (string_Eq(*current, "-subfile")) {
248 argc -= 2; current++;
251 subscriptions_filename_override = *current;
252 } else if (string_Eq(*current, "-nofork")) {
255 } else if (string_Eq(*current, "-reenter")) {
256 argc--; /* just throw it away */
257 } else if (string_Eq(*current, "-loc")) {
258 argc -= 2; current++;
261 location_override = *current;
269 * Initialize resolver library
271 status = ares_init(&achannel);
272 if (status != ARES_SUCCESS) {
273 fprintf(stderr, "Couldn't initialize resolver: %s\n",
274 ares_strerror(status, &errmem));
275 ares_free_errmem(errmem);
281 * Initialize various subsystems in proper order:
283 dprintf("Initializing subsystems...\n"); /*<<<>>>*/
285 var_clear_all_variables(); /* <<<>>> */
286 init_ports(); /* <<<>>> */
287 dprintf("Initializing standard ports...\n");
288 init_standard_ports(&argc, argv);
291 dprintf("Initializing zephyr...\n");
292 setup_signals(dofork);
293 zephyr_init(notice_handler);
298 * Run the initprogs program(s) now that we are all set to deal:
300 dprintf("Running initprogs program...\n");
303 dprintf("Test Zwgc parser.\n\n");
304 read_in_description_file();
306 dprintf("Entering main loop\n");
309 dprintf("Returning from main loop\n");
315 /****************************************************************************/
319 /****************************************************************************/
321 #define USER_SUPPRESS "SUPPRESS"
322 #define USER_UNSUPPRESS "UNSUPPRESS"
324 void notice_handler(notice)
327 struct hostent *fromhost = NULL;
329 if (notice->z_sender_addr.s_addr) {
331 ares_gethostbyaddr(achannel, &(notice->z_sender_addr),
332 sizeof(notice->z_sender_addr), AF_INET,
333 notice_callback, notice);
336 fromhost = gethostbyaddr((char *) &(notice->z_sender_addr),
337 sizeof(struct in_addr), AF_INET);
340 process_notice(notice, fromhost ? fromhost->h_name : NULL);
346 static void notice_callback(arg, status, fromhost)
349 struct hostent *fromhost;
351 ZNotice_t *notice = (ZNotice_t *) arg;
353 process_notice(notice, fromhost ? fromhost->h_name : NULL);
359 static void process_notice(notice, hostname)
363 char *control_opcode;
365 dprintf("Got a message\n");
367 if (control_opcode = decode_notice(notice, hostname)) {
369 printf("got control opcode <%s>.\n", control_opcode);
371 if (!strcasecmp(control_opcode, USER_REREAD)) {
372 read_in_description_file();
373 } else if (!strcasecmp(control_opcode, USER_SHUTDOWN))
375 else if (!strcasecmp(control_opcode, USER_STARTUP)) {
377 report_memory_usage(); /* <<<>>> */
380 } else if (!strcasecmp(control_opcode, USER_SUPPRESS)) {
381 string class = get_field(notice->z_message,
382 notice->z_message_len, 1);
383 string instance = get_field(notice->z_message,
384 notice->z_message_len, 2);
385 string recipient = get_field(notice->z_message,
386 notice->z_message_len, 3);
387 punt(class, instance, recipient);
391 } else if (!strcasecmp(control_opcode, USER_UNSUPPRESS)) {
392 string class = get_field(notice->z_message,
393 notice->z_message_len, 1);
394 string instance = get_field(notice->z_message,
395 notice->z_message_len, 2);
396 string recipient = get_field(notice->z_message,
397 notice->z_message_len, 3);
398 unpunt(class, instance, recipient);
402 } else if (!strcasecmp(control_opcode, USER_EXIT)) {
405 printf("zwgc: unknown control opcode %s.\n", control_opcode);
413 printf("NON-ACTIVE: PUNTED <%s>!!!!\n", notice->z_class_inst);
418 if (puntable_address_p(notice->z_class,
419 notice->z_class_inst,
420 notice->z_recipient)) {
423 printf("PUNTED <%s>!!!!\n", notice->z_class_inst);
428 exec_process_packet(program, notice);
431 /***************************************************************************/
437 static void signal_exit()
442 /* clean up ALL the waiting children, in case we get hit with
443 multiple SIGCHLD's at once, and don't process in time. */
444 static RETSIGTYPE signal_child()
452 int pid, old_errno = errno;
456 pid = waitpid(-1, &status, WNOHANG);
458 pid = wait3(&status, WNOHANG, (struct rusage *)0);
460 } while (pid != 0 && pid != -1);
464 static void setup_signals(dofork)
467 #ifdef _POSIX_VERSION
470 sigemptyset(&sa.sa_mask);
474 sa.sa_handler = SIG_IGN;
475 sigaction(SIGINT, &sa, (struct sigaction *)0);
476 sigaction(SIGTSTP, &sa, (struct sigaction *)0);
477 sigaction(SIGQUIT, &sa, (struct sigaction *)0);
478 sigaction(SIGTTOU, &sa, (struct sigaction *)0);
480 /* clean up on SIGINT; exiting on logout is the user's problem, now. */
481 sa.sa_handler = signal_exit;
482 sigaction(SIGINT, &sa, (struct sigaction *)0);
485 /* behavior never changes */
486 sa.sa_handler = signal_exit;
487 sigaction(SIGTERM, &sa, (struct sigaction *)0);
488 sigaction(SIGHUP, &sa, (struct sigaction *)0);
490 sa.sa_handler = SIG_IGN;
491 sigaction(SIGPIPE, &sa, (struct sigaction *)0);
493 sa.sa_handler = signal_child;
494 sigaction(SIGCHLD, &sa, (struct sigaction *)0);
498 /* Ignore keyboard signals if forking. Bad things will happen. */
499 signal(SIGINT, SIG_IGN);
500 signal(SIGTSTP, SIG_IGN);
501 signal(SIGTTOU, SIG_IGN);
502 signal(SIGQUIT, SIG_IGN);
504 /* clean up on SIGINT; exiting on logout is the user's problem, now. */
505 signal(SIGINT, signal_exit);
508 /* behavior never changes */
509 signal(SIGTERM, signal_exit);
510 signal(SIGHUP, signal_exit);
511 signal(SIGCHLD, signal_child);
512 signal(SIGPIPE, SIG_IGN); /* so that Xlib gets an error */
516 /* detach() taken from old zwgc, with lots of stuff ripped out */
520 /* detach from terminal and fork. */
523 /* Attempt to join the process group of the session leader. This
524 * will get us a HUP if the session leader is in the foreground at
525 * logout time (which is often the case) or if the shell is running
526 * under telnetd or xterm (both of which HUP the process group of
527 * their child process). If we have getsid(), that's the best way
528 * of finding the session leader; otherwise use the process group of
529 * the parent process, which is a good guess. */
530 #if defined(HAVE_GETSID)
531 setpgid(0, getsid(0));
532 #elif defined(HAVE_GETPGID)
533 setpgid(0, getpgid(getppid()));
534 #elif !defined(GETPGRP_VOID)
535 setpgid(0, getpgrp(getppid()));
538 /* fork off and let parent exit... */
541 perror("zwgc: cannot fork, aborting:");