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 "*"
46 char subsname[BUFSIZ];
47 char ourhost[MAXHOSTNAMELEN],ourhostcanon[MAXHOSTNAMELEN];
49 extern ss_request_table zctl_cmds;
51 void add_file(), del_file(), fix_macros(), fix_macros2();
59 char ssline[BUFSIZ],oldsubsname[BUFSIZ],*envptr,*tty = NULL;
61 #ifdef HAVE_SYS_UTSNAME
65 if ((retval = ZInitialize()) != ZERR_NONE) {
66 com_err(argv[0],retval,"while initializing");
70 /* Set hostname and tty for locations. If we support X, use the
71 * DISPLAY environment variable for the tty name. */
72 #ifndef X_DISPLAY_MISSING
73 tty = getenv("DISPLAY");
75 if ((retval = ZInitLocationInfo(NULL, tty)) != ZERR_NONE)
76 com_err(argv[0], retval, "initializing location information");
78 envptr = getenv("ZEPHYR_SUBS");
80 strcpy(subsname,envptr);
82 envptr = getenv("HOME");
84 strcpy(subsname,envptr);
86 if (!(pwd = getpwuid((int) getuid()))) {
87 fprintf(stderr,"Who are you?\n");
91 strcpy(subsname,pwd->pw_dir);
93 strcpy(oldsubsname,subsname);
94 strcat(oldsubsname,OLD_SUBS);
95 strcat(subsname,USERS_SUBS);
96 if (!access(oldsubsname,F_OK) && access(subsname, F_OK)) {
97 /* only if old one exists and new one does not exist */
98 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");
99 if (rename(oldsubsname,subsname))
100 com_err(argv[0], errno, "renaming .subscriptions");
104 #ifdef HAVE_SYS_UTSNAME
106 strcpy(ourhost, name.nodename);
108 if (gethostname(ourhost,MAXHOSTNAMELEN) == -1) {
109 com_err(argv[0],errno,"while getting host name");
114 if (!(hent = gethostbyname(ourhost))) {
115 fprintf(stderr,"%s: Can't resolve hostname %s; %s may be "
116 "wrong in subscriptions\n",argv[0],ourhost,
118 strncpy(ourhostcanon,ourhost,sizeof(ourhostcanon)-1);
120 strncpy(ourhostcanon,hent->h_name,sizeof(ourhostcanon)-1);
122 sci_idx = ss_create_invocation("zctl","",0,&zctl_cmds,&code);
124 ss_perror(sci_idx,code,"while creating invocation");
131 (void) sprintf(ssline+strlen(ssline),"%s ",argv[i]);
132 ssline[strlen(ssline)-1] = '\0';
133 code = ss_execute_line(sci_idx,ssline);
135 fprintf (stderr, "%s: %s: %s\n",
136 argv[0], error_message (code), ssline);
140 printf("ZCTL $Revision$ (Protocol %s%d.%d) - Type '?' for a list of commands.\n\n",
142 ZVERSIONMAJOR,ZVERSIONMINOR);
154 fprintf(stderr,"Usage: %s filename\n",argv[0]);
159 printf("Current file: %s\n",subsname);
161 (void) strcpy(subsname,argv[1]);
165 flush_locations(argc,argv)
172 fprintf(stderr,"Usage: %s\n",argv[0]);
176 if ((retval = ZFlushMyLocations()) != ZERR_NONE)
177 ss_perror(sci_idx,retval,"while flushing locations");
181 wgc_control(argc,argv)
183 register char **argv;
187 struct sockaddr_in newsin;
190 newsin = ZGetDestAddr();
193 fprintf(stderr,"Usage: %s\n",argv[0]);
197 if ((newport = ZGetWGPort()) == -1) {
198 ss_perror(sci_idx,errno,"while getting WindowGram port");
202 newsin.sin_port = (u_short) newport;
203 if ((retval = ZSetDestAddr(&newsin)) != ZERR_NONE) {
204 ss_perror(sci_idx,retval,"while setting destination address");
208 (void) memset((char *)¬ice, 0, sizeof(notice));
209 notice.z_kind = UNSAFE;
211 notice.z_class = WG_CTL_CLASS;
212 notice.z_class_inst = WG_CTL_USER;
214 if (!strcmp(argv[0],"wg_read"))
215 notice.z_opcode = USER_REREAD;
216 if (!strcmp(argv[0],"wg_shutdown"))
217 notice.z_opcode = USER_SHUTDOWN;
218 if (!strcmp(argv[0],"wg_startup"))
219 notice.z_opcode = USER_STARTUP;
220 if (!strcmp(argv[0],"wg_exit"))
221 notice.z_opcode = USER_EXIT;
222 if (!notice.z_opcode) {
224 "unknown WindowGram client control command %s\n",
229 notice.z_recipient = "";
230 notice.z_default_format = "";
231 notice.z_message_len = 0;
233 if ((retval = ZSendNotice(¬ice,ZNOAUTH)) != ZERR_NONE)
234 ss_perror(sci_idx,retval,"while sending notice");
236 if ((retval = ZInitialize()) != ZERR_NONE)
237 ss_perror(sci_idx,retval,
238 "while reinitializing");
242 hm_control(argc,argv)
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");
287 fprintf(stderr,"Usage: %s <varname> <varname> ...\n",argv[0]);
291 for (i=1;i<argc;i++) {
292 value = ZGetVariable(argv[i]);
294 printf("%s: %s\n",argv[i],value);
296 printf("%s: not defined\n",argv[i]);
303 register char **argv;
305 int retval,setting_exp,i;
306 char *exp_level,*newargv[1];
310 fprintf(stderr,"Usage: %s <varname> [value]\n",
317 if (!strcasecmp(argv[1],"exposure")) {
320 fprintf(stderr,"An exposure setting must be specified.\n");
323 exp_level = (char *)0;
324 if (!strcasecmp(argv[2],EXPOSE_NONE))
325 exp_level = EXPOSE_NONE;
326 if (!strcasecmp(argv[2],EXPOSE_OPSTAFF))
327 exp_level = EXPOSE_OPSTAFF;
328 if (!strcasecmp(argv[2],EXPOSE_REALMVIS))
329 exp_level = EXPOSE_REALMVIS;
330 if (!strcasecmp(argv[2],EXPOSE_REALMANN))
331 exp_level = EXPOSE_REALMANN;
332 if (!strcasecmp(argv[2],EXPOSE_NETVIS))
333 exp_level = EXPOSE_NETVIS;
334 if (!strcasecmp(argv[2],EXPOSE_NETANN))
335 exp_level = EXPOSE_NETANN;
337 fprintf(stderr,"The exposure setting must be one of:\n");
338 fprintf(stderr,"%s, %s, %s, %s, %s, %s.\n",
349 retval = ZSetVariable(argv[1],"");
351 (void) strcpy(varcat,argv[2]);
352 for (i=3;i<argc;i++) {
353 (void) strcat(varcat," ");
354 (void) strcat(varcat,argv[i]);
356 retval = ZSetVariable(argv[1],varcat);
359 if (retval != ZERR_NONE) {
360 ss_perror(sci_idx,retval,"while setting variable value");
364 /* Side-effects? Naw, us? */
367 if ((retval = ZSetLocation(exp_level)) != ZERR_NONE)
368 ss_perror(sci_idx,retval,"while changing exposure status");
369 if (!strcmp(exp_level,EXPOSE_NONE)) {
370 newargv[0] = "wg_shutdown";
371 wgc_control(1,newargv);
373 newargv[0] = "wg_startup";
374 wgc_control(1,newargv);
385 char *exp_level = NULL;
389 fprintf(stderr, "Usage: %s\n",argv[0]);
392 if (!strcmp(argv[0],"unhide"))
393 exp_level = EXPOSE_REALMVIS;
395 exp_level = EXPOSE_OPSTAFF;
396 if ((retval = ZSetLocation(exp_level)) != ZERR_NONE)
397 ss_perror(sci_idx,retval,"while changing exposure status");
409 fprintf(stderr,"Usage: %s <varname> [<varname> ... ]\n",
415 if ((retval = ZUnsetVariable(argv[i])) != ZERR_NONE)
416 ss_perror(sci_idx,retval,
417 "while unsetting variable value");
421 cancel_subs(argc,argv)
429 fprintf(stderr,"Usage: %s\n",argv[0]);
433 if ((wgport = ZGetWGPort()) == -1) {
434 ss_perror(sci_idx,errno,"while finding WindowGram port");
437 if ((retval = ZCancelSubscriptions((u_short)wgport)) != ZERR_NONE)
438 ss_perror(sci_idx,retval,"while cancelling subscriptions");
448 ZSubscription_t sub,sub2;
450 if (argc > 4 || argc < 3) {
451 fprintf(stderr,"Usage: %s class instance [*]\n",argv[0]);
455 sub.zsub_class = argv[1];
456 sub.zsub_classinst = argv[2];
457 sub.zsub_recipient = (argc == 3)?ZGetSender():argv[3];
459 fix_macros(&sub,&sub2,1);
461 if ((wgport = ZGetWGPort()) == -1) {
462 ss_perror(sci_idx,errno,"while finding WindowGram port");
466 retval = (*argv[0] == 's') ?
467 ZSubscribeToSansDefaults(&sub2,1,(u_short)wgport) :
468 ZUnsubscribeTo(&sub2,1,(u_short)wgport);
470 if (retval != ZERR_NONE)
471 ss_perror(sci_idx,retval,"while subscribing");
482 if (argc > 4 || argc < 3) {
483 fprintf(stderr,"Usage: %s class instance [*]\n",argv[0]);
487 if (argv[1][0] == '!') {
489 (!strcmp(argv[0],"add_unsubscription") ||
490 !strcmp(argv[0],"add_un") ||
491 !strcmp(argv[0],"delete_unsubscription") ||
492 !strcmp(argv[0],"del_un")) ?
493 "Do not use `!' as the first character of a class.\n\tIt is automatically added before modifying the subscription file." :
494 "Do not use `!' as the first character of a class.\n\tIt is reserved for internal use with un-subscriptions.");
497 sub.zsub_class = argv[1];
498 sub.zsub_classinst = argv[2];
499 sub.zsub_recipient = (argc == 3)?TOKEN_ME:argv[3];
501 if (make_exist(subsname))
503 if ((wgport = ZGetWGPort()) == -1) {
504 ss_perror(sci_idx,errno,"while finding WindowGram port");
508 if (!strcmp(argv[0],"add"))
509 add_file(wgport,&sub,0);
510 else if (!strcmp(argv[0],"add_unsubscription") ||
511 !strcmp(argv[0],"add_un"))
512 add_file(wgport,&sub,1);
513 else if (!strcmp(argv[0],"delete") ||
514 !strcmp(argv[0],"del") ||
515 !strcmp(argv[0],"dl"))
516 del_file(wgport,&sub,0);
517 else if (!strcmp(argv[0],"delete_unsubscription") ||
518 !strcmp(argv[0],"del_un")) {
519 del_file(wgport,&sub,1);
521 ss_perror(sci_idx,0,"unknown command name");
526 add_file(wgport,subs,unsub)
528 ZSubscription_t *subs;
533 ZSubscription_t sub2;
536 (void) purge_subs(subs,ALL); /* remove copies in the subs file */
537 if (!(fp = fopen(subsname,"a"))) {
538 (void) sprintf(errbuf,"while opening %s for append",subsname);
539 ss_perror(sci_idx,errno,errbuf);
542 fprintf(fp,"%s%s,%s,%s\n",
544 subs->zsub_class, subs->zsub_classinst, subs->zsub_recipient);
545 if (fclose(fp) == EOF) {
546 (void) sprintf(errbuf, "while closing %s", subsname);
547 ss_perror(sci_idx, errno, errbuf);
550 fix_macros(subs,&sub2,1);
551 if (retval = (unsub ? ZUnsubscribeTo(&sub2,1,(u_short)wgport) :
552 ZSubscribeToSansDefaults(&sub2,1,(u_short)wgport)))
553 ss_perror(sci_idx,retval,
554 unsub ? "while unsubscribing" :
555 "while subscribing");
560 del_file(wgport,subs,unsub)
562 register ZSubscription_t *subs;
565 ZSubscription_t sub2;
568 retval = purge_subs(subs, unsub ? UNSUBONLY : SUBONLY);
571 if (retval == NOT_REMOVED)
573 "Couldn't find %sclass %s instance %s recipient %s in\n\tfile %s\n",
574 unsub ? "un-subscription " : "",
575 subs->zsub_class, subs->zsub_classinst,
576 subs->zsub_recipient, subsname);
577 fix_macros(subs,&sub2,1);
578 if ((retval = ZUnsubscribeTo(&sub2,1,(u_short)wgport)) !=
580 ss_perror(sci_idx,retval,"while unsubscribing");
585 purge_subs(subs,which)
586 register ZSubscription_t *subs;
590 char errbuf[BUFSIZ],subline[BUFSIZ];
591 char backup[BUFSIZ],ourline[BUFSIZ];
592 int delflag = NOT_REMOVED;
601 ss_perror(sci_idx,0,"internal error in purge_subs");
605 (void) sprintf(ourline,"%s,%s,%s",
607 subs->zsub_classinst,
608 subs->zsub_recipient);
610 if (!(fp = fopen(subsname,"r"))) {
611 (void) sprintf(errbuf,"while opening %s for read",subsname);
612 ss_perror(sci_idx,errno,errbuf);
615 (void) strcpy(backup, subsname);
616 (void) strcat(backup, ".temp");
617 (void) unlink(backup);
618 if (!(fpout = fopen(backup,"w"))) {
619 (void) sprintf(errbuf,"while opening %s for writing",backup);
620 ss_perror(sci_idx,errno,errbuf);
625 if (!fgets(subline,sizeof subline,fp))
628 subline[strlen(subline)-1] = '\0'; /* nuke newline */
631 keep = strcmp(subline,ourline);
634 keep = (*subline != '!' || strcmp(subline+1,ourline));
637 keep = (strcmp(subline,ourline) &&
638 (*subline != '!' || strcmp(subline+1,
643 fputs(subline, fpout);
644 if (ferror(fpout) || (fputc('\n', fpout) == EOF)) {
645 (void) sprintf(errbuf, "while writing to %s",
647 ss_perror(sci_idx, errno, errbuf);
652 (void) fclose(fp); /* open read-only, ignore errs */
653 if (fclose(fpout) == EOF) {
654 (void) sprintf(errbuf, "while closing %s",backup);
655 ss_perror(sci_idx, errno, errbuf);
658 if (rename(backup,subsname) == -1) {
659 (void) sprintf(errbuf,"while renaming %s to %s\n",
661 ss_perror(sci_idx,errno,errbuf);
672 ZSubscription_t subs[SUBSATONCE],subs2[SUBSATONCE],unsubs[SUBSATONCE];
674 int ind,unind,lineno,i,retval,type;
676 char *comma,*comma2,*file,subline[BUFSIZ];
679 fprintf(stderr,"Usage: %s [file]\n",argv[0]);
686 if (!strcmp(argv[0],"list") || !strcmp(argv[0],"ls"))
692 if ((wgport = ZGetWGPort()) == -1) {
693 ss_perror(sci_idx,errno,
694 "while finding WindowGram port");
698 file = (argc == 1) ? subsname : argv[1];
700 fp = fopen(file,"r");
703 ss_perror(sci_idx,errno,
704 "while loading subscription file");
712 if (!fgets(subline,sizeof subline,fp))
714 if (*subline == '#' || !*subline)
716 subline[strlen(subline)-1] = '\0'; /* nuke newline */
717 comma = strchr(subline,',');
719 comma2 = strchr(comma+1,',');
722 if (!comma || !comma2) {
724 "Malformed subscription at line %d of %s:\n%s\n",
725 lineno,file,subline);
732 printf("(Un-subscription) Class %s instance %s recipient %s\n",
733 subline+1, comma+1, comma2+1);
735 printf("Class %s instance %s recipient %s\n",
736 subline, comma+1, comma2+1);
739 if (*subline == '!') { /* an un-subscription */
740 /* if we are explicitly un-subscribing to
741 the contents of a subscription file, ignore
742 any un-subscriptions in that file */
745 unsubs[unind].zsub_class =
746 (char *)malloc((unsigned)(strlen(subline)));
747 /* XXX check malloc return */
748 /* skip the leading '!' */
749 (void) strcpy(unsubs[unind].zsub_class,subline+1);
750 unsubs[unind].zsub_classinst =
751 (char *)malloc((unsigned)(strlen(comma+1)+1));
752 /* XXX check malloc return */
753 (void) strcpy(unsubs[unind].zsub_classinst,comma+1);
754 unsubs[unind].zsub_recipient =
755 (char *)malloc((unsigned)(strlen(comma2+1)+1));
756 /* XXX check malloc return */
757 (void) strcpy(unsubs[unind].zsub_recipient,comma2+1);
760 subs[ind].zsub_class =
761 (char *)malloc((unsigned)(strlen(subline)+1));
762 /* XXX check malloc return */
763 (void) strcpy(subs[ind].zsub_class,subline);
764 subs[ind].zsub_classinst =
765 (char *)malloc((unsigned)(strlen(comma+1)+1));
766 /* XXX check malloc return */
767 (void) strcpy(subs[ind].zsub_classinst,comma+1);
768 subs[ind].zsub_recipient =
769 (char *)malloc((unsigned)(strlen(comma2+1)+1));
770 /* XXX check malloc return */
771 (void) strcpy(subs[ind].zsub_recipient,comma2+1);
774 if (ind == SUBSATONCE) {
775 fix_macros(subs,subs2,ind);
776 if ((retval = (type == SUB)?
777 ZSubscribeTo(subs2,ind,(u_short)wgport):
778 ZUnsubscribeTo(subs2,ind,(u_short)wgport)) !=
780 ss_perror(sci_idx,retval,(type == SUB)?
782 "while unsubscribing");
785 for (i=0;i<ind;i++) {
786 free(subs[i].zsub_class);
787 free(subs[i].zsub_classinst);
788 free(subs[i].zsub_recipient);
792 if (unind == SUBSATONCE) {
793 fix_macros(unsubs,subs2,unind);
794 if ((retval = ZUnsubscribeTo(subs2,unind,(u_short)wgport)) != ZERR_NONE) {
795 ss_perror(sci_idx,retval,
796 "while unsubscribing to un-subscriptions");
799 for (i=0;i<unind;i++) {
800 free(unsubs[i].zsub_class);
801 free(unsubs[i].zsub_classinst);
802 free(unsubs[i].zsub_recipient);
809 /* even if we have no subscriptions, be sure to send
810 an empty packet to trigger the default subscriptions */
811 fix_macros(subs,subs2,ind);
812 if ((retval = (type == SUB)?ZSubscribeTo(subs2,ind,(u_short)wgport):
813 ZUnsubscribeTo(subs2,ind,(u_short)wgport)) != ZERR_NONE) {
814 ss_perror(sci_idx,retval,(type == SUB)?
816 "while unsubscribing");
820 fix_macros(unsubs,subs2,unind);
822 ZUnsubscribeTo(subs2,unind,(u_short)wgport)) != ZERR_NONE) {
823 ss_perror(sci_idx,retval,
824 "while unsubscribing to un-subscriptions");
830 for (i=0;i<ind;i++) {
831 free(subs[i].zsub_class);
832 free(subs[i].zsub_classinst);
833 free(subs[i].zsub_recipient);
835 for (i=0;i<unind;i++) {
836 free(unsubs[i].zsub_class);
837 free(unsubs[i].zsub_classinst);
838 free(unsubs[i].zsub_recipient);
841 (void) fclose(fp); /* ignore errs--file is read-only */
852 ZSubscription_t subs;
853 int i,nsubs,retval,save,one,defs;
855 char *file,backup[BUFSIZ];
860 if (!strcmp(argv[0],"save"))
862 else if (!strcmp(argv[0], "defaults") || !strcmp(argv[0], "defs"))
865 if (argc != 1 && !(save && argc == 2)) {
866 fprintf(stderr,"Usage: %s%s\n",argv[0],save?" [filename]":"");
871 if ((wgport = ZGetWGPort()) == -1) {
872 ss_perror(sci_idx,errno,
873 "while finding WindowGram port");
878 retval = ZRetrieveDefaultSubscriptions(&nsubs);
880 retval = ZRetrieveSubscriptions((u_short)wgport,&nsubs);
882 if (retval == ZERR_TOOMANYSUBS) {
883 fprintf(stderr,"Too many subscriptions -- some have not been returned.\n");
885 fprintf(stderr,"Save aborted.\n");
890 if (retval != ZERR_NONE) {
891 ss_perror(sci_idx,retval,"retrieving subscriptions");
896 file = (argc == 1)?subsname:argv[1];
897 (void) strcpy(backup,file);
898 (void) strcat(backup,".temp");
899 if (!(fp = fopen(backup,"w"))) {
900 (void) sprintf(errbuf,"while opening %s for write",
902 ss_perror(sci_idx,errno,errbuf);
907 for (i=0;i<nsubs;i++) {
909 if ((retval = ZGetSubscriptions(&subs,&one)) != ZERR_NONE) {
910 ss_perror(sci_idx,retval,"while getting subscription");
912 fprintf(stderr,"Subscriptions file not modified\n");
914 (void) unlink(backup);
919 fprintf(fp,"%s,%s,%s\n",subs.zsub_class,
920 subs.zsub_classinst, subs.zsub_recipient);
922 printf("Class %s Instance %s Recipient %s\n",
923 subs.zsub_class, subs.zsub_classinst,
924 subs.zsub_recipient);
928 if (fclose(fp) == EOF) {
929 (void) sprintf(errbuf, "while closing %s", backup);
930 ss_perror(sci_idx, errno, errbuf);
933 if (rename(backup,file) == -1) {
934 (void) sprintf(errbuf,"while renaming %s to %s",
936 ss_perror(sci_idx,retval,errbuf);
937 (void) unlink(backup);
949 if (!access(filename,F_OK))
952 if (!(fpout = fopen(filename,"w"))) {
953 (void) sprintf(errbuf,"while opening %s for write",filename);
954 ss_perror(sci_idx,errno,errbuf);
958 if (fclose(fpout) == EOF) {
959 (void) sprintf(errbuf, "while closing %s", filename);
960 ss_perror(sci_idx, errno, errbuf);
967 fix_macros(subs,subs2,num)
968 ZSubscription_t *subs,*subs2;
973 for (i=0;i<num;i++) {
975 fix_macros2(subs[i].zsub_class,&subs2[i].zsub_class);
976 fix_macros2(subs[i].zsub_classinst,&subs2[i].zsub_classinst);
977 fix_macros2(subs[i].zsub_recipient,&subs2[i].zsub_recipient);
982 fix_macros2(src,dest)
986 if (!strcmp(src,TOKEN_HOSTNAME)) {
990 if (!strcmp(src,TOKEN_CANONNAME)) {
991 *dest = ourhostcanon;
994 if (!strcmp(src,TOKEN_ME))
995 *dest = ZGetSender();