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)
118 var_set_variable("version", zwgc_version_string);
120 (void) memset(¬ice, 0, sizeof(notice));
122 notice.z_version = "";
123 notice.z_class = "WG_CTL_CLASS";
124 notice.z_class_inst = "WG_CTL_USER<<<>>>";
125 notice.z_opcode = "WG_STARTUP";
126 notice.z_default_format = "Zwgc mark II version $version now running...\n";
127 notice.z_recipient = "";
128 notice.z_sender = "ZWGC";
129 Z_gettimeofday(¬ice.z_time, &tz);
131 notice.z_kind = ACKED;
132 notice.z_auth = ZAUTH_YES;
133 sprintf(msgbuf,"Zwgc mark II version %s now running...",
134 zwgc_version_string);
135 notice.z_message = msgbuf;
136 notice.z_message_len = strlen(notice.z_message)+1;
138 process_notice(¬ice, NULL);
142 read_in_description_file(void)
147 /* var_clear_all_variables(); <<<>>> */
149 sprintf(defdesc, "%s/zephyr/%s", DATADIR, DEFDESC);
150 input_file = locate_file(description_filename_override, USRDESC, defdesc);
152 program = parse_file(input_file);
156 fake_startup_packet();
159 /****************************************************************************/
161 /* Code to deal with argument parsing & overall control: */
163 /****************************************************************************/
167 * Effects: Prints out an usage message on stderr then exits the
168 * program with error code 1.
176 zwgc: usage: zwgc [-debug] [-f <filename>] [-subfile <filename>]\n\
177 [-ttymode] [-nofork] [-reenter] [-loc text]\n\
178 [-default <driver>] {-disable <driver>}*\n\
179 [output driver options]\n");
182 zwgc: usage: zwgc [-f <filename>] [-subfile <filename>]\n\
183 [-ttymode] [-nofork] [-reenter] [-loc text]\n\
184 [-default <driver>] {-disable <driver>}*\n\
185 [output driver options]\n");
198 * This code stolen from old zwgc: yuck. Clean up & fix. <<<>>>
199 * Should this fork instead of just systeming?
203 char *progname = ZGetVariable("initprogs");
208 status = system(progname);
210 perror("zwgc initprog exec");
211 fprintf(stderr,"zwgc initprog of <%s> failed: no shell.\n",
213 } else if (status!=-1 && status>>8) {
214 perror("zwgc initprog exec");
215 fprintf(stderr,"zwgc initprog of <%s> failed with status [%d].\n",
216 progname, status>>8);
221 * main -- the program entry point. Does parsing & top level control.
229 register char **current;
239 * Process "-f <filename>", "-subfile <filename>", "-nofork",
240 * "-reenter" (which is ignored) and (if DEBUG) "-debug"
241 * arguments, removing then from argc, argv:
243 for (new=current=argv+1; *current; current++) {
244 if (string_Eq(*current, "-debug")) {
249 } else if (string_Eq(*current, "-f")) {
250 argc -= 2; current++;
253 description_filename_override = *current;
254 } else if (string_Eq(*current, "-subfile")) {
255 argc -= 2; current++;
258 subscriptions_filename_override = *current;
259 } else if (string_Eq(*current, "-nofork")) {
262 } else if (string_Eq(*current, "-reenter")) {
263 argc--; /* just throw it away */
264 } else if (string_Eq(*current, "-loc")) {
265 argc -= 2; current++;
268 location_override = *current;
276 * Initialize resolver library
278 status = ares_init(&achannel);
279 if (status != ARES_SUCCESS) {
280 fprintf(stderr, "Couldn't initialize resolver: %s\n",
281 ares_strerror(status, &errmem));
282 ares_free_errmem(errmem);
288 * Initialize various subsystems in proper order:
290 dprintf("Initializing subsystems...\n"); /*<<<>>>*/
292 var_clear_all_variables(); /* <<<>>> */
293 init_ports(); /* <<<>>> */
294 dprintf("Initializing standard ports...\n");
295 init_standard_ports(&argc, argv);
298 dprintf("Initializing zephyr...\n");
299 setup_signals(dofork);
300 zephyr_init(notice_handler);
305 * Run the initprogs program(s) now that we are all set to deal:
307 dprintf("Running initprogs program...\n");
310 dprintf("Test Zwgc parser.\n\n");
311 read_in_description_file();
313 dprintf("Entering main loop\n");
316 dprintf("Returning from main loop\n");
322 /****************************************************************************/
326 /****************************************************************************/
328 #define USER_SUPPRESS "SUPPRESS"
329 #define USER_UNSUPPRESS "UNSUPPRESS"
332 notice_handler(ZNotice_t *notice)
334 struct hostent *fromhost = NULL;
336 if (notice->z_sender_addr.s_addr) {
338 ares_gethostbyaddr(achannel, &(notice->z_sender_addr),
339 sizeof(notice->z_sender_addr), AF_INET,
340 notice_callback, notice);
343 fromhost = gethostbyaddr((char *) &(notice->z_sender_addr),
344 sizeof(struct in_addr), AF_INET);
347 process_notice(notice, fromhost ? fromhost->h_name : NULL);
354 notice_callback(void *arg,
356 struct hostent *fromhost)
358 ZNotice_t *notice = (ZNotice_t *) arg;
360 process_notice(notice, fromhost ? fromhost->h_name : NULL);
367 process_notice(ZNotice_t *notice,
370 char *control_opcode;
372 dprintf("Got a message\n");
374 if (control_opcode = decode_notice(notice, hostname)) {
376 printf("got control opcode <%s>.\n", control_opcode);
378 if (!strcasecmp(control_opcode, USER_REREAD)) {
379 read_in_description_file();
380 } else if (!strcasecmp(control_opcode, USER_SHUTDOWN))
382 else if (!strcasecmp(control_opcode, USER_STARTUP)) {
384 report_memory_usage(); /* <<<>>> */
387 } else if (!strcasecmp(control_opcode, USER_SUPPRESS)) {
388 string class = get_field(notice->z_message,
389 notice->z_message_len, 1);
390 string instance = get_field(notice->z_message,
391 notice->z_message_len, 2);
392 string recipient = get_field(notice->z_message,
393 notice->z_message_len, 3);
394 punt(class, instance, recipient);
398 } else if (!strcasecmp(control_opcode, USER_UNSUPPRESS)) {
399 string class = get_field(notice->z_message,
400 notice->z_message_len, 1);
401 string instance = get_field(notice->z_message,
402 notice->z_message_len, 2);
403 string recipient = get_field(notice->z_message,
404 notice->z_message_len, 3);
405 unpunt(class, instance, recipient);
409 } else if (!strcasecmp(control_opcode, USER_EXIT)) {
412 printf("zwgc: unknown control opcode %s.\n", control_opcode);
420 printf("NON-ACTIVE: PUNTED <%s>!!!!\n", notice->z_class_inst);
425 if (puntable_address_p(notice->z_class,
426 notice->z_class_inst,
427 notice->z_recipient)) {
430 printf("PUNTED <%s>!!!!\n", notice->z_class_inst);
435 exec_process_packet(program, notice);
438 /***************************************************************************/
445 signal_exit(int ignored)
450 /* clean up ALL the waiting children, in case we get hit with
451 multiple SIGCHLD's at once, and don't process in time. */
453 signal_child(int ignored)
460 int pid, old_errno = errno;
464 pid = waitpid(-1, &status, WNOHANG);
466 pid = wait3(&status, WNOHANG, (struct rusage *)0);
468 } while (pid != 0 && pid != -1);
472 /* rewrite the wgfile in case it has gone away */
474 signal_usr1(int ignored)
480 setup_signals(int dofork)
482 #ifdef _POSIX_VERSION
485 sigemptyset(&sa.sa_mask);
489 sa.sa_handler = SIG_IGN;
490 sigaction(SIGINT, &sa, (struct sigaction *)0);
491 sigaction(SIGTSTP, &sa, (struct sigaction *)0);
492 sigaction(SIGQUIT, &sa, (struct sigaction *)0);
493 sigaction(SIGTTOU, &sa, (struct sigaction *)0);
495 /* clean up on SIGINT; exiting on logout is the user's problem, now. */
496 sa.sa_handler = signal_exit;
497 sigaction(SIGINT, &sa, (struct sigaction *)0);
500 /* behavior never changes */
501 sa.sa_handler = signal_exit;
502 sigaction(SIGTERM, &sa, (struct sigaction *)0);
503 sigaction(SIGHUP, &sa, (struct sigaction *)0);
505 sa.sa_handler = SIG_IGN;
506 sigaction(SIGPIPE, &sa, (struct sigaction *)0);
508 sa.sa_handler = signal_child;
509 sigaction(SIGCHLD, &sa, (struct sigaction *)0);
511 sa.sa_handler = signal_usr1;
512 sigaction(SIGUSR1, &sa, (struct sigaction *)0);
516 /* Ignore keyboard signals if forking. Bad things will happen. */
517 signal(SIGINT, SIG_IGN);
518 signal(SIGTSTP, SIG_IGN);
519 signal(SIGTTOU, SIG_IGN);
520 signal(SIGQUIT, SIG_IGN);
522 /* clean up on SIGINT; exiting on logout is the user's problem, now. */
523 signal(SIGINT, signal_exit);
526 /* behavior never changes */
527 signal(SIGTERM, signal_exit);
528 signal(SIGHUP, signal_exit);
529 signal(SIGCHLD, signal_child);
530 signal(SIGPIPE, SIG_IGN); /* so that Xlib gets an error */
531 signal(SIGUSR1, signal_usr1);
535 /* detach() taken from old zwgc, with lots of stuff ripped out */
540 /* detach from terminal and fork. */
543 /* Attempt to join the process group of the session leader. This
544 * will get us a HUP if the session leader is in the foreground at
545 * logout time (which is often the case) or if the shell is running
546 * under telnetd or xterm (both of which HUP the process group of
547 * their child process). If we have getsid(), that's the best way
548 * of finding the session leader; otherwise use the process group of
549 * the parent process, which is a good guess. */
550 #if defined(HAVE_GETSID)
551 setpgid(0, getsid(0));
552 #elif defined(HAVE_GETPGID)
553 setpgid(0, getpgid(getppid()));
554 #elif !defined(GETPGRP_VOID)
555 setpgid(0, getpgrp(getppid()));
558 /* fork off and let parent exit... */
561 perror("zwgc: cannot fork, aborting:");