home *** CD-ROM | disk | FTP | other *** search
/ Usenet 1994 October / usenetsourcesnewsgroupsinfomagicoctober1994disk2.iso / unix / volume28 / skill / part01 / argparse.c next >
Encoding:
C/C++ Source or Header  |  1994-07-15  |  7.2 KB  |  283 lines

  1. #ifndef lint
  2. static char rcsid[] = "$Header: argparse.c,v 1.7 1994/06/26 04:09:17 forys Exp $";
  3. #endif
  4.  
  5. /*
  6. **  This program may be freely redistributed for noncommercial purposes.
  7. **  This entire comment MUST remain intact.
  8. **
  9. **  Copyright 1994 by Jeff Forys (jeff@forys.cranbury.nj.us)
  10. */
  11.  
  12. #define    NO_AEXTERN
  13. #include "conf.h"
  14. #undef    NO_AEXTERN
  15.  
  16. #include <stdio.h>
  17. #include <ctype.h>
  18. #include <pwd.h>
  19.  
  20. /*
  21.  *  Define/initialize linked lists of user supplied things.
  22.  */
  23. tty_T    *TtyList = NULL;        /* list of ttys */
  24. uid_T    *UidList = NULL;        /* list of user id's */
  25. pid_T    *PidList = NULL;        /* list of process id's */
  26. cmd_T    *CmdList = NULL;        /* list of commands */
  27. int    TtyIndx = 0, UidIndx = 0, PidIndx = 0, CmdIndx = 0;
  28. int    Fflag = 0, Iflag = 0, Nflag = 0, Vflag = 0, Wflag = 0;
  29.  
  30. /*
  31.  * ArgParse(argc, argv)
  32.  *
  33.  * Destructively parse argv[] into appropriate global variables.
  34.  */
  35. void
  36. ArgParse(argc, argv)
  37.     int argc;
  38.     char *argv[];
  39. {
  40.     extern int atoi();
  41.     extern char *calloc();
  42.     struct passwd *pp;
  43.     struct stat st;
  44.     int argcnt = argc;    /* saved so ALLOC() knows max mem to allocate */
  45.     int haveno = 0;        /* set when we get a signal or priority */
  46.     int help, argloop;
  47.  
  48. #define    ALLOC(cnt,type,loc,nstr)                    \
  49.     if ((loc = (type) calloc((unsigned)cnt,sizeof(type))) == NULL)    \
  50.         Exceed(nstr)
  51.  
  52.     /*
  53.      * This is the main argument parsing loop.  At first glance
  54.      * this may look confusing.  We destructively move across
  55.      * arguments by incrementing that which "*argv" points to.
  56.      *
  57.      * Basically, for each argument, we first check if we have a
  58.      * flag (flags are preceded by a `-').  If so, then we enter
  59.      * the flag loop, processing each character until we reach
  60.      * end of string, or we hit a flag that requires special
  61.      * processing (i.e. any of "ltucp", "SIGNO", or "PRIORITY").
  62.      *
  63.      * Second, we check for the special case flag, "+PRIORITY".
  64.      * Finally, if we do not have a flag, we simply go on to the
  65.      * argument classification phase.  This is where we decide
  66.      * if a string represents a tty, a user name, a process id,
  67.      * or a command.
  68.      *
  69.      * If at any time something incomprehensible is unearthed,
  70.      * we call Usage(), who in turn calls exit().  Using "-l" also
  71.      * forces an immediate exit() (through ListSigs() or Usage()).
  72.      */
  73.     while (--argc > 0) {        /* for each argument */
  74.         help = 0;
  75.         if (**(++argv) == '-') {    /* found a flag */
  76.             do {
  77.             argloop = 0;
  78.             switch (*++(*argv)) {
  79.                 case 'l':
  80.                 if (Skill)
  81.                     ListSigs();
  82.                 else
  83.                     Usage(E_USAGE);
  84.                 /*NOTREACHED*/
  85.                 break;
  86.                 case 'f':    /* fast mode (if possible) */
  87.                 Fflag++;
  88.                 argloop++;    /* look for more flags */
  89.                 break;
  90.                 case 'i':    /* interactive mode */
  91.                 Iflag++;
  92.                 argloop++;    /* look for more flags */
  93.                 break;
  94.                 case 'v':    /* verbose mode */
  95.                 Vflag++;
  96.                 argloop++;    /* look for more flags */
  97.                 break;
  98.                 case 'w':    /* display warning messages */
  99.                 Wflag++;
  100.                 argloop++;    /* look for more flags */
  101.                 break;
  102.                 case 'n':    /* display pid's (do not act on them) */
  103.                 Nflag++;
  104.                 argloop++;    /* look for more flags */
  105.                 break;
  106.                 case 't':
  107.                 case 'u':
  108.                 case 'c':
  109.                 case 'p':
  110.                 help = **argv;
  111.                 break;
  112.                 default:
  113.                 /*
  114.                  * This code is kind of gnarly.  The user
  115.                  * may specify "-SIGNO" or "-PRIORITY"
  116.                  * (depending on what we are doing).  This
  117.                  * is further complicated by the fact that
  118.                  * SIGNO may be the signal *name*.  The
  119.                  * special case of "+PRIORITY" is handled
  120.                  * outside this switch() statement.
  121.                  */
  122.                 if (haveno)
  123.                     Usage(E_USAGE);
  124.  
  125.                 if (isdigit(**argv)) {
  126.                     if (Skill) {
  127.                         SigPri = atoi(*argv);
  128.                         if (SigPri < 0 || SigPri > NSig)
  129.                             Usage(E_SIGNO);
  130.                     } else {
  131.                         SigPri = -atoi(*argv);
  132.                         if (SigPri < PrioMin)
  133.                             SigPri = PrioMin;
  134.                     }
  135.                     haveno++;
  136.                 } else if (!Skill) {
  137.                     Usage(E_USAGE);
  138.                 } else for (SigPri=0; SigPri <= NSig; SigPri++)
  139.                     if (STREQU(SigMap[SigPri], *argv)) {
  140.                         haveno++;
  141.                         break;
  142.                     }
  143.                 if (!haveno) {
  144.                     fprintf(stderr, "%s: Unknown signal (%s); %s -l lists signals.\n",
  145.                             ProgName, *argv, ProgName);
  146.                     exit(EX_UERR);
  147.                 }
  148.                 break;
  149.             }
  150.             } while (argloop && *(*argv+1) != '\0');
  151.  
  152.             /*
  153.              * There can be no more flags in this string.  If the
  154.              * help variable was not set, we can short-circuit the
  155.              * remainder of the argument processing and move on to
  156.              * the next argument.
  157.              */
  158.             if (!help)            /* go to next arg */
  159.             continue;
  160.         } else if (!Skill && **argv == '+') {    /* "+priority" */
  161.             ++(*argv);
  162.             if (isdigit(**argv)) {
  163.                 SigPri = atoi(*argv);
  164.                 if (SigPri > PrioMax)
  165.                     SigPri = PrioMax;
  166.                 haveno++;
  167.                 continue;    /* go to next arg */
  168.             }
  169.             Usage(E_USAGE);    /* dopey priority: usage error */
  170.         }
  171.  
  172.         /*
  173.          * At this point, all we have left are ttys, user names,
  174.          * processes id's, and commands.  If we have `help', our
  175.          * job is easy; otherwise we have to hunt for things.
  176.          */
  177.         if (help && !(*++(*argv) || (--argc && *++argv)))
  178.             Usage(E_USAGE);    /* no arg following flag */
  179.  
  180.         if (!help || help == 't') {    /* tty? */
  181.             if (stat(*argv,&st)>=0&&(st.st_mode&S_IFMT)==S_IFCHR) {
  182.                 if (TtyIndx == 0)
  183.                     ALLOC(argcnt, tty_T *, TtyList, "tty");
  184.                 *(TtyList + TtyIndx++) = st.st_rdev;
  185.                 help = -1;
  186.             } else if (help)
  187.                 Not(*argv, "tty");
  188.         }
  189.  
  190.         if (!help || help == 'u') {    /* user name? */
  191.              if ((pp=getpwnam(*argv)) != NULL) {
  192.                 if (UidIndx == 0)
  193.                     ALLOC(argcnt, uid_T *, UidList, "user");
  194.                 *(UidList + UidIndx++) = pp->pw_uid;
  195.                 help = -1;
  196.             } else if (help)
  197.                 Not(*argv, "user name");
  198.         }
  199.  
  200.         if (!help || help == 'p') {    /* process id? */
  201.             if (isdigit(**argv)) {
  202.                 if (PidIndx == 0)
  203.                     ALLOC(argcnt, pid_T *, PidList, "pid");
  204.                 *(PidList + PidIndx++) = atoi(*argv);
  205.                 help = -1;
  206.             } else if (help)
  207.                 Not(*argv, "process id");
  208.         }
  209.  
  210.         if (help > -1) {        /* default: it's a command */
  211.             if (CmdIndx == 0)
  212.                 ALLOC(argcnt, cmd_T *, CmdList, "command");
  213.             *(CmdList + CmdIndx++) = *argv;
  214.         }
  215.     }
  216.  
  217.     if (TtyIndx == 0 && UidIndx == 0 && PidIndx == 0 && CmdIndx == 0)
  218.         Usage(E_USAGE);
  219.  
  220.     /*
  221.      *  If this is not the superuser and no specific users were
  222.      *  mentioned, we assume they only want to deal with their
  223.      *  own processes.  This cuts down on error messages since
  224.      *  the general user is not usually allowed to modify the
  225.      *  state of other users' processes.
  226.      */
  227.     if (UidIndx == 0 && MyUid != ROOTUID) {
  228.         ALLOC(1, uid_T *, UidList, "user");
  229.         *(UidList + UidIndx++) = MyUid;
  230.     }
  231. #undef    ALLOC
  232. }
  233.  
  234. /*
  235.  * ListSigs()
  236.  *
  237.  * Display a list of available signals and exit.
  238.  */
  239. void
  240. ListSigs()
  241. {
  242.     register int signo;
  243.     register int didprint = 0;
  244.  
  245.     for (signo = 1; signo <= NSig; signo++)
  246.         if (!isdigit(*SigMap[signo])) {
  247.             printf("%s%c", SigMap[signo],    /* 16 signals/line */
  248.                    (++didprint % 16) == 0? '\n': ' ');
  249.         }
  250.  
  251.     if ((didprint % 16) != 0)
  252.         (void) putc('\n', stdout);
  253.  
  254.     exit(EX_OKAY);
  255. }
  256.  
  257. /*
  258.  * Not(thought, this)
  259.  *
  260.  * The user incorrectly forced a type (e.g. "-u tty00").
  261.  * Display an error message and exit.
  262.  */
  263. void
  264. Not(thought, this)
  265.     char *thought, *this;
  266. {
  267.     fprintf(stderr, "%s: %s: not a %s\n", ProgName, thought, this);
  268.     exit(EX_UERR);
  269. }
  270.  
  271. /*
  272.  * Exceed(what)
  273.  *
  274.  * Ran out of memory allocating space for `what'.
  275.  */
  276. void
  277. Exceed(what)
  278.     char *what;
  279. {
  280.     fprintf(stderr, "%s: out of memory (can't alloc %s)\n", ProgName, what);
  281.     exit(EX_SERR);
  282. }
  283.