1 /* This file is part of the Project Athena Zephyr Notification System.
2 * It contains code for the "zctl" command.
4 * Created by: Robert French
8 * Copyright (c) 1987,1988 by the Massachusetts Institute of Technology.
9 * For copying and distribution information, see the file
14 #include <zephyr/zephyr.h>
20 static const char rcsid_zctl_c[] = "$Id$";
28 #define USERS_SUBS "/.zephyr.subs"
29 #define OLD_SUBS "/.subscriptions"
31 #define TOKEN_HOSTNAME "%host%"
32 #define TOKEN_CANONNAME "%canon%"
33 #define TOKEN_ME "%me%"
34 #define TOKEN_WILD "*"
45 char subsname[BUFSIZ];
46 char ourhost[MAXHOSTNAMELEN],ourhostcanon[MAXHOSTNAMELEN];
48 extern ss_request_table zctl_cmds;
50 int purge_subs(register ZSubscription_t *, int);
51 void add_file(short, ZSubscription_t *, int);
52 void del_file(short, ZSubscription_t *, int);
53 void fix_macros(ZSubscription_t *, ZSubscription_t *, int);
54 void fix_macros2(char *, char **);
55 int make_exist(char *);
63 char ssline[BUFSIZ],oldsubsname[BUFSIZ],*envptr,*tty = NULL;
65 #ifdef HAVE_SYS_UTSNAME
69 if ((retval = ZInitialize()) != ZERR_NONE) {
70 com_err(argv[0],retval,"while initializing");
74 /* Set hostname and tty for locations. If we support X, use the
75 * DISPLAY environment variable for the tty name. */
76 #ifndef X_DISPLAY_MISSING
77 tty = getenv("DISPLAY");
79 if ((retval = ZInitLocationInfo(NULL, tty)) != ZERR_NONE)
80 com_err(argv[0], retval, "initializing location information");
82 envptr = getenv("ZEPHYR_SUBS");
84 strcpy(subsname,envptr);
86 envptr = getenv("HOME");
88 strcpy(subsname,envptr);
90 if (!(pwd = getpwuid((int) getuid()))) {
91 fprintf(stderr,"Who are you?\n");
95 strcpy(subsname,pwd->pw_dir);
97 strcpy(oldsubsname,subsname);
98 strcat(oldsubsname,OLD_SUBS);
99 strcat(subsname,USERS_SUBS);
100 if (!access(oldsubsname,F_OK) && access(subsname, F_OK)) {
101 /* only if old one exists and new one does not exist */
102 printf("The .subscriptions file in your home directory is now being used as\n.zephyr.subs . I will rename it to .zephyr.subs for you.\n");
103 if (rename(oldsubsname,subsname))
104 com_err(argv[0], errno, "renaming .subscriptions");
108 #ifdef HAVE_SYS_UTSNAME
110 strcpy(ourhost, name.nodename);
112 if (gethostname(ourhost,MAXHOSTNAMELEN) == -1) {
113 com_err(argv[0],errno,"while getting host name");
118 if (!(hent = gethostbyname(ourhost))) {
119 fprintf(stderr,"%s: Can't resolve hostname %s; %s may be "
120 "wrong in subscriptions\n",argv[0],ourhost,
122 strncpy(ourhostcanon,ourhost,sizeof(ourhostcanon)-1);
124 strncpy(ourhostcanon,hent->h_name,sizeof(ourhostcanon)-1);
126 sci_idx = ss_create_invocation("zctl","",0,&zctl_cmds,&code);
128 ss_perror(sci_idx,code,"while creating invocation");
135 (void) sprintf(ssline+strlen(ssline),"%s ",argv[i]);
136 ssline[strlen(ssline)-1] = '\0';
137 code = ss_execute_line(sci_idx,ssline);
139 fprintf (stderr, "%s: %s: %s\n",
140 argv[0], error_message (code), ssline);
144 printf("ZCTL $Revision$ (Protocol %s%d.%d) - Type '?' for a list of commands.\n\n",
146 ZVERSIONMAJOR,ZVERSIONMINOR);
157 fprintf(stderr,"Usage: %s filename\n",argv[0]);
162 printf("Current file: %s\n",subsname);
164 (void) strcpy(subsname,argv[1]);
168 flush_locations(int argc,
174 fprintf(stderr,"Usage: %s\n",argv[0]);
178 if ((retval = ZFlushMyLocations()) != ZERR_NONE)
179 ss_perror(sci_idx,retval,"while flushing locations");
183 wgc_control(int argc,
188 struct sockaddr_in newsin;
191 newsin = ZGetDestAddr();
194 fprintf(stderr,"Usage: %s\n",argv[0]);
198 if ((newport = ZGetWGPort()) == -1) {
199 ss_perror(sci_idx,errno,"while getting WindowGram port");
203 newsin.sin_port = (u_short) newport;
204 if ((retval = ZSetDestAddr(&newsin)) != ZERR_NONE) {
205 ss_perror(sci_idx,retval,"while setting destination address");
209 (void) memset((char *)¬ice, 0, sizeof(notice));
210 notice.z_kind = UNSAFE;
212 notice.z_class = WG_CTL_CLASS;
213 notice.z_class_inst = WG_CTL_USER;
215 if (!strcmp(argv[0],"wg_read"))
216 notice.z_opcode = USER_REREAD;
217 if (!strcmp(argv[0],"wg_shutdown"))
218 notice.z_opcode = USER_SHUTDOWN;
219 if (!strcmp(argv[0],"wg_startup"))
220 notice.z_opcode = USER_STARTUP;
221 if (!strcmp(argv[0],"wg_exit"))
222 notice.z_opcode = USER_EXIT;
223 if (!notice.z_opcode) {
225 "unknown WindowGram client control command %s\n",
230 notice.z_recipient = "";
231 notice.z_default_format = "";
232 notice.z_message_len = 0;
234 if ((retval = ZSendNotice(¬ice,ZNOAUTH)) != ZERR_NONE)
235 ss_perror(sci_idx,retval,"while sending notice");
237 if ((retval = ZInitialize()) != ZERR_NONE)
238 ss_perror(sci_idx,retval,
239 "while reinitializing");
250 fprintf(stderr,"Usage: %s\n",argv[0]);
254 (void) memset((char *)¬ice, 0, sizeof(notice));
255 notice.z_kind = HMCTL;
257 notice.z_class = HM_CTL_CLASS;
258 notice.z_class_inst = HM_CTL_CLIENT;
260 if (!strcmp(argv[0],"hm_flush"))
261 notice.z_opcode = CLIENT_FLUSH;
262 if (!strcmp(argv[0],"new_server"))
263 notice.z_opcode = CLIENT_NEW_SERVER;
264 if (!notice.z_opcode) {
265 fprintf(stderr, "unknown HostManager control command %s\n",
270 notice.z_recipient = "";
271 notice.z_default_format = "";
272 notice.z_message_len = 0;
274 if ((retval = ZSendNotice(¬ice,ZNOAUTH)) != ZERR_NONE)
275 ss_perror(sci_idx,retval,"while sending notice");
286 fprintf(stderr,"Usage: %s <varname> <varname> ...\n",argv[0]);
290 for (i=1;i<argc;i++) {
291 value = ZGetVariable(argv[i]);
293 printf("%s: %s\n",argv[i],value);
295 printf("%s: not defined\n",argv[i]);
300 set_var(int argc, char *argv[])
302 int retval,setting_exp,i;
303 char *exp_level,*newargv[1];
307 fprintf(stderr,"Usage: %s <varname> [value]\n",
314 if (!strcasecmp(argv[1],"exposure")) {
317 fprintf(stderr,"An exposure setting must be specified.\n");
320 exp_level = (char *)0;
321 if (!strcasecmp(argv[2],EXPOSE_NONE))
322 exp_level = EXPOSE_NONE;
323 if (!strcasecmp(argv[2],EXPOSE_OPSTAFF))
324 exp_level = EXPOSE_OPSTAFF;
325 if (!strcasecmp(argv[2],EXPOSE_REALMVIS))
326 exp_level = EXPOSE_REALMVIS;
327 if (!strcasecmp(argv[2],EXPOSE_REALMANN))
328 exp_level = EXPOSE_REALMANN;
329 if (!strcasecmp(argv[2],EXPOSE_NETVIS))
330 exp_level = EXPOSE_NETVIS;
331 if (!strcasecmp(argv[2],EXPOSE_NETANN))
332 exp_level = EXPOSE_NETANN;
334 fprintf(stderr,"The exposure setting must be one of:\n");
335 fprintf(stderr,"%s, %s, %s, %s, %s, %s.\n",
346 retval = ZSetVariable(argv[1],"");
348 (void) strcpy(varcat,argv[2]);
349 for (i=3;i<argc;i++) {
350 (void) strcat(varcat," ");
351 (void) strcat(varcat,argv[i]);
353 retval = ZSetVariable(argv[1],varcat);
356 if (retval != ZERR_NONE) {
357 ss_perror(sci_idx,retval,"while setting variable value");
361 /* Side-effects? Naw, us? */
364 if ((retval = ZSetLocation(exp_level)) != ZERR_NONE)
365 ss_perror(sci_idx,retval,"while changing exposure status");
366 if (!strcmp(exp_level,EXPOSE_NONE)) {
367 newargv[0] = "wg_shutdown";
368 wgc_control(1,newargv);
370 newargv[0] = "wg_startup";
371 wgc_control(1,newargv);
381 char *exp_level = NULL;
385 fprintf(stderr, "Usage: %s\n",argv[0]);
388 if (!strcmp(argv[0],"unhide"))
389 exp_level = EXPOSE_REALMVIS;
391 exp_level = EXPOSE_OPSTAFF;
392 if ((retval = ZSetLocation(exp_level)) != ZERR_NONE)
393 ss_perror(sci_idx,retval,"while changing exposure status");
404 fprintf(stderr,"Usage: %s <varname> [<varname> ... ]\n",
410 if ((retval = ZUnsetVariable(argv[i])) != ZERR_NONE)
411 ss_perror(sci_idx,retval,
412 "while unsetting variable value");
416 cancel_subs(int argc,
423 fprintf(stderr,"Usage: %s\n",argv[0]);
427 if ((wgport = ZGetWGPort()) == -1) {
428 ss_perror(sci_idx,errno,"while finding WindowGram port");
431 if ((retval = ZCancelSubscriptions((u_short)wgport)) != ZERR_NONE)
432 ss_perror(sci_idx,retval,"while cancelling subscriptions");
441 ZSubscription_t sub,sub2;
443 if (argc > 4 || argc < 3) {
444 fprintf(stderr,"Usage: %s class instance [*]\n",argv[0]);
448 sub.zsub_class = argv[1];
449 sub.zsub_classinst = argv[2];
450 sub.zsub_recipient = (argc == 3)?ZGetSender():argv[3];
452 fix_macros(&sub,&sub2,1);
454 if ((wgport = ZGetWGPort()) == -1) {
455 ss_perror(sci_idx,errno,"while finding WindowGram port");
459 retval = (*argv[0] == 's') ?
460 ZSubscribeToSansDefaults(&sub2,1,(u_short)wgport) :
461 ZUnsubscribeTo(&sub2,1,(u_short)wgport);
463 if (retval != ZERR_NONE)
464 ss_perror(sci_idx,retval,"while subscribing");
474 if (argc > 4 || argc < 3) {
475 fprintf(stderr,"Usage: %s class instance [*]\n",argv[0]);
479 if (argv[1][0] == '!') {
481 (!strcmp(argv[0],"add_unsubscription") ||
482 !strcmp(argv[0],"add_un") ||
483 !strcmp(argv[0],"delete_unsubscription") ||
484 !strcmp(argv[0],"del_un")) ?
485 "Do not use `!' as the first character of a class.\n\tIt is automatically added before modifying the subscription file." :
486 "Do not use `!' as the first character of a class.\n\tIt is reserved for internal use with un-subscriptions.");
489 sub.zsub_class = argv[1];
490 sub.zsub_classinst = argv[2];
491 sub.zsub_recipient = (argc == 3)?TOKEN_ME:argv[3];
493 if (make_exist(subsname))
495 if ((wgport = ZGetWGPort()) == -1) {
496 ss_perror(sci_idx,errno,"while finding WindowGram port");
500 if (!strcmp(argv[0],"add"))
501 add_file(wgport,&sub,0);
502 else if (!strcmp(argv[0],"add_unsubscription") ||
503 !strcmp(argv[0],"add_un"))
504 add_file(wgport,&sub,1);
505 else if (!strcmp(argv[0],"delete") ||
506 !strcmp(argv[0],"del") ||
507 !strcmp(argv[0],"dl"))
508 del_file(wgport,&sub,0);
509 else if (!strcmp(argv[0],"delete_unsubscription") ||
510 !strcmp(argv[0],"del_un")) {
511 del_file(wgport,&sub,1);
513 ss_perror(sci_idx,0,"unknown command name");
518 add_file(short wgport,
519 ZSubscription_t *subs,
524 ZSubscription_t sub2;
527 (void) purge_subs(subs,ALL); /* remove copies in the subs file */
528 if (!(fp = fopen(subsname,"a"))) {
529 (void) sprintf(errbuf,"while opening %s for append",subsname);
530 ss_perror(sci_idx,errno,errbuf);
533 fprintf(fp,"%s%s,%s,%s\n",
535 subs->zsub_class, subs->zsub_classinst, subs->zsub_recipient);
536 if (fclose(fp) == EOF) {
537 (void) sprintf(errbuf, "while closing %s", subsname);
538 ss_perror(sci_idx, errno, errbuf);
541 fix_macros(subs,&sub2,1);
543 ? ZUnsubscribeTo(&sub2,1,(u_short)wgport)
544 : ZSubscribeToSansDefaults(&sub2,1,(u_short)wgport));
546 ss_perror(sci_idx,retval,
547 unsub ? "while unsubscribing" :
548 "while subscribing");
553 del_file(short wgport,
554 register ZSubscription_t *subs,
557 ZSubscription_t sub2;
560 retval = purge_subs(subs, unsub ? UNSUBONLY : SUBONLY);
563 if (retval == NOT_REMOVED)
565 "Couldn't find %sclass %s instance %s recipient %s in\n\tfile %s\n",
566 unsub ? "un-subscription " : "",
567 subs->zsub_class, subs->zsub_classinst,
568 subs->zsub_recipient, subsname);
569 fix_macros(subs,&sub2,1);
570 if ((retval = ZUnsubscribeTo(&sub2,1,(u_short)wgport)) !=
572 ss_perror(sci_idx,retval,"while unsubscribing");
577 purge_subs(register ZSubscription_t *subs,
581 char errbuf[BUFSIZ],subline[BUFSIZ];
582 char backup[BUFSIZ],ourline[BUFSIZ];
583 int delflag = NOT_REMOVED;
592 ss_perror(sci_idx,0,"internal error in purge_subs");
596 (void) sprintf(ourline,"%s,%s,%s",
598 subs->zsub_classinst,
599 subs->zsub_recipient);
601 if (!(fp = fopen(subsname,"r"))) {
602 (void) sprintf(errbuf,"while opening %s for read",subsname);
603 ss_perror(sci_idx,errno,errbuf);
606 (void) strcpy(backup, subsname);
607 (void) strcat(backup, ".temp");
608 (void) unlink(backup);
609 if (!(fpout = fopen(backup,"w"))) {
610 (void) sprintf(errbuf,"while opening %s for writing",backup);
611 ss_perror(sci_idx,errno,errbuf);
616 if (!fgets(subline,sizeof subline,fp))
619 subline[strlen(subline)-1] = '\0'; /* nuke newline */
622 keep = strcmp(subline,ourline);
625 keep = (*subline != '!' || strcmp(subline+1,ourline));
628 keep = (strcmp(subline,ourline) &&
629 (*subline != '!' || strcmp(subline+1,
634 fputs(subline, fpout);
635 if (ferror(fpout) || (fputc('\n', fpout) == EOF)) {
636 (void) sprintf(errbuf, "while writing to %s",
638 ss_perror(sci_idx, errno, errbuf);
643 (void) fclose(fp); /* open read-only, ignore errs */
644 if (fclose(fpout) == EOF) {
645 (void) sprintf(errbuf, "while closing %s",backup);
646 ss_perror(sci_idx, errno, errbuf);
649 if (rename(backup,subsname) == -1) {
650 (void) sprintf(errbuf,"while renaming %s to %s\n",
652 ss_perror(sci_idx,errno,errbuf);
662 ZSubscription_t subs[SUBSATONCE],subs2[SUBSATONCE],unsubs[SUBSATONCE];
664 int ind,unind,lineno,i,retval,type;
666 char *comma,*comma2,*file,subline[BUFSIZ];
669 fprintf(stderr,"Usage: %s [file]\n",argv[0]);
676 if (!strcmp(argv[0],"list") || !strcmp(argv[0],"ls"))
682 if ((wgport = ZGetWGPort()) == -1) {
683 ss_perror(sci_idx,errno,
684 "while finding WindowGram port");
688 file = (argc == 1) ? subsname : argv[1];
690 fp = fopen(file,"r");
693 ss_perror(sci_idx,errno,
694 "while loading subscription file");
702 if (!fgets(subline,sizeof subline,fp))
704 if (*subline == '#' || !*subline)
706 subline[strlen(subline)-1] = '\0'; /* nuke newline */
707 comma = strchr(subline,',');
709 comma2 = strchr(comma+1,',');
712 if (!comma || !comma2) {
714 "Malformed subscription at line %d of %s:\n%s\n",
715 lineno,file,subline);
722 printf("(Un-subscription) Class %s instance %s recipient %s\n",
723 subline+1, comma+1, comma2+1);
725 printf("Class %s instance %s recipient %s\n",
726 subline, comma+1, comma2+1);
729 if (*subline == '!') { /* an un-subscription */
730 /* if we are explicitly un-subscribing to
731 the contents of a subscription file, ignore
732 any un-subscriptions in that file */
735 unsubs[unind].zsub_class =
736 (char *)malloc((unsigned)(strlen(subline)));
737 /* XXX check malloc return */
738 /* skip the leading '!' */
739 (void) strcpy(unsubs[unind].zsub_class,subline+1);
740 unsubs[unind].zsub_classinst =
741 (char *)malloc((unsigned)(strlen(comma+1)+1));
742 /* XXX check malloc return */
743 (void) strcpy(unsubs[unind].zsub_classinst,comma+1);
744 unsubs[unind].zsub_recipient =
745 (char *)malloc((unsigned)(strlen(comma2+1)+1));
746 /* XXX check malloc return */
747 (void) strcpy(unsubs[unind].zsub_recipient,comma2+1);
750 subs[ind].zsub_class =
751 (char *)malloc((unsigned)(strlen(subline)+1));
752 /* XXX check malloc return */
753 (void) strcpy(subs[ind].zsub_class,subline);
754 subs[ind].zsub_classinst =
755 (char *)malloc((unsigned)(strlen(comma+1)+1));
756 /* XXX check malloc return */
757 (void) strcpy(subs[ind].zsub_classinst,comma+1);
758 subs[ind].zsub_recipient =
759 (char *)malloc((unsigned)(strlen(comma2+1)+1));
760 /* XXX check malloc return */
761 (void) strcpy(subs[ind].zsub_recipient,comma2+1);
764 if (ind == SUBSATONCE) {
765 fix_macros(subs,subs2,ind);
766 if ((retval = (type == SUB)?
767 ZSubscribeTo(subs2,ind,(u_short)wgport):
768 ZUnsubscribeTo(subs2,ind,(u_short)wgport)) !=
770 ss_perror(sci_idx,retval,(type == SUB)?
772 "while unsubscribing");
775 for (i=0;i<ind;i++) {
776 free(subs[i].zsub_class);
777 free(subs[i].zsub_classinst);
778 free(subs[i].zsub_recipient);
782 if (unind == SUBSATONCE) {
783 fix_macros(unsubs,subs2,unind);
784 if ((retval = ZUnsubscribeTo(subs2,unind,(u_short)wgport)) != ZERR_NONE) {
785 ss_perror(sci_idx,retval,
786 "while unsubscribing to un-subscriptions");
789 for (i=0;i<unind;i++) {
790 free(unsubs[i].zsub_class);
791 free(unsubs[i].zsub_classinst);
792 free(unsubs[i].zsub_recipient);
799 /* even if we have no subscriptions, be sure to send
800 an empty packet to trigger the default subscriptions */
801 fix_macros(subs,subs2,ind);
802 if ((retval = (type == SUB)?ZSubscribeTo(subs2,ind,(u_short)wgport):
803 ZUnsubscribeTo(subs2,ind,(u_short)wgport)) != ZERR_NONE) {
804 ss_perror(sci_idx,retval,(type == SUB)?
806 "while unsubscribing");
810 fix_macros(unsubs,subs2,unind);
812 ZUnsubscribeTo(subs2,unind,(u_short)wgport)) != ZERR_NONE) {
813 ss_perror(sci_idx,retval,
814 "while unsubscribing to un-subscriptions");
820 for (i=0;i<ind;i++) {
821 free(subs[i].zsub_class);
822 free(subs[i].zsub_classinst);
823 free(subs[i].zsub_recipient);
825 for (i=0;i<unind;i++) {
826 free(unsubs[i].zsub_class);
827 free(unsubs[i].zsub_classinst);
828 free(unsubs[i].zsub_recipient);
831 (void) fclose(fp); /* ignore errs--file is read-only */
841 ZSubscription_t subs;
842 int i,nsubs,retval,save,one,defs;
844 char *file,backup[BUFSIZ];
849 if (!strcmp(argv[0],"save"))
851 else if (!strcmp(argv[0], "defaults") || !strcmp(argv[0], "defs"))
854 if (argc != 1 && !(save && argc == 2)) {
855 fprintf(stderr,"Usage: %s%s\n",argv[0],save?" [filename]":"");
860 if ((wgport = ZGetWGPort()) == -1) {
861 ss_perror(sci_idx,errno,
862 "while finding WindowGram port");
867 retval = ZRetrieveDefaultSubscriptions(&nsubs);
869 retval = ZRetrieveSubscriptions((u_short)wgport,&nsubs);
871 if (retval == ZERR_TOOMANYSUBS) {
872 fprintf(stderr,"Too many subscriptions -- some have not been returned.\n");
874 fprintf(stderr,"Save aborted.\n");
879 if (retval != ZERR_NONE) {
880 ss_perror(sci_idx,retval,"retrieving subscriptions");
885 file = (argc == 1)?subsname:argv[1];
886 (void) strcpy(backup,file);
887 (void) strcat(backup,".temp");
888 if (!(fp = fopen(backup,"w"))) {
889 (void) sprintf(errbuf,"while opening %s for write",
891 ss_perror(sci_idx,errno,errbuf);
896 for (i=0;i<nsubs;i++) {
898 if ((retval = ZGetSubscriptions(&subs,&one)) != ZERR_NONE) {
899 ss_perror(sci_idx,retval,"while getting subscription");
901 fprintf(stderr,"Subscriptions file not modified\n");
903 (void) unlink(backup);
908 fprintf(fp,"%s,%s,%s\n",subs.zsub_class,
909 subs.zsub_classinst, subs.zsub_recipient);
911 printf("Class %s Instance %s Recipient %s\n",
912 subs.zsub_class, subs.zsub_classinst,
913 subs.zsub_recipient);
917 if (fclose(fp) == EOF) {
918 (void) sprintf(errbuf, "while closing %s", backup);
919 ss_perror(sci_idx, errno, errbuf);
922 if (rename(backup,file) == -1) {
923 (void) sprintf(errbuf,"while renaming %s to %s",
925 ss_perror(sci_idx,retval,errbuf);
926 (void) unlink(backup);
932 make_exist(char *filename)
937 if (!access(filename,F_OK))
940 if (!(fpout = fopen(filename,"w"))) {
941 (void) sprintf(errbuf,"while opening %s for write",filename);
942 ss_perror(sci_idx,errno,errbuf);
946 if (fclose(fpout) == EOF) {
947 (void) sprintf(errbuf, "while closing %s", filename);
948 ss_perror(sci_idx, errno, errbuf);
955 fix_macros(ZSubscription_t *subs,
956 ZSubscription_t *subs2,
961 for (i=0;i<num;i++) {
963 fix_macros2(subs[i].zsub_class,&subs2[i].zsub_class);
964 fix_macros2(subs[i].zsub_classinst,&subs2[i].zsub_classinst);
965 fix_macros2(subs[i].zsub_recipient,&subs2[i].zsub_recipient);
970 fix_macros2(char *src, char **dest)
972 if (!strcmp(src,TOKEN_HOSTNAME)) {
976 if (!strcmp(src,TOKEN_CANONNAME)) {
977 *dest = ourhostcanon;
980 if (!strcmp(src,TOKEN_ME))
981 *dest = ZGetSender();