/* This file is part of the Project Athena Zephyr Notification System. * It contains code for the "zctl" command. * * Created by: Robert French * * $Id$ * * Copyright (c) 1987,1988 by the Massachusetts Institute of Technology. * For copying and distribution information, see the file * "mit-copyright.h". */ #include #include #ifdef HAVE_SS #include #endif #include #include #include #ifndef lint static const char rcsid_zctl_c[] = "$Id$"; #endif #define SUBSATONCE 7 #define SUB 0 #define UNSUB 1 #define LIST 2 #define USERS_SUBS "/.zephyr.subs" #define OLD_SUBS "/.subscriptions" #define TOKEN_HOSTNAME "%host%" #define TOKEN_CANONNAME "%canon%" #define TOKEN_ME "%me%" #define TOKEN_WILD "*" #define ALL 0 #define UNSUBONLY 1 #define SUBONLY 2 #define ERR (-1) #define NOT_REMOVED 0 #define REMOVED 1 #ifdef HAVE_SS int sci_idx; #endif char subsname[BUFSIZ]; char ourhost[NS_MAXDNAME], ourhostcanon[NS_MAXDNAME]; #ifdef HAVE_SS extern ss_request_table zctl_cmds; #endif int purge_subs(register ZSubscription_t *, int); void add_file(short, ZSubscription_t *, int); void del_file(short, ZSubscription_t *, int); void fix_macros(ZSubscription_t *, ZSubscription_t *, int); void fix_macros2(char *, char **); int make_exist(char *); char *whoami; #ifndef HAVE_SS static void run_command(int, char *[]); static void show_commands(int, char *[]); #endif /* Prototype all of the commands. * These really should be in a header also visible to zctl_cmds.c, * but mk_cmds doesn't make that easy. */ void cancel_subs(int argc, char *argv[]); void current(int argc, char *argv[]); void do_hide(int argc, char *argv[]); void do_punt(int argc, char *argv[]); void flush_locations(int argc, char *argv[]); void hm_control(int argc, char *argv[]); void list_punts(int argc, char *argv[]); void load_subs(int argc, char *argv[]); void set_file(int argc, char *argv[]); void set_var(int argc, char *argv[]); void show_var(int argc, char *argv[]); void sub_file(int argc, char *argv[]); void subscribe(int argc, char *argv[]); void unset_var(int argc, char *argv[]); void wgc_control(int argc, char *argv[]); int main(int argc, char *argv[]) { struct passwd *pwd; struct hostent *hent; char ssline[BUFSIZ],oldsubsname[BUFSIZ],*envptr,*tty = NULL; int retval,code,i; #ifdef HAVE_SYS_UTSNAME struct utsname name; #endif whoami = argv[0]; if ((retval = ZInitialize()) != ZERR_NONE) { com_err(argv[0],retval,"while initializing"); exit (1); } /* Set hostname and tty for locations. If we support X, use the * DISPLAY environment variable for the tty name. */ #ifndef X_DISPLAY_MISSING tty = getenv("DISPLAY"); #endif if ((retval = ZInitLocationInfo(NULL, tty)) != ZERR_NONE) com_err(argv[0], retval, "initializing location information"); envptr = getenv("ZEPHYR_SUBS"); if (envptr) strcpy(subsname,envptr); else { envptr = getenv("HOME"); if (envptr) strcpy(subsname,envptr); else { if (!(pwd = getpwuid((int) getuid()))) { fprintf(stderr,"Who are you?\n"); exit (1); } strcpy(subsname,pwd->pw_dir); } strcpy(oldsubsname,subsname); strcat(oldsubsname,OLD_SUBS); strcat(subsname,USERS_SUBS); if (!access(oldsubsname,F_OK) && access(subsname, F_OK)) { /* only if old one exists and new one does not exist */ 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"); if (rename(oldsubsname,subsname)) com_err(argv[0], errno, "renaming .subscriptions"); } } #ifdef HAVE_SYS_UTSNAME uname(&name); strcpy(ourhost, name.nodename); #else if (gethostname(ourhost, sizeof(ourhost)) == -1) { com_err(argv[0],errno,"while getting host name"); exit (1); } #endif if (!(hent = gethostbyname(ourhost))) { fprintf(stderr,"%s: Can't resolve hostname %s; %s may be " "wrong in subscriptions\n",argv[0],ourhost, TOKEN_CANONNAME); strncpy(ourhostcanon,ourhost,sizeof(ourhostcanon)-1); } else strncpy(ourhostcanon,hent->h_name,sizeof(ourhostcanon)-1); #ifdef HAVE_SS sci_idx = ss_create_invocation("zctl","",0,&zctl_cmds,&code); if (code) { ss_perror(sci_idx,code,"while creating invocation"); exit(1); #else if (argc <= 1) { printf("ZCTL $Revision$ (Protocol %s%d.%d)\nType '%s help' for a list of subcommands.\n\n", ZVERSIONHDR, ZVERSIONMAJOR,ZVERSIONMINOR, argv[0]); exit(0); #endif } #ifdef HAVE_SS if (argc > 1) { *ssline = '\0'; for (i=1;i 2) { fprintf(stderr,"Usage: %s filename\n",argv[0]); return; } if (argc == 1) printf("Current file: %s\n",subsname); else (void) strcpy(subsname,argv[1]); } void flush_locations(int argc, char *argv[]) { int retval; if (argc > 2) { fprintf(stderr,"Usage: %s [user]\n",argv[0]); return; } if (argc > 1) retval = ZFlushUserLocations(argv[1]); else retval = ZFlushMyLocations(); if (retval != ZERR_NONE) com_err(whoami, retval, "while flushing locations"); } void wgc_control(int argc, char *argv[]) { int retval; short newport; struct sockaddr_in newsin; ZNotice_t notice; newsin = ZGetDestAddr(); if (argc > 1) { fprintf(stderr,"Usage: %s\n",argv[0]); return; } if ((newport = ZGetWGPort()) == -1) { com_err(whoami, errno, "while getting WindowGram port"); return; } newsin.sin_port = (u_short) newport; if ((retval = ZSetDestAddr(&newsin)) != ZERR_NONE) { com_err(whoami, retval, "while setting destination address"); return; } (void) memset((char *)¬ice, 0, sizeof(notice)); notice.z_kind = UNSAFE; notice.z_port = 0; notice.z_class = WG_CTL_CLASS; notice.z_class_inst = WG_CTL_USER; if (!strcmp(argv[0],"wg_read")) notice.z_opcode = USER_REREAD; if (!strcmp(argv[0],"wg_shutdown")) notice.z_opcode = USER_SHUTDOWN; if (!strcmp(argv[0],"wg_startup")) notice.z_opcode = USER_STARTUP; if (!strcmp(argv[0],"wg_exit")) notice.z_opcode = USER_EXIT; if (!notice.z_opcode) { fprintf(stderr, "unknown WindowGram client control command %s\n", argv[0]); return; } notice.z_sender = 0; notice.z_recipient = ""; notice.z_default_format = ""; notice.z_message_len = 0; if ((retval = ZSendNotice(¬ice,ZNOAUTH)) != ZERR_NONE) com_err(whoami, retval, "while sending notice"); if ((retval = ZInitialize()) != ZERR_NONE) com_err(whoami, retval, "while reinitializing"); } void hm_control(int argc, char *argv[]) { int retval; ZNotice_t notice; if (argc > 1) { fprintf(stderr,"Usage: %s\n",argv[0]); return; } (void) memset((char *)¬ice, 0, sizeof(notice)); notice.z_kind = HMCTL; notice.z_port = 0; notice.z_class = HM_CTL_CLASS; notice.z_class_inst = HM_CTL_CLIENT; if (!strcmp(argv[0],"hm_flush")) notice.z_opcode = CLIENT_FLUSH; if (!strcmp(argv[0],"new_server")) notice.z_opcode = CLIENT_NEW_SERVER; if (!notice.z_opcode) { fprintf(stderr, "unknown HostManager control command %s\n", argv[0]); return; } notice.z_sender = 0; notice.z_recipient = ""; notice.z_default_format = ""; notice.z_message_len = 0; if ((retval = ZSendNotice(¬ice,ZNOAUTH)) != ZERR_NONE) com_err(whoami, retval, "while sending notice"); } void show_var(int argc, char *argv[]) { int i; char *value; if (argc < 2) { fprintf(stderr,"Usage: %s ...\n",argv[0]); return; } for (i=1;i [value]\n", argv[0]); return; } setting_exp = 0; if (!strcasecmp(argv[1],"exposure")) { setting_exp = 1; if (argc != 3) { fprintf(stderr,"An exposure setting must be specified.\n"); return; } exp_level = (char *)0; if (!strcasecmp(argv[2],EXPOSE_NONE)) exp_level = EXPOSE_NONE; if (!strcasecmp(argv[2],EXPOSE_OPSTAFF)) exp_level = EXPOSE_OPSTAFF; if (!strcasecmp(argv[2],EXPOSE_REALMVIS)) exp_level = EXPOSE_REALMVIS; if (!strcasecmp(argv[2],EXPOSE_REALMANN)) exp_level = EXPOSE_REALMANN; if (!strcasecmp(argv[2],EXPOSE_NETVIS)) exp_level = EXPOSE_NETVIS; if (!strcasecmp(argv[2],EXPOSE_NETANN)) exp_level = EXPOSE_NETANN; if (!exp_level) { fprintf(stderr,"The exposure setting must be one of:\n"); fprintf(stderr,"%s, %s, %s, %s, %s, %s.\n", EXPOSE_NONE, EXPOSE_OPSTAFF, EXPOSE_REALMVIS, EXPOSE_REALMANN, EXPOSE_NETVIS, EXPOSE_NETANN); return; } } if (argc == 2) retval = ZSetVariable(argv[1],""); else { (void) strcpy(varcat,argv[2]); for (i=3;i [ ... ]\n", argv[0]); return; } for (i=1;i 4 || argc < 3) { fprintf(stderr,"Usage: %s class instance [*]\n",argv[0]); return; } sub.zsub_class = argv[1]; sub.zsub_classinst = argv[2]; sub.zsub_recipient = (argc == 3)?ZGetSender():argv[3]; fix_macros(&sub,&sub2,1); if ((wgport = ZGetWGPort()) == -1) { com_err(whoami, errno, "while finding WindowGram port"); return; } retval = (*argv[0] == 's') ? ZSubscribeToSansDefaults(&sub2,1,(u_short)wgport) : ZUnsubscribeTo(&sub2,1,(u_short)wgport); if (retval != ZERR_NONE) com_err(whoami, retval, "while subscribing"); } void sub_file(int argc, char *argv[]) { ZSubscription_t sub; short wgport; if (argc > 4 || argc < 3) { fprintf(stderr,"Usage: %s class instance [*]\n",argv[0]); return; } if (argv[1][0] == '!') { com_err(whoami, 0, (!strcmp(argv[0],"add_unsubscription") || !strcmp(argv[0],"add_un") || !strcmp(argv[0],"delete_unsubscription") || !strcmp(argv[0],"del_un")) ? "Do not use `!' as the first character of a class.\n\tIt is automatically added before modifying the subscription file." : "Do not use `!' as the first character of a class.\n\tIt is reserved for internal use with un-subscriptions."); return; } sub.zsub_class = argv[1]; sub.zsub_classinst = argv[2]; sub.zsub_recipient = (argc == 3)?TOKEN_ME:argv[3]; if (make_exist(subsname)) return; if ((wgport = ZGetWGPort()) == -1) { com_err(whoami, errno, "while finding WindowGram port"); return; } if (!strcmp(argv[0],"add")) add_file(wgport,&sub,0); else if (!strcmp(argv[0],"add_unsubscription") || !strcmp(argv[0],"add_un")) add_file(wgport,&sub,1); else if (!strcmp(argv[0],"delete") || !strcmp(argv[0],"del") || !strcmp(argv[0],"dl")) del_file(wgport,&sub,0); else if (!strcmp(argv[0],"delete_unsubscription") || !strcmp(argv[0],"del_un")) { del_file(wgport,&sub,1); } else com_err(whoami, 0, "unknown command name"); return; } void add_file(short wgport, ZSubscription_t *subs, int unsub) { FILE *fp; ZSubscription_t sub2; Code_t retval; (void) purge_subs(subs,ALL); /* remove copies in the subs file */ if (!(fp = fopen(subsname,"a"))) { com_err(whoami, errno, "while opening %s for append", subsname); return; } fprintf(fp,"%s%s,%s,%s\n", unsub ? "!" : "", subs->zsub_class, subs->zsub_classinst, subs->zsub_recipient); if (fclose(fp) == EOF) { com_err(whoami, errno, "while closing %s", subsname); return; } fix_macros(subs,&sub2,1); retval = (unsub ? ZUnsubscribeTo(&sub2,1,(u_short)wgport) : ZSubscribeToSansDefaults(&sub2,1,(u_short)wgport)); if (retval) com_err(whoami, retval, unsub ? "while unsubscribing" : "while subscribing"); return; } void del_file(short wgport, register ZSubscription_t *subs, int unsub) { ZSubscription_t sub2; int retval; retval = purge_subs(subs, unsub ? UNSUBONLY : SUBONLY); if (retval == ERR) return; if (retval == NOT_REMOVED) fprintf(stderr, "Couldn't find %sclass %s instance %s recipient %s in\n\tfile %s\n", unsub ? "un-subscription " : "", subs->zsub_class, subs->zsub_classinst, subs->zsub_recipient, subsname); fix_macros(subs,&sub2,1); if ((retval = ZUnsubscribeTo(&sub2,1,(u_short)wgport)) != ZERR_NONE) com_err(whoami, retval, "while unsubscribing"); return; } int purge_subs(register ZSubscription_t *subs, int which) { FILE *fp,*fpout; char subline[BUFSIZ]; char backup[BUFSIZ],ourline[BUFSIZ]; int delflag = NOT_REMOVED; int keep = 0; switch (which) { case SUBONLY: case UNSUBONLY: case ALL: break; default: com_err(whoami, 0, "internal error in purge_subs"); return(ERR); } (void) sprintf(ourline,"%s,%s,%s", subs->zsub_class, subs->zsub_classinst, subs->zsub_recipient); if (!(fp = fopen(subsname,"r"))) { com_err(whoami, errno, "while opening %s for read", subsname); return(ERR); } (void) strcpy(backup, subsname); (void) strcat(backup, ".temp"); (void) unlink(backup); if (!(fpout = fopen(backup,"w"))) { com_err(whoami, errno, "while opening %s for writing", backup); (void) fclose(fp); return(ERR); } for (;;) { if (!fgets(subline,sizeof subline,fp)) break; if (*subline) subline[strlen(subline)-1] = '\0'; /* nuke newline */ switch (which) { case SUBONLY: keep = strcmp(subline,ourline); break; case UNSUBONLY: keep = (*subline != '!' || strcmp(subline+1,ourline)); break; case ALL: keep = (strcmp(subline,ourline) && (*subline != '!' || strcmp(subline+1, ourline))); break; } if (keep) { fputs(subline, fpout); if (ferror(fpout) || (fputc('\n', fpout) == EOF)) { com_err(whoami, errno, "while writing to %s", backup); } } else delflag = REMOVED; } (void) fclose(fp); /* open read-only, ignore errs */ if (fclose(fpout) == EOF) { com_err(whoami, errno, "while closing %s", backup); return(ERR); } if (rename(backup,subsname) == -1) { com_err(whoami, errno, "while renaming %s to %s\n", backup, subsname); return(ERR); } return(delflag); } void load_subs(int argc, char *argv[]) { ZSubscription_t subs[SUBSATONCE],subs2[SUBSATONCE],unsubs[SUBSATONCE]; #ifdef CMU_ZCTL_PUNT ZSubscription_t punts[SUBSATONCE]; int pind; #endif FILE *fp; int ind,unind,lineno,i,retval,type; short wgport = 0; char *comma,*comma2,*file,subline[BUFSIZ]; if (argc > 2) { fprintf(stderr,"Usage: %s [file]\n",argv[0]); return; } if (*argv[0] == 'u') type = UNSUB; else if (!strcmp(argv[0],"list") || !strcmp(argv[0],"ls")) type = LIST; else type = SUB; if (type != LIST) if ((wgport = ZGetWGPort()) == -1) { com_err(whoami, errno, "while finding WindowGram port"); return; } file = (argc == 1) ? subsname : argv[1]; fp = fopen(file,"r"); if (fp == NULL) { com_err(whoami, errno, "while loading subscription file"); return; } #ifdef CMU_ZCTL_PUNT pind = #endif ind = unind = 0; lineno = 1; for (;;lineno++) { if (!fgets(subline,sizeof subline,fp)) break; if (*subline == '#' || !*subline) continue; subline[strlen(subline)-1] = '\0'; /* nuke newline */ comma = strchr(subline,','); if (comma) comma2 = strchr(comma+1,','); else comma2 = 0; if (!comma || !comma2) { fprintf(stderr, "Malformed subscription at line %d of %s:\n%s\n", lineno,file,subline); continue; } *comma = '\0'; *comma2 = '\0'; if (type == LIST) { if (*subline == '!') printf("(Un-subscription) Class %s instance %s recipient %s\n", subline+1, comma+1, comma2+1); #ifdef CMU_ZCTL_PUNT else if(*subline == '-') printf("(Punted) Class %s instance %s recipient %s\n", subline+1, comma+1, comma2+1); #endif else printf("Class %s instance %s recipient %s\n", subline, comma+1, comma2+1); continue; } if (*subline == '!') { /* an un-subscription */ /* if we are explicitly un-subscribing to the contents of a subscription file, ignore any un-subscriptions in that file */ if (type == UNSUB) continue; unsubs[unind].zsub_class = (char *)malloc((unsigned)(strlen(subline))); /* XXX check malloc return */ /* skip the leading '!' */ (void) strcpy(unsubs[unind].zsub_class,subline+1); unsubs[unind].zsub_classinst = (char *)malloc((unsigned)(strlen(comma+1)+1)); /* XXX check malloc return */ (void) strcpy(unsubs[unind].zsub_classinst,comma+1); unsubs[unind].zsub_recipient = (char *)malloc((unsigned)(strlen(comma2+1)+1)); /* XXX check malloc return */ (void) strcpy(unsubs[unind].zsub_recipient,comma2+1); unind++; } else #ifdef CMU_ZCTL_PUNT if (*subline == '-') { /* a punt */ if (type == UNSUB) continue; punts[pind].zsub_class = (char *)malloc((unsigned)(strlen(subline)+1)); /* XXX check malloc return */ (void) strcpy(punts[pind].zsub_class,subline+1); punts[pind].zsub_classinst = (char *)malloc((unsigned)(strlen(comma+1)+1)); /* XXX check malloc return */ (void) strcpy(punts[pind].zsub_classinst,comma+1); punts[pind].zsub_recipient = (char *)malloc((unsigned)(strlen(comma2+1)+1)); /* XXX check malloc return */ (void) strcpy(punts[pind].zsub_recipient,comma2+1); pind++; } else #endif { subs[ind].zsub_class = (char *)malloc((unsigned)(strlen(subline)+1)); /* XXX check malloc return */ (void) strcpy(subs[ind].zsub_class,subline); subs[ind].zsub_classinst = (char *)malloc((unsigned)(strlen(comma+1)+1)); /* XXX check malloc return */ (void) strcpy(subs[ind].zsub_classinst,comma+1); subs[ind].zsub_recipient = (char *)malloc((unsigned)(strlen(comma2+1)+1)); /* XXX check malloc return */ (void) strcpy(subs[ind].zsub_recipient,comma2+1); ind++; } #ifdef CMU_ZCTL_PUNT if (pind == SUBSATONCE) { fix_macros(punts,subs2,pind); if ((retval = ZPunt(subs2,pind,(u_short)wgport) != ZERR_NONE)) { com_err(whoami, retval, "while punting"); goto cleanup; } for (i=0;i\n", punt ? "Punting" : "Unpunting", class, inst, *recip ? recip : "*"); memset((char *) ¬ice, 0, sizeof(ZNotice_t)); notice.z_kind = UNSAFE; notice.z_class = WG_CTL_CLASS; notice.z_class_inst = WG_CTL_USER; notice.z_recipient = ""; notice.z_default_format = ""; notice.z_opcode = (punt) ? "SUPPRESS" : "UNSUPPRESS"; notice.z_port = 0; notice.z_message = msg; notice.z_message_len = strlen(class)+strlen(inst)+strlen(recip)+3; if ((retval = ZSendNotice(¬ice,ZNOAUTH)) != ZERR_NONE) fprintf(stderr,"%s: while sending notice\n",whoami); free(msg); ZClosePort(); #endif return; } void list_punts(int argc, char *argv[]) { #ifdef CMU_ZCTL_PUNT ZNotice_t notice; int retval; struct sockaddr_in old, to, from; u_short ourport, zwgcport; char *msg; ourport=0; retval = ZOpenPort(&ourport); if(retval != ZERR_NONE) { com_err("zctl", retval, "while opening Zephyr port."); return; } old = ZGetDestAddr(); to = old; if ((zwgcport = ZGetWGPort()) == (u_short)-1) { fprintf(stderr, "zctl: Can't find windowgram port\n"); return; } to.sin_port = (u_short) zwgcport; if ((retval = ZSetDestAddr(&to)) != ZERR_NONE) { com_err("zctl",retval,"while setting destination address"); return; } memset((char *) ¬ice, 0, sizeof(ZNotice_t)); notice.z_kind = UNSAFE; notice.z_class = WG_CTL_CLASS; notice.z_class_inst = WG_CTL_USER; notice.z_recipient = ""; notice.z_default_format = ""; notice.z_opcode = "LIST-SUPPRESSED" /*USER_LIST_SUPPRESSED*/; notice.z_port = ourport; notice.z_message = NULL; notice.z_message_len = 0; if ((retval = ZSendNotice(¬ice,ZNOAUTH)) != ZERR_NONE) com_err("zctl",retval,"while sending notice"); if ((retval = ZReceiveNotice(¬ice,&from)) != ZERR_NONE) com_err("zctl",retval,"while receiving ack"); (void) ZFreeNotice(¬ice); if ((retval = ZReceiveNotice(¬ice,&from)) != ZERR_NONE) com_err("zctl",retval,"while receiving notice"); notice.z_auth = ZCheckAuthentication(¬ice, &from); if ((retval = ZSetDestAddr(&old)) != ZERR_NONE) { com_err("zctl",retval,"while resetting destination address"); return; } msg = (char *) malloc((notice.z_message_len+1) * sizeof(char)); (void) strncpy(msg,notice.z_message, notice.z_message_len); msg[notice.z_message_len]=(char)0; printf("%s", msg); (void) free(msg); (void) ZFreeNotice(¬ice); (void) ZClosePort(); #endif /* CMU_ZCTL_PUNT */ return; } #ifndef HAVE_SS #define MAXNAMES 3 static const struct { void (*fptr)(int, char *[]); const char *doc; const char *names[MAXNAMES]; } commands[] = { /* { set_file, "Set default subscriptions file.", "file" }, */ { cancel_subs, "Cancel all subscriptions.", { "cancel" } }, { load_subs, "Subscribe to a subscriptions file.", { "load", "ld" } }, { load_subs, "Unsubscribe to a subscriptions file.", { "unload", "unld" } }, { load_subs, "List a subscriptions file.", { "list", "ls" } }, { subscribe, "Subscribe to a class/class instance.", { "subscribe", "sub" } }, { subscribe, "Unsubscribe to a class/class instance.", { "unsubscribe", "unsub" } }, { sub_file, "Subscribe and add to subscriptions file.", { "add" } }, { sub_file, "Unsubscribe and add to subscriptions file\nas un-subscription.", { "add_unsubscription", "add_un" } }, { sub_file, "Unsubscribe and delete subscription from\nsubscriptions file.", { "delete", "del", "dl" } }, { sub_file, "Delete un-subscription from subscriptions file.", { "delete_unsubscription", "del_un" } }, { current, "Retrieve current subscriptions.", { "retrieve", "ret" } }, { current, "Retrieve system-wide default subscriptions.", { "defaults", "defs" } }, { current, "Save current subscriptions (replacing existing file).", { "save" } }, { show_var, "Show a variable's value.", { "show" } }, { set_var, "Set a variable's value.", { "set" } }, { unset_var, "Delete a variable's value.", { "unset" } }, { wgc_control, "Get the WindowGram to reread its description file.", { "wg_read" } }, { wgc_control, "Tell the WindowGram not to react to incoming notices.", { "wg_shutdown" } }, { wgc_control, "Tell the WindowGram to react to incoming notices.", { "wg_startup" } }, { wgc_control, "Tell the WindowGram to exit completely.", { "wg_exit" } }, { hm_control, "Tell the server to flush information about this host.", { "hm_flush" } }, { hm_control, "Tell the HostManager to find a new server.", { "new_server" } }, { flush_locations, "Flush all location information.", { "flush_locs" } }, { do_hide, "Hide your location.", { "hide" } }, { do_hide, "Show (un-hide) your location.", { "unhide" } }, { show_commands, "List available commands.", { "help", "?" } }, #ifdef CMU_ZCTL_PUNT { do_punt, "Ignore specified messages.", { "punt" } }, { do_punt, "Stop ignoring specified messages.", { "unpunt" } }, { list_punts, "List current messages to ignore.", { "list_punts", "lp" } }, #endif }; #define MAXCOMMAND (sizeof(commands)/sizeof(commands[0])) #define DOCCOL 25 static void show_commands(int argc, char *argv[]) { int i, j, col, len; const char *str, *s; printf("Available zctl requests:\n\n"); for (i = 0; i < MAXCOMMAND; i++) { col = 0; printf("%s", commands[i].names[0]); col += strlen(commands[i].names[0]); for (j = 1; j < MAXNAMES && commands[i].names[j]; j++) { printf(", %s", commands[i].names[j]); col += 2 + strlen(commands[i].names[j]); } if (col > DOCCOL - 2) { printf("\n"); col = 0; } printf("%*s", DOCCOL - col, ""); str = commands[i].doc; while ((s = strchr(str, '\n')) != NULL) { printf("%.*s\n%*s", (int)(s-str), str, DOCCOL, ""); str = s+1; } printf("%s\n", str); } } static void run_command(int argc, char *argv[]) { int i, j; for (i = 0; i < MAXCOMMAND; i++) for (j = 0; j < MAXNAMES; j++) if (commands[i].names[j] != NULL && !strcmp(commands[i].names[j], argv[0])) { commands[i].fptr(argc, argv); return; } com_err(whoami, 0, "Unknown command '%s'; use '%s help' for a list of commands.", argv[0], whoami); exit(1); } #endif