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

  1. #ifndef lint
  2. static char rcsid[] = "$Header: main.c,v 1.12 1994/07/13 20:31:16 forys Exp $";
  3. /*
  4.  * SCCS version release number is manually updated (for what(1), etc).
  5.  * If you use SCCS, please use last extension for version (e.g. "3.6.1.1").
  6.  */
  7. static char sccsid[] = 
  8.     "@(#)skill    3.6.1.0 (jeff@forys.cranbury.nj.us) 7/15/94";
  9. #endif
  10.  
  11. /*
  12. **  skill - send signals to processes by tty, user name, command or proc id.
  13. **  snice - change process priorities by tty, user name, command or proc id.
  14. **
  15. **  Version 3.6
  16. **
  17. **  This program may be freely redistributed for noncommercial purposes.
  18. **  This entire comment MUST remain intact.
  19. **
  20. **  Copyright 1994 by Jeff Forys (jeff@forys.cranbury.nj.us)
  21. */
  22.  
  23. #include "conf.h"
  24.  
  25. #include <stdio.h>
  26. #include <errno.h>
  27. #include <pwd.h>
  28.  
  29. /*
  30.  * Processes which could not be checked -- usually due to permission
  31.  * problems (SunOS 4.1, Dunix 3) -- are tallied in "MissedProcCnt".
  32.  * The machine dependent code is responsible for incrementing this;
  33.  * if it does not, we simply assume that all reasonable processes
  34.  * have been investigated (i.e. zombies are not reasonable).
  35.  */
  36. int MissedProcCnt = 0;
  37.  
  38. int
  39. main(argc, argv)
  40.     int argc;
  41.     char *argv[];
  42. {
  43.     extern char *SysErr(), *WhoIs();
  44.     register struct ProcInfo *proc;    /* process we are examining */
  45.     int reterr = -1;        /* -1:matchless, 0:okay, 1:error(s) */
  46.     register int i;
  47.  
  48.     /*
  49.      * Ignore SIGHUP (in case we kill our shell).
  50.      */
  51.     (void) signal(SIGHUP, SIG_IGN);
  52.  
  53.     /*
  54.      * Call machine-dependent initialization routine; besides setting
  55.      * up many global variables, this routine will change our working
  56.      * directory to where tty devs reside and may raise our priority.
  57.      *
  58.      * When machine-dependent initialization is complete, parse the
  59.      * argument list.
  60.      */
  61.     MdepInit(argv[0]);
  62.     ArgParse(argc, argv);
  63.  
  64.     /*
  65.      * Our friend ArgParse() has painfully categorized the arguments
  66.      * as ttys, users, commands, or pids. Loop through the list of
  67.      * currently running processes and find things that match.  In
  68.      * order for a match, we must have 1 item from each category
  69.      * (unless a category is empty).  When a match is found, the
  70.      * process is either sent signal `SigPri' (`Skill' == 1) or has
  71.      * it's priority is changed to `SigPri' (`Skill' == 0).
  72.      */
  73. #define    PID    proc->pi_pid        /* process id */
  74. #define    UID    proc->pi_uid        /* process owner */
  75. #define    TTY    proc->pi_tty        /* controlling tty */
  76. #define    CMD    proc->pi_cmd        /* command being executed */
  77. #define    FLAGS    proc->pi_flags        /* various flags (see conf.h) */
  78.  
  79.     while ((proc = GetProc()) != NULL) {
  80.         if (TtyIndx > 0) {
  81.             if ((FLAGS & PI_CTLTTY) == 0)
  82.                 continue;    /* no controlling tty */
  83.  
  84.             for (i = 0; i < TtyIndx && *(TtyList+i) != TTY; i++)
  85.                 ;
  86.             if (i == TtyIndx)    /* no matching tty */
  87.                 continue;
  88.         }
  89.  
  90.         if (UidIndx > 0) {
  91.             for (i = 0; i < UidIndx && *(UidList+i) != UID; i++)
  92.                 ;
  93.             if (i == UidIndx)    /* no matching uid */
  94.                 continue;
  95.         }
  96.  
  97.         if (PidIndx > 0) {
  98.             for (i = 0; i < PidIndx && *(PidList+i) != PID; i++)
  99.                 ;
  100.             if (i == PidIndx)    /* no matching pid */
  101.                 continue;
  102.         }
  103.  
  104.         if (CmdIndx > 0) {
  105.             for (i = 0; i < CmdIndx; i++) {
  106.                 if (STREQU(CMD, *(CmdList + i)))
  107.                     break;
  108.             }
  109.             if (i == CmdIndx)    /* no matching cmd  */
  110.                 continue;
  111.         }
  112.  
  113.         if (PID == MyPid || PID == 0)    /* ignore self */
  114.             continue;
  115.  
  116.         if (Iflag || (!Nflag && (FLAGS & PI_ASKUSR))) {    /* ask user */
  117.             static char yesno[10];
  118.  
  119.             (void) fseek(stdin, 0L, 0);
  120.  
  121.             fputs(ProgName, stdout);
  122.             if (Skill)
  123.                 printf(": send #%d a %s", PID, SigMap[SigPri]);
  124.             else
  125.                 printf(": renice #%d to %s%d", PID,
  126.                        (SigPri >= 0)? "+": "", SigPri);
  127.             printf(" (%s executing %s)? ", WhoIs(UID), CMD);
  128.             (void) fflush(stdout);
  129.  
  130.             if (fgets(yesno, 10, stdin) == NULL) {    /* EOF */
  131.                 (void) putc('\n', stdout);
  132.                 return(EX_OKAY);
  133.             }
  134.  
  135.             if (reterr < 0)
  136.                 reterr = 0;
  137.  
  138.             if (*yesno != 'y' && *yesno != 'Y')
  139.                 continue;
  140.         }
  141.  
  142.         if (FLAGS & PI_ZOMBIE) {    /* zombie process */
  143.             fprintf(stderr, "%d: zombie process\n", PID);
  144.             continue;
  145.         } else if (FLAGS & PI_SWEXIT) {    /* process is exiting */
  146.             fprintf(stderr, "%d: exiting process\n", PID);
  147.             continue;
  148.         }
  149.  
  150.         /*
  151.          * Finally do what we came here to do.  First, if
  152.          * we are only displaying process id's, then do so.
  153.          * If `Skill' is set, send signal `SigPri' to the
  154.          * process, otherwise, set priority of process to
  155.          * `SigPri'.  If either setpriority(2) or kill(2)
  156.          * return -1, display the system error message.
  157.          */
  158.         if (Nflag) {
  159.             printf("%d", (int)PID);
  160.             if (Vflag)
  161.                 printf(" (%s executing %s)", WhoIs(UID), CMD);
  162.             (void) putc('\n', stdout);
  163.             reterr = 0;
  164.         } else if (MdepAction(PID) < 0) {
  165.             fprintf(stderr, "%d: %s (%s executing %s)\n",
  166.                     PID, SysErr(), WhoIs(UID), CMD);
  167.             reterr = 1;
  168.         } else {            /* success! */
  169.             if (reterr < 0)
  170.                 reterr = 0;
  171.  
  172.             if (Vflag) {
  173.                 if (Skill)
  174.                     printf("> sent #%d a %s",
  175.                            PID, SigMap[SigPri]);
  176.                 else
  177.                     printf("> reniced #%d to %s%d", PID,
  178.                            (SigPri >= 0)? "+": "", SigPri);
  179.  
  180.                 if (!Iflag)
  181.                     printf(" (%s executing %s)",
  182.                            WhoIs(UID), CMD);
  183.                 (void) putc('\n', stdout);
  184.                 (void) fflush(stdout);
  185.             }
  186.         }
  187.     }
  188.  
  189.     if (reterr == -1) {
  190.         fprintf(stderr, "%s: no matching processes", ProgName);
  191.         if (MissedProcCnt > 0)
  192.             fprintf(stderr, " (but %d could not be checked)",
  193.                     MissedProcCnt);
  194.         (void) putc('\n', stderr);
  195.         reterr = 1;
  196.     }
  197.  
  198.     return(reterr? EX_UERR: EX_OKAY);
  199. }
  200.  
  201. /*
  202.  * Whois(uid)
  203.  *
  204.  * Given a user id, return its associated user name.
  205.  */
  206. char *
  207. WhoIs(uid)
  208.     uid_T uid;
  209. {
  210.     extern char *strncpy();            /* avoid <string/strings> war */
  211.     static char usrcache[64] = ROOTUSR;    /* user name */
  212.     static uid_T uidcache = ROOTUID;    /* user id */
  213.     struct passwd *pp;
  214.  
  215.     if (uid == ROOTUID)            /* be consistant w/ROOTUID */
  216.         return(ROOTUSR);
  217.  
  218.     if (uid == uidcache)            /* lucky break: same person */
  219.         return(usrcache);
  220.  
  221.     if ((pp=getpwuid((int) uid)) == NULL)    /* entry is gone? */
  222.         (void) sprintf(usrcache, "<uid:%d>", (int)uid);
  223.     else {
  224.         (void) strncpy(usrcache, pp->pw_name, 63);
  225.         usrcache[63] = '\0';
  226.     }
  227.  
  228.     uidcache = uid;
  229.     return(usrcache);
  230. }
  231.  
  232. /*
  233.  * Usage(error)
  234.  *
  235.  * The user typed something incorrect; explain their mistake (encoded
  236.  * in `error'), display usage information, and exit.
  237.  */
  238. void
  239. Usage(error)
  240.     int error;
  241. {
  242.     switch (error) {
  243.         case E_USAGE:
  244.         fprintf(stderr,
  245.                 "Usage: %s [%s] [-ivfwn] {<tty> <user> <pid> <cmd>}\n",
  246.                 ProgName, Skill? "-<signal>": "(+|-)<priority>");
  247.         break;
  248.         case E_PRIOR:    /* unused... remains for posterity? */
  249.         fprintf(stderr, "%s: no such priority (%d)\n",
  250.                 ProgName, SigPri);
  251.         break;
  252.         case E_SIGNO:
  253.         fprintf(stderr, "%s: bad signal number (%d)\n",
  254.                 ProgName, SigPri);
  255.         break;
  256.         default:
  257.         fprintf(stderr, "%s: internal error: Usage(%d)\n",
  258.                 ProgName, error);
  259.         break;
  260.     }
  261.     exit(EX_UERR);
  262.     /*NOTREACHED*/
  263. }
  264.  
  265. /*
  266.  * SysErr()
  267.  *
  268.  * Return the error message described by `errno'.
  269.  */
  270. char *
  271. SysErr()
  272. {
  273.     extern int errno;
  274. #if !defined(_FSTDIO) || defined(_ANSI_SOURCE) || defined(__STRICT_ANSI__)
  275.     extern char *sys_errlist[];
  276.     extern int sys_nerr;
  277. #endif
  278.  
  279.     return((errno > sys_nerr)? "unknown error": (char *)sys_errlist[errno]);
  280. }
  281.