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 2328 2009-03-22 17:34:39Z kcr $
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 2328 2009-03-22 17:34:39Z kcr $";
24 #include <arpa/nameser.h>
25 #include <sys/socket.h>
26 #include <sys/resource.h>
27 #include <zephyr/mit-copyright.h>
28 #include <zephyr/zephyr.h>
30 #include "new_memory.h"
37 #include "subscriptions.h"
41 #include "variables.h"
44 #include "int_dictionary.h"
51 void notice_handler(ZNotice_t *);
52 static void process_notice(ZNotice_t *, char *);
53 static void setup_signals(int);
54 static void detach(void);
55 static void signal_exit(int);
57 static void notice_callback(void *, int, int, char *, char *);
61 * Global zwgc-wide variables:
68 static char *zwgc_version_string = "1.0";
71 * description_filename_override - <<<>>>
74 static char *description_filename_override = NULL;
77 * progname - <<<>>> export!
80 char *progname = NULL;
83 * subscriptions_filename_override - <<<>>> export!
86 char *subscriptions_filename_override = NULL;
89 * location_override - <<<>>> export!
92 char *location_override = NULL;
96 * achannel - <<<>>> export!
99 ares_channel achannel;
102 /****************************************************************************/
104 /* Code to deal with reading in the description file: */
106 /****************************************************************************/
109 * program - this holds a pointer to the node representation of the
110 * description file once it has been read in.
113 static struct _Node *program = NULL;
120 fake_startup_packet(void)
122 ZNotice_t *notice = (ZNotice_t *)malloc(sizeof(ZNotice_t));
125 extern void Z_gettimeofday(struct _ZTimeval *, struct timezone *);
127 var_set_variable("version", zwgc_version_string);
129 (void) memset(notice, 0, sizeof(ZNotice_t));
131 notice->z_version = "";
132 notice->z_class = "WG_CTL_CLASS";
133 notice->z_class_inst = "WG_CTL_USER<<<>>>";
134 notice->z_opcode = "WG_STARTUP";
135 notice->z_default_format = "Zwgc mark II version $version now running...\n";
136 notice->z_recipient = "";
137 notice->z_sender = "ZWGC";
138 Z_gettimeofday(¬ice->z_time, &tz);
140 notice->z_kind = ACKED;
141 notice->z_auth = ZAUTH_YES;
142 notice->z_charset = ZCHARSET_UNKNOWN;
143 sprintf(msgbuf,"Zwgc mark II version %s now running...",
144 zwgc_version_string);
145 notice->z_message = msgbuf;
146 notice->z_message_len = strlen(notice->z_message)+1;
149 list_add_notice(notice);
150 set_notice_fake(notice, 1);
152 process_notice(notice, NULL);
154 list_del_notice(notice);
161 read_in_description_file(void)
166 /* var_clear_all_variables(); <<<>>> */
168 sprintf(defdesc, "%s/zephyr/%s", DATADIR, DEFDESC);
169 input_file = locate_file(description_filename_override, USRDESC, defdesc);
171 program = parse_file(input_file);
175 fake_startup_packet();
178 /****************************************************************************/
180 /* Code to deal with argument parsing & overall control: */
182 /****************************************************************************/
186 * Effects: Prints out an usage message on stderr then exits the
187 * program with error code 1.
195 zwgc: usage: zwgc [-debug] [-f <filename>] [-subfile <filename>]\n\
196 [-ttymode] [-nofork] [-reenter] [-loc text]\n\
197 [-default <driver>] {-disable <driver>}*\n\
198 [output driver options]\n");
201 zwgc: usage: zwgc [-f <filename>] [-subfile <filename>]\n\
202 [-ttymode] [-nofork] [-reenter] [-loc text]\n\
203 [-default <driver>] {-disable <driver>}*\n\
204 [output driver options]\n");
217 * This code stolen from old zwgc: yuck. Clean up & fix. <<<>>>
218 * Should this fork instead of just systeming?
222 char *progname = ZGetVariable("initprogs");
227 status = system(progname);
229 perror("zwgc initprog exec");
230 fprintf(stderr,"zwgc initprog of <%s> failed: no shell.\n",
232 } else if (status!=-1 && status>>8) {
233 perror("zwgc initprog exec");
234 fprintf(stderr,"zwgc initprog of <%s> failed with status [%d].\n",
235 progname, status>>8);
240 * main -- the program entry point. Does parsing & top level control.
248 register char **current;
257 * Process "-f <filename>", "-subfile <filename>", "-nofork",
258 * "-reenter" (which is ignored) and (if DEBUG) "-debug"
259 * arguments, removing then from argc, argv:
261 for (new=current=argv+1; *current; current++) {
262 if (string_Eq(*current, "-debug")) {
267 } else if (string_Eq(*current, "-f")) {
268 argc -= 2; current++;
271 description_filename_override = *current;
272 } else if (string_Eq(*current, "-subfile")) {
273 argc -= 2; current++;
276 subscriptions_filename_override = *current;
277 } else if (string_Eq(*current, "-nofork")) {
280 } else if (string_Eq(*current, "-reenter")) {
281 argc--; /* just throw it away */
282 } else if (string_Eq(*current, "-loc")) {
283 argc -= 2; current++;
286 location_override = *current;
294 * Initialize resolver library
296 status = ares_init(&achannel);
297 if (status != ARES_SUCCESS) {
298 fprintf(stderr, "Couldn't initialize resolver: %s\n",
299 ares_strerror(status));
305 * Initialize various subsystems in proper order:
307 dprintf("Initializing subsystems...\n"); /*<<<>>>*/
312 var_clear_all_variables(); /* <<<>>> */
313 init_ports(); /* <<<>>> */
314 dprintf("Initializing standard ports...\n");
315 init_standard_ports(&argc, argv);
318 dprintf("Initializing zephyr...\n");
319 setup_signals(dofork);
320 zephyr_init(notice_handler);
325 * Run the initprogs program(s) now that we are all set to deal:
327 dprintf("Running initprogs program...\n");
330 dprintf("Test Zwgc parser.\n\n");
331 read_in_description_file();
334 if (strcmp(progname, "zwgcplus") == 0)
338 dprintf("Entering main loop\n");
341 dprintf("Returning from main loop\n");
347 /****************************************************************************/
351 /****************************************************************************/
353 #define USER_SUPPRESS "SUPPRESS"
354 #define USER_UNSUPPRESS "UNSUPPRESS"
357 #define USER_LIST_SUPPRESSED "LIST-SUPPRESSED"
359 #define PUNT_INC 1024
360 extern int_dictionary puntable_addresses_dict;
361 ZNotice_t punt_reply;
364 create_punt_reply(int_dictionary_binding *punt)
367 int key_len = strlen(punt->key);
370 if (!punt_reply.z_message) {
371 punt_reply.z_message = (char *)malloc(PUNT_INC);
372 punt_reply.z_message[0] = 0;
375 if ((punt_reply.z_message_len + key_len + 1) / PUNT_INC >
376 (punt_reply.z_message_len + PUNT_INC - 1) / PUNT_INC) {
377 char *new_message = (char *)malloc((punt_reply.z_message_len
378 / PUNT_INC + 1) * PUNT_INC);
380 strcpy(new_message, punt_reply.z_message);
382 free(punt_reply.z_message);
383 punt_reply.z_message = new_message;
385 tmp = punt_reply.z_message + strlen(punt_reply.z_message);
386 strcat (punt_reply.z_message, punt->key);
387 strcat (punt_reply.z_message, "\n");
388 punt_reply.z_message_len += key_len + 1;
390 while (*tmp != '\001') tmp++;
392 while (*tmp != '\001') tmp++;
395 #endif /* CMU_ZCTL_PUNT */
398 notice_handler(ZNotice_t *notice)
402 #if defined(CMU_ZWGCPLUS)
403 list_add_notice(notice);
407 ares_getnameinfo(achannel,
408 (const struct sockaddr *)&(notice->z_sender_sockaddr),
409 notice->z_sender_sockaddr.sa.sa_family == AF_INET ?
410 sizeof(struct sockaddr_in) :
411 notice->z_sender_sockaddr.sa.sa_family == AF_INET6 ?
412 sizeof(struct sockaddr_in6) :
413 sizeof(notice->z_sender_sockaddr), ARES_NI_LOOKUPHOST,
414 notice_callback, notice);
417 getnameinfo((const struct sockaddr *)&(notice->z_sender_sockaddr),
418 sizeof(notice->z_sender_sockaddr),
419 node, sizeof(node), NULL, 0, 0);
421 process_notice(notice, node);
423 /* Let list_del_notice clean up for us. */
434 notice_callback(void *arg,
437 struct hostent *fromhost)
440 notice_callback(void *arg,
446 ZNotice_t *notice = (ZNotice_t *) arg;
449 plus_set_hname(notice, node);
452 process_notice(notice, node);
454 list_del_notice(notice);
463 process_notice(ZNotice_t *notice,
466 char *control_opcode;
468 dprintf("Got a message\n");
470 control_opcode = decode_notice(notice, hostname);
471 if (control_opcode) {
473 printf("got control opcode <%s>.\n", control_opcode);
475 if (!strcasecmp(control_opcode, USER_REREAD)) {
476 read_in_description_file();
477 } else if (!strcasecmp(control_opcode, USER_SHUTDOWN))
479 else if (!strcasecmp(control_opcode, USER_STARTUP)) {
481 report_memory_usage(); /* <<<>>> */
484 } else if (!strcasecmp(control_opcode, USER_SUPPRESS)) {
485 string class = get_field(notice->z_message,
486 notice->z_message_len, 1);
487 string instance = get_field(notice->z_message,
488 notice->z_message_len, 2);
489 string recipient = get_field(notice->z_message,
490 notice->z_message_len, 3);
491 punt(class, instance, recipient);
495 } else if (!strcasecmp(control_opcode, USER_UNSUPPRESS)) {
496 string class = get_field(notice->z_message,
497 notice->z_message_len, 1);
498 string instance = get_field(notice->z_message,
499 notice->z_message_len, 2);
500 string recipient = get_field(notice->z_message,
501 notice->z_message_len, 3);
502 unpunt(class, instance, recipient);
507 } else if (!strcasecmp(control_opcode, USER_LIST_SUPPRESSED)) {
508 struct sockaddr_in old, to;
511 if (!notice->z_port) {
512 printf("zwgc: can't reply to LIST-SUPPRESSED request\n");
515 memset((char *) &punt_reply, 0, sizeof(ZNotice_t));
516 punt_reply.z_kind = CLIENTACK;
517 punt_reply.z_class = WG_CTL_CLASS;
518 punt_reply.z_class_inst = "WG_REPLY";
519 punt_reply.z_recipient = "zctl?";
520 punt_reply.z_sender = "Zwgc";
521 punt_reply.z_default_format = "";
522 punt_reply.z_opcode = USER_LIST_SUPPRESSED;
523 punt_reply.z_port = notice->z_port;
524 punt_reply.z_message = NULL;
525 punt_reply.z_message_len = 0;
527 if (puntable_addresses_dict) {
528 int_dictionary_Enumerate(puntable_addresses_dict,
532 old = ZGetDestAddr();
535 to.sin_port = notice->z_port;
536 if ((retval = ZSetDestAddr(&to)) != ZERR_NONE) {
537 com_err("zwgc",retval,"while setting destination address");
541 ZSendNotice(&punt_reply, ZNOAUTH);
543 if ((retval = ZSetDestAddr(&old)) != ZERR_NONE) {
544 com_err("zwgc",retval,"while resetting destination address");
548 if (punt_reply.z_message) {
549 free(punt_reply.z_message);
550 punt_reply.z_message = NULL;
553 } else if (!strcasecmp(control_opcode, USER_EXIT)) {
556 printf("zwgc: unknown control opcode %s.\n", control_opcode);
564 printf("NON-ACTIVE: PUNTED <%s>!!!!\n", notice->z_class_inst);
569 if (puntable_address_p(notice->z_class,
570 notice->z_class_inst,
571 notice->z_recipient)) {
574 printf("PUNTED <%s>!!!!\n", notice->z_class_inst);
579 exec_process_packet(program, notice);
586 reprocess_notice(ZNotice_t *notice, char *hostname)
588 list_add_notice(notice);
589 process_notice(notice, hostname);
590 list_del_notice(notice);
594 /***************************************************************************/
601 signal_exit(int ignored)
606 /* clean up ALL the waiting children, in case we get hit with
607 multiple SIGCHLD's at once, and don't process in time. */
609 signal_child(int ignored)
616 int pid, old_errno = errno;
620 pid = waitpid(-1, &status, WNOHANG);
622 pid = wait3(&status, WNOHANG, (struct rusage *)0);
624 } while (pid != 0 && pid != -1);
628 /* rewrite the wgfile in case it has gone away */
630 signal_usr1(int ignored)
636 setup_signals(int dofork)
638 #ifdef _POSIX_VERSION
641 sigemptyset(&sa.sa_mask);
645 sa.sa_handler = SIG_IGN;
646 sigaction(SIGINT, &sa, (struct sigaction *)0);
647 sigaction(SIGTSTP, &sa, (struct sigaction *)0);
648 sigaction(SIGQUIT, &sa, (struct sigaction *)0);
649 sigaction(SIGTTOU, &sa, (struct sigaction *)0);
651 /* clean up on SIGINT; exiting on logout is the user's problem, now. */
652 sa.sa_handler = signal_exit;
653 sigaction(SIGINT, &sa, (struct sigaction *)0);
656 /* behavior never changes */
657 sa.sa_handler = signal_exit;
658 sigaction(SIGTERM, &sa, (struct sigaction *)0);
659 sigaction(SIGHUP, &sa, (struct sigaction *)0);
661 sa.sa_handler = SIG_IGN;
662 sigaction(SIGPIPE, &sa, (struct sigaction *)0);
664 sa.sa_handler = signal_child;
665 sigaction(SIGCHLD, &sa, (struct sigaction *)0);
667 sa.sa_handler = signal_usr1;
668 sigaction(SIGUSR1, &sa, (struct sigaction *)0);
672 /* Ignore keyboard signals if forking. Bad things will happen. */
673 signal(SIGINT, SIG_IGN);
674 signal(SIGTSTP, SIG_IGN);
675 signal(SIGTTOU, SIG_IGN);
676 signal(SIGQUIT, SIG_IGN);
678 /* clean up on SIGINT; exiting on logout is the user's problem, now. */
679 signal(SIGINT, signal_exit);
682 /* behavior never changes */
683 signal(SIGTERM, signal_exit);
684 signal(SIGHUP, signal_exit);
685 signal(SIGCHLD, signal_child);
686 signal(SIGPIPE, SIG_IGN); /* so that Xlib gets an error */
687 signal(SIGUSR1, signal_usr1);
691 /* detach() taken from old zwgc, with lots of stuff ripped out */
696 /* detach from terminal and fork. */
699 /* Attempt to join the process group of the session leader. This
700 * will get us a HUP if the session leader is in the foreground at
701 * logout time (which is often the case) or if the shell is running
702 * under telnetd or xterm (both of which HUP the process group of
703 * their child process). If we have getsid(), that's the best way
704 * of finding the session leader; otherwise use the process group of
705 * the parent process, which is a good guess. */
706 #if defined(HAVE_GETSID)
708 setpgid(0, getsid(0));
709 #elif defined(HAVE_GETPGID)
710 setpgid(0, getpgid(getppid()));
711 #elif !defined(GETPGRP_VOID)
712 setpgid(0, getpgrp(getppid()));
715 /* fork off and let parent exit... */
719 perror("zwgc: cannot fork, aborting:");