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>
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$";
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 void notice_handler(ZNotice_t *);
44 static void process_notice(ZNotice_t *, char *);
45 static void setup_signals(int);
46 static void detach(void);
47 static void signal_exit(int);
49 static void notice_callback(void *, int, struct hostent *);
53 * Global zwgc-wide variables:
60 static char *zwgc_version_string = "1.0";
63 * description_filename_override - <<<>>>
66 static char *description_filename_override = NULL;
69 * progname - <<<>>> export!
72 char *progname = NULL;
75 * subscriptions_filename_override - <<<>>> export!
78 char *subscriptions_filename_override = NULL;
81 * location_override - <<<>>> export!
84 char *location_override = NULL;
88 * achannel - <<<>>> export!
91 ares_channel achannel;
94 /****************************************************************************/
96 /* Code to deal with reading in the description file: */
98 /****************************************************************************/
101 * program - this holds a pointer to the node representation of the
102 * description file once it has been read in.
105 static struct _Node *program = NULL;
112 fake_startup_packet(void)
117 extern void Z_gettimeofday(struct _ZTimeval *, struct timezone *);
119 var_set_variable("version", zwgc_version_string);
121 (void) memset(¬ice, 0, sizeof(notice));
123 notice.z_version = "";
124 notice.z_class = "WG_CTL_CLASS";
125 notice.z_class_inst = "WG_CTL_USER<<<>>>";
126 notice.z_opcode = "WG_STARTUP";
127 notice.z_default_format = "Zwgc mark II version $version now running...\n";
128 notice.z_recipient = "";
129 notice.z_sender = "ZWGC";
130 Z_gettimeofday(¬ice.z_time, &tz);
132 notice.z_kind = ACKED;
133 notice.z_auth = ZAUTH_YES;
134 sprintf(msgbuf,"Zwgc mark II version %s now running...",
135 zwgc_version_string);
136 notice.z_message = msgbuf;
137 notice.z_message_len = strlen(notice.z_message)+1;
139 process_notice(¬ice, NULL);
143 read_in_description_file(void)
148 /* var_clear_all_variables(); <<<>>> */
150 sprintf(defdesc, "%s/zephyr/%s", DATADIR, DEFDESC);
151 input_file = locate_file(description_filename_override, USRDESC, defdesc);
153 program = parse_file(input_file);
157 fake_startup_packet();
160 /****************************************************************************/
162 /* Code to deal with argument parsing & overall control: */
164 /****************************************************************************/
168 * Effects: Prints out an usage message on stderr then exits the
169 * program with error code 1.
177 zwgc: usage: zwgc [-debug] [-f <filename>] [-subfile <filename>]\n\
178 [-ttymode] [-nofork] [-reenter] [-loc text]\n\
179 [-default <driver>] {-disable <driver>}*\n\
180 [output driver options]\n");
183 zwgc: usage: zwgc [-f <filename>] [-subfile <filename>]\n\
184 [-ttymode] [-nofork] [-reenter] [-loc text]\n\
185 [-default <driver>] {-disable <driver>}*\n\
186 [output driver options]\n");
199 * This code stolen from old zwgc: yuck. Clean up & fix. <<<>>>
200 * Should this fork instead of just systeming?
204 char *progname = ZGetVariable("initprogs");
209 status = system(progname);
211 perror("zwgc initprog exec");
212 fprintf(stderr,"zwgc initprog of <%s> failed: no shell.\n",
214 } else if (status!=-1 && status>>8) {
215 perror("zwgc initprog exec");
216 fprintf(stderr,"zwgc initprog of <%s> failed with status [%d].\n",
217 progname, status>>8);
222 * main -- the program entry point. Does parsing & top level control.
230 register char **current;
240 * Process "-f <filename>", "-subfile <filename>", "-nofork",
241 * "-reenter" (which is ignored) and (if DEBUG) "-debug"
242 * arguments, removing then from argc, argv:
244 for (new=current=argv+1; *current; current++) {
245 if (string_Eq(*current, "-debug")) {
250 } else if (string_Eq(*current, "-f")) {
251 argc -= 2; current++;
254 description_filename_override = *current;
255 } else if (string_Eq(*current, "-subfile")) {
256 argc -= 2; current++;
259 subscriptions_filename_override = *current;
260 } else if (string_Eq(*current, "-nofork")) {
263 } else if (string_Eq(*current, "-reenter")) {
264 argc--; /* just throw it away */
265 } else if (string_Eq(*current, "-loc")) {
266 argc -= 2; current++;
269 location_override = *current;
277 * Initialize resolver library
279 status = ares_init(&achannel);
280 if (status != ARES_SUCCESS) {
281 fprintf(stderr, "Couldn't initialize resolver: %s\n",
282 ares_strerror(status, &errmem));
283 ares_free_errmem(errmem);
289 * Initialize various subsystems in proper order:
291 dprintf("Initializing subsystems...\n"); /*<<<>>>*/
293 var_clear_all_variables(); /* <<<>>> */
294 init_ports(); /* <<<>>> */
295 dprintf("Initializing standard ports...\n");
296 init_standard_ports(&argc, argv);
299 dprintf("Initializing zephyr...\n");
300 setup_signals(dofork);
301 zephyr_init(notice_handler);
306 * Run the initprogs program(s) now that we are all set to deal:
308 dprintf("Running initprogs program...\n");
311 dprintf("Test Zwgc parser.\n\n");
312 read_in_description_file();
314 dprintf("Entering main loop\n");
317 dprintf("Returning from main loop\n");
323 /****************************************************************************/
327 /****************************************************************************/
329 #define USER_SUPPRESS "SUPPRESS"
330 #define USER_UNSUPPRESS "UNSUPPRESS"
333 notice_handler(ZNotice_t *notice)
335 struct hostent *fromhost = NULL;
337 if (notice->z_sender_addr.s_addr) {
339 ares_gethostbyaddr(achannel, &(notice->z_sender_addr),
340 sizeof(notice->z_sender_addr), AF_INET,
341 notice_callback, notice);
344 fromhost = gethostbyaddr((char *) &(notice->z_sender_addr),
345 sizeof(struct in_addr), AF_INET);
348 process_notice(notice, fromhost ? fromhost->h_name : NULL);
355 notice_callback(void *arg,
357 struct hostent *fromhost)
359 ZNotice_t *notice = (ZNotice_t *) arg;
361 process_notice(notice, fromhost ? fromhost->h_name : NULL);
368 process_notice(ZNotice_t *notice,
371 char *control_opcode;
373 dprintf("Got a message\n");
375 control_opcode = decode_notice(notice, hostname);
376 if (control_opcode) {
378 printf("got control opcode <%s>.\n", control_opcode);
380 if (!strcasecmp(control_opcode, USER_REREAD)) {
381 read_in_description_file();
382 } else if (!strcasecmp(control_opcode, USER_SHUTDOWN))
384 else if (!strcasecmp(control_opcode, USER_STARTUP)) {
386 report_memory_usage(); /* <<<>>> */
389 } else if (!strcasecmp(control_opcode, USER_SUPPRESS)) {
390 string class = get_field(notice->z_message,
391 notice->z_message_len, 1);
392 string instance = get_field(notice->z_message,
393 notice->z_message_len, 2);
394 string recipient = get_field(notice->z_message,
395 notice->z_message_len, 3);
396 punt(class, instance, recipient);
400 } else if (!strcasecmp(control_opcode, USER_UNSUPPRESS)) {
401 string class = get_field(notice->z_message,
402 notice->z_message_len, 1);
403 string instance = get_field(notice->z_message,
404 notice->z_message_len, 2);
405 string recipient = get_field(notice->z_message,
406 notice->z_message_len, 3);
407 unpunt(class, instance, recipient);
411 } else if (!strcasecmp(control_opcode, USER_EXIT)) {
414 printf("zwgc: unknown control opcode %s.\n", control_opcode);
422 printf("NON-ACTIVE: PUNTED <%s>!!!!\n", notice->z_class_inst);
427 if (puntable_address_p(notice->z_class,
428 notice->z_class_inst,
429 notice->z_recipient)) {
432 printf("PUNTED <%s>!!!!\n", notice->z_class_inst);
437 exec_process_packet(program, notice);
440 /***************************************************************************/
447 signal_exit(int ignored)
452 /* clean up ALL the waiting children, in case we get hit with
453 multiple SIGCHLD's at once, and don't process in time. */
455 signal_child(int ignored)
462 int pid, old_errno = errno;
466 pid = waitpid(-1, &status, WNOHANG);
468 pid = wait3(&status, WNOHANG, (struct rusage *)0);
470 } while (pid != 0 && pid != -1);
474 /* rewrite the wgfile in case it has gone away */
476 signal_usr1(int ignored)
482 setup_signals(int dofork)
484 #ifdef _POSIX_VERSION
487 sigemptyset(&sa.sa_mask);
491 sa.sa_handler = SIG_IGN;
492 sigaction(SIGINT, &sa, (struct sigaction *)0);
493 sigaction(SIGTSTP, &sa, (struct sigaction *)0);
494 sigaction(SIGQUIT, &sa, (struct sigaction *)0);
495 sigaction(SIGTTOU, &sa, (struct sigaction *)0);
497 /* clean up on SIGINT; exiting on logout is the user's problem, now. */
498 sa.sa_handler = signal_exit;
499 sigaction(SIGINT, &sa, (struct sigaction *)0);
502 /* behavior never changes */
503 sa.sa_handler = signal_exit;
504 sigaction(SIGTERM, &sa, (struct sigaction *)0);
505 sigaction(SIGHUP, &sa, (struct sigaction *)0);
507 sa.sa_handler = SIG_IGN;
508 sigaction(SIGPIPE, &sa, (struct sigaction *)0);
510 sa.sa_handler = signal_child;
511 sigaction(SIGCHLD, &sa, (struct sigaction *)0);
513 sa.sa_handler = signal_usr1;
514 sigaction(SIGUSR1, &sa, (struct sigaction *)0);
518 /* Ignore keyboard signals if forking. Bad things will happen. */
519 signal(SIGINT, SIG_IGN);
520 signal(SIGTSTP, SIG_IGN);
521 signal(SIGTTOU, SIG_IGN);
522 signal(SIGQUIT, SIG_IGN);
524 /* clean up on SIGINT; exiting on logout is the user's problem, now. */
525 signal(SIGINT, signal_exit);
528 /* behavior never changes */
529 signal(SIGTERM, signal_exit);
530 signal(SIGHUP, signal_exit);
531 signal(SIGCHLD, signal_child);
532 signal(SIGPIPE, SIG_IGN); /* so that Xlib gets an error */
533 signal(SIGUSR1, signal_usr1);
537 /* detach() taken from old zwgc, with lots of stuff ripped out */
542 /* detach from terminal and fork. */
545 /* Attempt to join the process group of the session leader. This
546 * will get us a HUP if the session leader is in the foreground at
547 * logout time (which is often the case) or if the shell is running
548 * under telnetd or xterm (both of which HUP the process group of
549 * their child process). If we have getsid(), that's the best way
550 * of finding the session leader; otherwise use the process group of
551 * the parent process, which is a good guess. */
552 #if defined(HAVE_GETSID)
554 setpgid(0, getsid(0));
555 #elif defined(HAVE_GETPGID)
556 setpgid(0, getpgid(getppid()));
557 #elif !defined(GETPGRP_VOID)
558 setpgid(0, getpgrp(getppid()));
561 /* fork off and let parent exit... */
565 perror("zwgc: cannot fork, aborting:");