home *** CD-ROM | disk | FTP | other *** search
- #ifndef lint
- static char rcsid[] = "$Header: argparse.c,v 1.7 1994/06/26 04:09:17 forys Exp $";
- #endif
-
- /*
- ** This program may be freely redistributed for noncommercial purposes.
- ** This entire comment MUST remain intact.
- **
- ** Copyright 1994 by Jeff Forys (jeff@forys.cranbury.nj.us)
- */
-
- #define NO_AEXTERN
- #include "conf.h"
- #undef NO_AEXTERN
-
- #include <stdio.h>
- #include <ctype.h>
- #include <pwd.h>
-
- /*
- * Define/initialize linked lists of user supplied things.
- */
- tty_T *TtyList = NULL; /* list of ttys */
- uid_T *UidList = NULL; /* list of user id's */
- pid_T *PidList = NULL; /* list of process id's */
- cmd_T *CmdList = NULL; /* list of commands */
- int TtyIndx = 0, UidIndx = 0, PidIndx = 0, CmdIndx = 0;
- int Fflag = 0, Iflag = 0, Nflag = 0, Vflag = 0, Wflag = 0;
-
- /*
- * ArgParse(argc, argv)
- *
- * Destructively parse argv[] into appropriate global variables.
- */
- void
- ArgParse(argc, argv)
- int argc;
- char *argv[];
- {
- extern int atoi();
- extern char *calloc();
- struct passwd *pp;
- struct stat st;
- int argcnt = argc; /* saved so ALLOC() knows max mem to allocate */
- int haveno = 0; /* set when we get a signal or priority */
- int help, argloop;
-
- #define ALLOC(cnt,type,loc,nstr) \
- if ((loc = (type) calloc((unsigned)cnt,sizeof(type))) == NULL) \
- Exceed(nstr)
-
- /*
- * This is the main argument parsing loop. At first glance
- * this may look confusing. We destructively move across
- * arguments by incrementing that which "*argv" points to.
- *
- * Basically, for each argument, we first check if we have a
- * flag (flags are preceded by a `-'). If so, then we enter
- * the flag loop, processing each character until we reach
- * end of string, or we hit a flag that requires special
- * processing (i.e. any of "ltucp", "SIGNO", or "PRIORITY").
- *
- * Second, we check for the special case flag, "+PRIORITY".
- * Finally, if we do not have a flag, we simply go on to the
- * argument classification phase. This is where we decide
- * if a string represents a tty, a user name, a process id,
- * or a command.
- *
- * If at any time something incomprehensible is unearthed,
- * we call Usage(), who in turn calls exit(). Using "-l" also
- * forces an immediate exit() (through ListSigs() or Usage()).
- */
- while (--argc > 0) { /* for each argument */
- help = 0;
- if (**(++argv) == '-') { /* found a flag */
- do {
- argloop = 0;
- switch (*++(*argv)) {
- case 'l':
- if (Skill)
- ListSigs();
- else
- Usage(E_USAGE);
- /*NOTREACHED*/
- break;
- case 'f': /* fast mode (if possible) */
- Fflag++;
- argloop++; /* look for more flags */
- break;
- case 'i': /* interactive mode */
- Iflag++;
- argloop++; /* look for more flags */
- break;
- case 'v': /* verbose mode */
- Vflag++;
- argloop++; /* look for more flags */
- break;
- case 'w': /* display warning messages */
- Wflag++;
- argloop++; /* look for more flags */
- break;
- case 'n': /* display pid's (do not act on them) */
- Nflag++;
- argloop++; /* look for more flags */
- break;
- case 't':
- case 'u':
- case 'c':
- case 'p':
- help = **argv;
- break;
- default:
- /*
- * This code is kind of gnarly. The user
- * may specify "-SIGNO" or "-PRIORITY"
- * (depending on what we are doing). This
- * is further complicated by the fact that
- * SIGNO may be the signal *name*. The
- * special case of "+PRIORITY" is handled
- * outside this switch() statement.
- */
- if (haveno)
- Usage(E_USAGE);
-
- if (isdigit(**argv)) {
- if (Skill) {
- SigPri = atoi(*argv);
- if (SigPri < 0 || SigPri > NSig)
- Usage(E_SIGNO);
- } else {
- SigPri = -atoi(*argv);
- if (SigPri < PrioMin)
- SigPri = PrioMin;
- }
- haveno++;
- } else if (!Skill) {
- Usage(E_USAGE);
- } else for (SigPri=0; SigPri <= NSig; SigPri++)
- if (STREQU(SigMap[SigPri], *argv)) {
- haveno++;
- break;
- }
- if (!haveno) {
- fprintf(stderr, "%s: Unknown signal (%s); %s -l lists signals.\n",
- ProgName, *argv, ProgName);
- exit(EX_UERR);
- }
- break;
- }
- } while (argloop && *(*argv+1) != '\0');
-
- /*
- * There can be no more flags in this string. If the
- * help variable was not set, we can short-circuit the
- * remainder of the argument processing and move on to
- * the next argument.
- */
- if (!help) /* go to next arg */
- continue;
- } else if (!Skill && **argv == '+') { /* "+priority" */
- ++(*argv);
- if (isdigit(**argv)) {
- SigPri = atoi(*argv);
- if (SigPri > PrioMax)
- SigPri = PrioMax;
- haveno++;
- continue; /* go to next arg */
- }
- Usage(E_USAGE); /* dopey priority: usage error */
- }
-
- /*
- * At this point, all we have left are ttys, user names,
- * processes id's, and commands. If we have `help', our
- * job is easy; otherwise we have to hunt for things.
- */
- if (help && !(*++(*argv) || (--argc && *++argv)))
- Usage(E_USAGE); /* no arg following flag */
-
- if (!help || help == 't') { /* tty? */
- if (stat(*argv,&st)>=0&&(st.st_mode&S_IFMT)==S_IFCHR) {
- if (TtyIndx == 0)
- ALLOC(argcnt, tty_T *, TtyList, "tty");
- *(TtyList + TtyIndx++) = st.st_rdev;
- help = -1;
- } else if (help)
- Not(*argv, "tty");
- }
-
- if (!help || help == 'u') { /* user name? */
- if ((pp=getpwnam(*argv)) != NULL) {
- if (UidIndx == 0)
- ALLOC(argcnt, uid_T *, UidList, "user");
- *(UidList + UidIndx++) = pp->pw_uid;
- help = -1;
- } else if (help)
- Not(*argv, "user name");
- }
-
- if (!help || help == 'p') { /* process id? */
- if (isdigit(**argv)) {
- if (PidIndx == 0)
- ALLOC(argcnt, pid_T *, PidList, "pid");
- *(PidList + PidIndx++) = atoi(*argv);
- help = -1;
- } else if (help)
- Not(*argv, "process id");
- }
-
- if (help > -1) { /* default: it's a command */
- if (CmdIndx == 0)
- ALLOC(argcnt, cmd_T *, CmdList, "command");
- *(CmdList + CmdIndx++) = *argv;
- }
- }
-
- if (TtyIndx == 0 && UidIndx == 0 && PidIndx == 0 && CmdIndx == 0)
- Usage(E_USAGE);
-
- /*
- * If this is not the superuser and no specific users were
- * mentioned, we assume they only want to deal with their
- * own processes. This cuts down on error messages since
- * the general user is not usually allowed to modify the
- * state of other users' processes.
- */
- if (UidIndx == 0 && MyUid != ROOTUID) {
- ALLOC(1, uid_T *, UidList, "user");
- *(UidList + UidIndx++) = MyUid;
- }
- #undef ALLOC
- }
-
- /*
- * ListSigs()
- *
- * Display a list of available signals and exit.
- */
- void
- ListSigs()
- {
- register int signo;
- register int didprint = 0;
-
- for (signo = 1; signo <= NSig; signo++)
- if (!isdigit(*SigMap[signo])) {
- printf("%s%c", SigMap[signo], /* 16 signals/line */
- (++didprint % 16) == 0? '\n': ' ');
- }
-
- if ((didprint % 16) != 0)
- (void) putc('\n', stdout);
-
- exit(EX_OKAY);
- }
-
- /*
- * Not(thought, this)
- *
- * The user incorrectly forced a type (e.g. "-u tty00").
- * Display an error message and exit.
- */
- void
- Not(thought, this)
- char *thought, *this;
- {
- fprintf(stderr, "%s: %s: not a %s\n", ProgName, thought, this);
- exit(EX_UERR);
- }
-
- /*
- * Exceed(what)
- *
- * Ran out of memory allocating space for `what'.
- */
- void
- Exceed(what)
- char *what;
- {
- fprintf(stderr, "%s: out of memory (can't alloc %s)\n", ProgName, what);
- exit(EX_SERR);
- }
-