[BACK]Return to commands.c CVS log [TXT][DIR] Up to [local] / src / usr.bin / top

Diff for /src/usr.bin/top/commands.c between version 1.8 and 1.9

version 1.8, 2003/06/12 22:30:23 version 1.9, 2003/06/13 21:52:24
Line 1 
Line 1 
 /*      $OpenBSD$       */  /* $OpenBSD$     */
   
 /*  /*
  *  Top users/processes display for Unix   *  Top users/processes display for Unix
Line 53 
Line 53 
 #include "utils.h"  #include "utils.h"
 #include "machine.h"  #include "machine.h"
   
 static char *next_field(char *);  static char    *next_field(char *);
 static int scanint(char *, int *);  static int      scanint(char *, int *);
 static char *err_string(void);  static char    *err_string(void);
 static size_t str_adderr(char *, size_t, int);  static size_t   str_adderr(char *, size_t, int);
 static size_t str_addarg(char *, size_t, char *, int);  static size_t   str_addarg(char *, size_t, char *, int);
 static int err_compar(const void *, const void *);  static int      err_compar(const void *, const void *);
   
 /*  /*
  *  show_help() - display the help screen; invoked in response to   *  show_help() - display the help screen; invoked in response to
  *              either 'h' or '?'.   *              either 'h' or '?'.
  */   */
   
 void  void
 show_help(void)  show_help(void)
 {  {
     printf("Top version %s, %s\n", version_string(), copyright);          printf("Top version %s, %s\n", version_string(), copyright);
     fputs("\n\n\          fputs("\n\n"
 A top users display for Unix\n\              "A top users display for Unix\n"
 \n\              "\n"
 These single-character commands are available:\n\              "These single-character commands are available:\n"
 \n\              "\n"
 ^L      - redraw screen\n\              "^L      - redraw screen\n"
 q       - quit\n\              "q       - quit\n"
 h or ?  - help; show this text\n", stdout);              "h or ?  - help; show this text\n", stdout);
   
     /* not all commands are availalbe with overstrike terminals */          /* not all commands are available with overstrike terminals */
     if (overstrike)          if (overstrike) {
     {                  fputs("\n"
         fputs("\n\                      "Other commands are also available, but this terminal is not\n"
 Other commands are also available, but this terminal is not\n\                      "sophisticated enough to handle those commands gracefully.\n\n",
 sophisticated enough to handle those commands gracefully.\n\n", stdout);                      stdout);
     }          } else {
     else                  fputs(
     {                      "d       - change number of displays to show\n"
         fputs("\                      "e       - list errors generated by last \"kill\" or \"renice\" command\n"
 d       - change number of displays to show\n\                      "i       - toggle the displaying of idle processes\n"
 e       - list errors generated by last \"kill\" or \"renice\" command\n\                      "I       - same as 'i'\n"
 i       - toggle the displaying of idle processes\n\                      "k       - kill processes; send a signal to a list of processes\n"
 I       - same as 'i'\n\                      "n or #  - change number of processes to display\n", stdout);
 k       - kill processes; send a signal to a list of processes\n\  
 n or #  - change number of processes to display\n", stdout);  
 #ifdef ORDER  #ifdef ORDER
         fputs("\                  fputs(
 o       - specify sort order (size, res, cpu, time)\n", stdout);                      "o       - specify sort order (size, res, cpu, time)\n",
                       stdout);
 #endif  #endif
         fputs("\                  fputs(
 r       - renice a process\n\                      "r       - renice a process\n"
 s       - change number of seconds to delay between updates\n\                      "s       - change number of seconds to delay between updates\n"
 u       - display processes for only one user (+ selects all users)\n\                      "u       - display processes for only one user (+ selects all users)\n"
 \n\                      "\n\n", stdout);
 \n", stdout);          }
     }  
 }  }
   
 /*  /*
  *  Utility routines that help with some of the commands.   *  Utility routines that help with some of the commands.
  */   */
   
 static char *  static char *
 next_field(char *str)  next_field(char *str)
 {  {
     if ((str = strchr(str, ' ')) == NULL)          if ((str = strchr(str, ' ')) == NULL)
     {                  return (NULL);
         return(NULL);  
     }  
     *str = '\0';  
     while (*++str == ' ') /* loop */;  
   
     /* if there is nothing left of the string, return NULL */          *str = '\0';
     /* This fix is dedicated to Greg Earle */          while (*++str == ' ')   /* loop */
     return (*str == '\0' ? NULL : str);                  ;
   
           /* if there is nothing left of the string, return NULL */
           /* This fix is dedicated to Greg Earle */
           return (*str == '\0' ? NULL : str);
 }  }
   
 static int scanint(char *str, int *intp)  static int
   scanint(char *str, int *intp)
 {  {
     int val = 0;          int val = 0;
     char ch;          char ch;
   
     /* if there is nothing left of the string, flag it as an error */          /* if there is nothing left of the string, flag it as an error */
     /* This fix is dedicated to Greg Earle */          /* This fix is dedicated to Greg Earle */
     if (*str == '\0')          if (*str == '\0')
     {                  return (-1);
         return(-1);  
     }  
   
     while ((ch = *str++) != '\0')          while ((ch = *str++) != '\0') {
     {                  if (isdigit(ch))
         if (isdigit(ch))                          val = val * 10 + (ch - '0');
         {                  else if (isspace(ch))
             val = val * 10 + (ch - '0');                          break;
                   else
                           return (-1);
         }          }
         else if (isspace(ch))          *intp = val;
         {          return (0);
             break;  
         }  
         else  
         {  
             return(-1);  
         }  
     }  
     *intp = val;  
     return(0);  
 }  }
   
 /*  /*
Line 168 
Line 156 
   
 #define ERRMAX 20  #define ERRMAX 20
   
 struct errs             /* structure for a system-call error */  struct errs {                   /* structure for a system-call error */
 {          int             errno;  /* value of errno (that is, the actual error) */
     int  errno;         /* value of errno (that is, the actual error) */          char           *arg;    /* argument that caused the error */
     char *arg;          /* argument that caused the error */  
 };  };
   
 static struct errs errs[ERRMAX];  static struct errs errs[ERRMAX];
 static int errcnt;  static int      errcnt;
 static char *err_toomany = " too many errors occurred";  static char    *err_toomany = " too many errors occurred";
 static char *err_listem =  static char    *err_listem =
         " Many errors occurred.  Press `e' to display the list of errors.";          " Many errors occurred.  Press `e' to display the list of errors.";
   
 /* These macros get used to reset and log the errors */  /* These macros get used to reset and log the errors */
 #define ERR_RESET   errcnt = 0  #define ERR_RESET   errcnt = 0
 #define ERROR(p, e) if (errcnt >= ERRMAX) \  #define ERROR(p, e) \
                     { \          if (errcnt >= ERRMAX) { \
                         return(err_toomany); \                  return(err_toomany); \
                     } \          } else { \
                     else \                  errs[errcnt].arg = (p); \
                     { \                  errs[errcnt++].errno = (e); \
                         errs[errcnt].arg = (p); \          }
                         errs[errcnt++].errno = (e); \  
                     }  
   
   #define STRMAX 80
   
 /*  /*
  *  err_string() - return an appropriate error string.  This is what the   *  err_string() - return an appropriate error string.  This is what the
  *      command will return for displaying.  If no errors were logged, then   *      command will return for displaying.  If no errors were logged, then
  *      return NULL.  The maximum length of the error string is defined by   *      return NULL.  The maximum length of the error string is defined by
  *      "STRMAX".   *      "STRMAX".
  */   */
   
 #define STRMAX 80  
   
 static char *  static char *
 err_string(void)  err_string(void)
 {  {
     struct errs *errp;          int cnt = 0, first = Yes, currerr = -1;
     int  cnt = 0;          static char string[STRMAX];
     int  first = Yes;          struct errs *errp;
     int  currerr = -1;  
     static char string[STRMAX];  
   
     /* if there are no errors, return NULL */          /* if there are no errors, return NULL */
     if (errcnt == 0)          if (errcnt == 0)
     {                  return (NULL);
         return(NULL);  
     }  
   
     /* sort the errors */          /* sort the errors */
     qsort((char *)errs, errcnt, sizeof(struct errs), err_compar);          qsort((char *) errs, errcnt, sizeof(struct errs), err_compar);
   
     /* need a space at the front of the error string */          /* need a space at the front of the error string */
     string[0] = ' ';          string[0] = ' ';
     string[1] = '\0';          string[1] = '\0';
   
     /* loop thru the sorted list, building an error string */          /* loop thru the sorted list, building an error string */
     while (cnt < errcnt)          while (cnt < errcnt) {
     {                  errp = &(errs[cnt++]);
         errp = &(errs[cnt++]);                  if (errp->errno != currerr) {
         if (errp->errno != currerr)                          if (currerr != -1) {
         {                                  if (str_adderr(string, sizeof string, currerr) >
             if (currerr != -1)                                      sizeof string - 2)
             {                                          return (err_listem);
                 if (str_adderr(string, sizeof string, currerr) >  
                     (sizeof string - 2))                                  /* we know there's more */
                 {                                  (void) strlcat(string, "; ", sizeof string);
                     return(err_listem);                          }
                           currerr = errp->errno;
                           first = Yes;
                 }                  }
                 /* we know there's more */                  if (str_addarg(string, sizeof string, errp->arg, first) >=
                 (void) strlcat(string, "; ", sizeof string);                      sizeof string)
             }                          return (err_listem);
             currerr = errp->errno;  
             first = Yes;                  first = No;
         }          }
         if (str_addarg(string, sizeof string, errp->arg, first) >=  
             sizeof string)  
         {  
             return(err_listem);  
         }  
         first = No;  
     }  
   
     /* add final message */          /* add final message */
     if (str_adderr(string, sizeof string, currerr) >= sizeof string)          if (str_adderr(string, sizeof string, currerr) >= sizeof string)
         return(err_listem);                  return (err_listem);
   
     /* return the error string */          /* return the error string */
     return(string);          return (string);
 }  }
   
 /*  /*
  *  str_adderr(str, len, err) - add an explanation of error "err" to   *  str_adderr(str, len, err) - add an explanation of error "err" to
  *      the string "str".   *      the string "str".
  */   */
   
 static size_t  static size_t
 str_adderr(char *str, size_t len, int err)  str_adderr(char *str, size_t len, int err)
 {  {
     char *msg;          size_t msglen;
     size_t msglen;          char *msg;
   
     msg = err == 0 ? "Not a number" : strerror(err);          msg = err == 0 ? "Not a number" : strerror(err);
   
     if ((msglen = strlcat(str, ": ", len)) >= len)          if ((msglen = strlcat(str, ": ", len)) >= len)
         return(msglen);                  return (msglen);
   
     return(strlcat(str, msg, len));          return (strlcat(str, msg, len));
 }  }
   
 /*  /*
Line 282 
Line 256 
  *      the string "str".  This is the first in the group when "first"   *      the string "str".  This is the first in the group when "first"
  *      is set (indicating that a comma should NOT be added to the front).   *      is set (indicating that a comma should NOT be added to the front).
  */   */
   
 static size_t  static size_t
 str_addarg(char *str, size_t len, char *arg, int first)  str_addarg(char *str, size_t len, char *arg, int first)
 {  {
     size_t msglen;          size_t msglen;
   
     if (!first)          if (!first) {
     {                  if ((msglen = strlcat(str, ", ", len)) >= len)
         if ((msglen = strlcat(str, ", ", len)) >= len)                          return (msglen);
             return(msglen);          }
     }          return (strlcat(str, arg, len));
   
     return (strlcat(str, arg, len));  
 }  }
   
 /*  /*
  *  err_compar(p1, p2) - comparison routine used by "qsort"   *  err_compar(p1, p2) - comparison routine used by "qsort"
  *      for sorting errors.   *      for sorting errors.
  */   */
   
 static int  static int
 err_compar(const void *e1, const void *e2)  err_compar(const void *e1, const void *e2)
 {  {
     const struct errs *p1 = (struct errs *)e1;          const struct errs *p1 = (struct errs *) e1;
     const struct errs *p2 = (struct errs *)e2;          const struct errs *p2 = (struct errs *) e2;
     int result;          int result;
   
     if ((result = p1->errno - p2->errno) == 0)          if ((result = p1->errno - p2->errno) == 0)
     {                  return (strcmp(p1->arg, p2->arg));
         return(strcmp(p1->arg, p2->arg));          return (result);
     }  
     return(result);  
 }  }
   
 /*  /*
  *  error_count() - return the number of errors currently logged.   *  error_count() - return the number of errors currently logged.
  */   */
   
 int  int
 error_count(void)  error_count(void)
 {  {
     return(errcnt);          return (errcnt);
 }  }
   
 /*  /*
  *  show_errors() - display on stdout the current log of errors.   *  show_errors() - display on stdout the current log of errors.
  */   */
   
 void  void
 show_errors(void)  show_errors(void)
 {  {
     int cnt = 0;          struct errs *errp = errs;
     struct errs *errp = errs;          int cnt = 0;
   
     printf("%d error%s:\n\n", errcnt, errcnt == 1 ? "" : "s");          printf("%d error%s:\n\n", errcnt, errcnt == 1 ? "" : "s");
     while (cnt++ < errcnt)          while (cnt++ < errcnt) {
     {                  printf("%5s: %s\n", errp->arg,
         printf("%5s: %s\n", errp->arg,                      errp->errno == 0 ? "Not a number" : strerror(errp->errno));
             errp->errno == 0 ? "Not a number" : strerror(errp->errno));                  errp++;
         errp++;          }
     }  
 }  }
   
 /*  /*
  *  kill_procs(str) - send signals to processes, much like the "kill"   *  kill_procs(str) - send signals to processes, much like the "kill"
  *              command does; invoked in response to 'k'.   *              command does; invoked in response to 'k'.
  */   */
   
 char *  char *
 kill_procs(char *str)  kill_procs(char *str)
 {  {
     char *nptr;          int signum = SIGTERM, procnum, uid;
     int signum = SIGTERM;       /* default */          struct sigdesc *sigp;
     int procnum;          char *nptr;
     struct sigdesc *sigp;  
     int uid;  
   
     /* reset error array */          /* reset error array */
     ERR_RESET;          ERR_RESET;
   
     /* remember our uid */          /* remember our uid */
     uid = getuid();          uid = getuid();
   
     /* skip over leading white space */          /* skip over leading white space */
     while (isspace(*str)) str++;          while (isspace(*str))
                   str++;
   
     if (str[0] == '-')          if (str[0] == '-') {
     {                  /* explicit signal specified */
         /* explicit signal specified */                  if ((nptr = next_field(str)) == NULL)
         if ((nptr = next_field(str)) == NULL)                          return (" kill: no processes specified");
         {  
             return(" kill: no processes specified");  
         }  
   
         if (isdigit(str[1]))                  if (isdigit(str[1])) {
         {                          (void) scanint(str + 1, &signum);
             (void) scanint(str + 1, &signum);                          if (signum <= 0 || signum >= NSIG)
             if (signum <= 0 || signum >= NSIG)                                  return (" invalid signal number");
             {                  } else {
                 return(" invalid signal number");                          /* translate the name into a number */
             }                          for (sigp = sigdesc; sigp->name != NULL; sigp++) {
                                   if (strcmp(sigp->name, str + 1) == 0) {
                                           signum = sigp->number;
                                           break;
                                   }
                           }
   
                           /* was it ever found */
                           if (sigp->name == NULL)
                                   return (" bad signal name");
                   }
                   /* put the new pointer in place */
                   str = nptr;
         }          }
         else          /* loop thru the string, killing processes */
         {          do {
             /* translate the name into a number */                  if (scanint(str, &procnum) == -1) {
             for (sigp = sigdesc; sigp->name != NULL; sigp++)                          ERROR(str, 0);
             {                  } else {
                 if (strcmp(sigp->name, str + 1) == 0)                          /* check process owner if we're not root */
                 {                          if (uid && (uid != proc_owner(procnum))) {
                     signum = sigp->number;                                  ERROR(str, EACCES);
                     break;                          } else if (kill(procnum, signum) == -1) {
                                   ERROR(str, errno);
                           }
                 }                  }
             }          } while ((str = next_field(str)) != NULL);
   
             /* was it ever found */          /* return appropriate error string */
             if (sigp->name == NULL)          return (err_string());
             {  
                 return(" bad signal name");  
             }  
         }  
         /* put the new pointer in place */  
         str = nptr;  
     }  
   
     /* loop thru the string, killing processes */  
     do  
     {  
         if (scanint(str, &procnum) == -1)  
         {  
             ERROR(str, 0);  
         }  
         else  
         {  
             /* check process owner if we're not root */  
             if (uid && (uid != proc_owner(procnum)))  
             {  
                 ERROR(str, EACCES);  
             }  
             /* go in for the kill */  
             else if (kill(procnum, signum) == -1)  
             {  
                 /* chalk up an error */  
                 ERROR(str, errno);  
             }  
         }  
     } while ((str = next_field(str)) != NULL);  
   
     /* return appropriate error string */  
     return(err_string());  
 }  }
   
 /*  /*
  *  renice_procs(str) - change the "nice" of processes, much like the   *  renice_procs(str) - change the "nice" of processes, much like the
  *              "renice" command does; invoked in response to 'r'.   *              "renice" command does; invoked in response to 'r'.
  */   */
   
 char *  char *
 renice_procs(char *str)  renice_procs(char *str)
 {  {
     char negate;          int prio, procnum, uid;
     int prio;          char negate;
     int procnum;  
     int uid;  
   
     ERR_RESET;          ERR_RESET;
     uid = getuid();          uid = getuid();
   
     /* allow for negative priority values */          /* allow for negative priority values */
     if ((negate = (*str == '-')) != 0)          if ((negate = (*str == '-')) != 0) {
     {                  /* move past the minus sign */
         /* move past the minus sign */                  str++;
         str++;          }
     }          /* use procnum as a temporary holding place and get the number */
           procnum = scanint(str, &prio);
   
     /* use procnum as a temporary holding place and get the number */          /* negate if necessary */
     procnum = scanint(str, &prio);          if (negate)
                   prio = -prio;
   
     /* negate if necessary */  
     if (negate)  
     {  
         prio = -prio;  
     }  
   
 #if defined(PRIO_MIN) && defined(PRIO_MAX)  #if defined(PRIO_MIN) && defined(PRIO_MAX)
     /* check for validity */          /* check for validity */
     if (procnum == -1 || prio < PRIO_MIN || prio > PRIO_MAX)          if (procnum == -1 || prio < PRIO_MIN || prio > PRIO_MAX)
     {                  return (" bad priority value");
         return(" bad priority value");  
     }  
 #endif  #endif
   
     /* move to the first process number */          /* move to the first process number */
     if ((str = next_field(str)) == NULL)          if ((str = next_field(str)) == NULL)
     {                  return (" no processes specified");
         return(" no processes specified");  
     }  
   
     /* loop thru the process numbers, renicing each one */          /* loop thru the process numbers, renicing each one */
     do          do {
     {                  if (scanint(str, &procnum) == -1) {
         if (scanint(str, &procnum) == -1)                          ERROR(str, 0);
         {                  }
             ERROR(str, 0);                  /* check process owner if we're not root */
         }                  else if (uid && (uid != proc_owner(procnum))) {
                           ERROR(str, EACCES);
                   } else if (setpriority(PRIO_PROCESS, procnum, prio) == -1) {
                           ERROR(str, errno);
                   }
           } while ((str = next_field(str)) != NULL);
   
         /* check process owner if we're not root */          /* return appropriate error string */
         else if (uid && (uid != proc_owner(procnum)))          return (err_string());
         {  
             ERROR(str, EACCES);  
         }  
         else if (setpriority(PRIO_PROCESS, procnum, prio) == -1)  
         {  
             ERROR(str, errno);  
         }  
     } while ((str = next_field(str)) != NULL);  
   
     /* return appropriate error string */  
     return(err_string());  
 }  }

Legend:
Removed from v.1.8  
changed lines
  Added in v.1.9