13be6ef06SEitan Adler /* 23be6ef06SEitan Adler * Top users/processes display for Unix 33be6ef06SEitan Adler * Version 3 43be6ef06SEitan Adler * 53be6ef06SEitan Adler * This program may be freely redistributed, 63be6ef06SEitan Adler * but this entire comment MUST remain intact. 73be6ef06SEitan Adler * 83be6ef06SEitan Adler * Copyright (c) 1984, 1989, William LeFebvre, Rice University 93be6ef06SEitan Adler * Copyright (c) 1989, 1990, 1992, William LeFebvre, Northwestern University 103be6ef06SEitan Adler * 113be6ef06SEitan Adler * $FreeBSD$ 123be6ef06SEitan Adler */ 133be6ef06SEitan Adler 143be6ef06SEitan Adler /* 153be6ef06SEitan Adler * This file contains the routines that implement some of the interactive 163be6ef06SEitan Adler * mode commands. Note that some of the commands are implemented in-line 173be6ef06SEitan Adler * in "main". This is necessary because they change the global state of 183be6ef06SEitan Adler * "top" (i.e.: changing the number of processes to display). 193be6ef06SEitan Adler */ 203be6ef06SEitan Adler 213be6ef06SEitan Adler #include <sys/time.h> 223be6ef06SEitan Adler #include <sys/resource.h> 233be6ef06SEitan Adler 243be6ef06SEitan Adler #include <ctype.h> 253be6ef06SEitan Adler #include <errno.h> 263be6ef06SEitan Adler #include <signal.h> 27*caee4883SEitan Adler #include <stdlib.h> 28*caee4883SEitan Adler #include <stdio.h> 29*caee4883SEitan Adler #include <string.h> 303be6ef06SEitan Adler #include <unistd.h> 313be6ef06SEitan Adler 323be6ef06SEitan Adler #include "commands.h" 333be6ef06SEitan Adler #include "sigdesc.h" /* generated automatically */ 343be6ef06SEitan Adler #include "top.h" 353be6ef06SEitan Adler #include "boolean.h" 363be6ef06SEitan Adler #include "utils.h" 373be6ef06SEitan Adler #include "machine.h" 383be6ef06SEitan Adler 393be6ef06SEitan Adler extern int errno; 403be6ef06SEitan Adler 413be6ef06SEitan Adler extern char *copyright; 423be6ef06SEitan Adler 433be6ef06SEitan Adler /* imported from screen.c */ 443be6ef06SEitan Adler extern int overstrike; 453be6ef06SEitan Adler 463be6ef06SEitan Adler int err_compar(); 473be6ef06SEitan Adler char *err_string(); 483be6ef06SEitan Adler static int str_adderr(char *str, int len, int err); 493be6ef06SEitan Adler static int str_addarg(char *str, int len, char *arg, int first); 503be6ef06SEitan Adler 513be6ef06SEitan Adler /* 523be6ef06SEitan Adler * show_help() - display the help screen; invoked in response to 533be6ef06SEitan Adler * either 'h' or '?'. 543be6ef06SEitan Adler */ 553be6ef06SEitan Adler 563be6ef06SEitan Adler void 573be6ef06SEitan Adler show_help() 583be6ef06SEitan Adler 593be6ef06SEitan Adler { 608a133278SEitan Adler printf("Top version FreeBSD, %s\n", copyright); 613be6ef06SEitan Adler fputs("\n\n\ 623be6ef06SEitan Adler A top users display for Unix\n\ 633be6ef06SEitan Adler \n\ 643be6ef06SEitan Adler These single-character commands are available:\n\ 653be6ef06SEitan Adler \n\ 663be6ef06SEitan Adler ^L - redraw screen\n\ 673be6ef06SEitan Adler q - quit\n\ 683be6ef06SEitan Adler h or ? - help; show this text\n", stdout); 693be6ef06SEitan Adler 703be6ef06SEitan Adler /* not all commands are availalbe with overstrike terminals */ 713be6ef06SEitan Adler if (overstrike) 723be6ef06SEitan Adler { 733be6ef06SEitan Adler fputs("\n\ 743be6ef06SEitan Adler Other commands are also available, but this terminal is not\n\ 753be6ef06SEitan Adler sophisticated enough to handle those commands gracefully.\n\n", stdout); 763be6ef06SEitan Adler } 773be6ef06SEitan Adler else 783be6ef06SEitan Adler { 793be6ef06SEitan Adler fputs("\ 803be6ef06SEitan Adler C - toggle the displaying of weighted CPU percentage\n\ 813be6ef06SEitan Adler d - change number of displays to show\n\ 823be6ef06SEitan Adler e - list errors generated by last \"kill\" or \"renice\" command\n\ 833be6ef06SEitan Adler H - toggle the displaying of threads\n\ 843be6ef06SEitan Adler i or I - toggle the displaying of idle processes\n\ 853be6ef06SEitan Adler j - toggle the displaying of jail ID\n\ 863be6ef06SEitan Adler J - display processes for only one jail (+ selects all jails)\n\ 873be6ef06SEitan Adler k - kill processes; send a signal to a list of processes\n\ 883be6ef06SEitan Adler m - toggle the display between 'cpu' and 'io' modes\n\ 893be6ef06SEitan Adler n or # - change number of processes to display\n", stdout); 903be6ef06SEitan Adler if (displaymode == DISP_CPU) 913be6ef06SEitan Adler fputs("\ 923be6ef06SEitan Adler o - specify sort order (pri, size, res, cpu, time, threads, jid, pid)\n", 933be6ef06SEitan Adler stdout); 943be6ef06SEitan Adler else 953be6ef06SEitan Adler fputs("\ 963be6ef06SEitan Adler o - specify sort order (vcsw, ivcsw, read, write, fault, total, jid, pid)\n", 973be6ef06SEitan Adler stdout); 983be6ef06SEitan Adler fputs("\ 993be6ef06SEitan Adler P - toggle the displaying of per-CPU statistics\n\ 1003be6ef06SEitan Adler r - renice a process\n\ 1013be6ef06SEitan Adler s - change number of seconds to delay between updates\n\ 1023be6ef06SEitan Adler S - toggle the displaying of system processes\n\ 1033be6ef06SEitan Adler a - toggle the displaying of process titles\n\ 1043be6ef06SEitan Adler t - toggle the display of this process\n\ 1053be6ef06SEitan Adler u - display processes for only one user (+ selects all users)\n\ 1063be6ef06SEitan Adler w - toggle the display of swap use for each process\n\ 1073be6ef06SEitan Adler z - toggle the displaying of the system idle process\n\ 1083be6ef06SEitan Adler \n\ 1093be6ef06SEitan Adler \n", stdout); 1103be6ef06SEitan Adler } 1113be6ef06SEitan Adler } 1123be6ef06SEitan Adler 1133be6ef06SEitan Adler /* 1143be6ef06SEitan Adler * Utility routines that help with some of the commands. 1153be6ef06SEitan Adler */ 1163be6ef06SEitan Adler 1173be6ef06SEitan Adler char *next_field(str) 1183be6ef06SEitan Adler 1193be6ef06SEitan Adler register char *str; 1203be6ef06SEitan Adler 1213be6ef06SEitan Adler { 1223be6ef06SEitan Adler if ((str = strchr(str, ' ')) == NULL) 1233be6ef06SEitan Adler { 1243be6ef06SEitan Adler return(NULL); 1253be6ef06SEitan Adler } 1263be6ef06SEitan Adler *str = '\0'; 1273be6ef06SEitan Adler while (*++str == ' ') /* loop */; 1283be6ef06SEitan Adler 1293be6ef06SEitan Adler /* if there is nothing left of the string, return NULL */ 1303be6ef06SEitan Adler /* This fix is dedicated to Greg Earle */ 1313be6ef06SEitan Adler return(*str == '\0' ? NULL : str); 1323be6ef06SEitan Adler } 1333be6ef06SEitan Adler 1343be6ef06SEitan Adler int 1353be6ef06SEitan Adler scanint(str, intp) 1363be6ef06SEitan Adler 1373be6ef06SEitan Adler char *str; 1383be6ef06SEitan Adler int *intp; 1393be6ef06SEitan Adler 1403be6ef06SEitan Adler { 1413be6ef06SEitan Adler register int val = 0; 1423be6ef06SEitan Adler register char ch; 1433be6ef06SEitan Adler 1443be6ef06SEitan Adler /* if there is nothing left of the string, flag it as an error */ 1453be6ef06SEitan Adler /* This fix is dedicated to Greg Earle */ 1463be6ef06SEitan Adler if (*str == '\0') 1473be6ef06SEitan Adler { 1483be6ef06SEitan Adler return(-1); 1493be6ef06SEitan Adler } 1503be6ef06SEitan Adler 1513be6ef06SEitan Adler while ((ch = *str++) != '\0') 1523be6ef06SEitan Adler { 1533be6ef06SEitan Adler if (isdigit(ch)) 1543be6ef06SEitan Adler { 1553be6ef06SEitan Adler val = val * 10 + (ch - '0'); 1563be6ef06SEitan Adler } 1573be6ef06SEitan Adler else if (isspace(ch)) 1583be6ef06SEitan Adler { 1593be6ef06SEitan Adler break; 1603be6ef06SEitan Adler } 1613be6ef06SEitan Adler else 1623be6ef06SEitan Adler { 1633be6ef06SEitan Adler return(-1); 1643be6ef06SEitan Adler } 1653be6ef06SEitan Adler } 1663be6ef06SEitan Adler *intp = val; 1673be6ef06SEitan Adler return(0); 1683be6ef06SEitan Adler } 1693be6ef06SEitan Adler 1703be6ef06SEitan Adler /* 1713be6ef06SEitan Adler * Some of the commands make system calls that could generate errors. 1723be6ef06SEitan Adler * These errors are collected up in an array of structures for later 1733be6ef06SEitan Adler * contemplation and display. Such routines return a string containing an 1743be6ef06SEitan Adler * error message, or NULL if no errors occurred. The next few routines are 1753be6ef06SEitan Adler * for manipulating and displaying these errors. We need an upper limit on 1763be6ef06SEitan Adler * the number of errors, so we arbitrarily choose 20. 1773be6ef06SEitan Adler */ 1783be6ef06SEitan Adler 1793be6ef06SEitan Adler #define ERRMAX 20 1803be6ef06SEitan Adler 1813be6ef06SEitan Adler struct errs /* structure for a system-call error */ 1823be6ef06SEitan Adler { 1833be6ef06SEitan Adler int errnum; /* value of errno (that is, the actual error) */ 1843be6ef06SEitan Adler char *arg; /* argument that caused the error */ 1853be6ef06SEitan Adler }; 1863be6ef06SEitan Adler 1873be6ef06SEitan Adler static struct errs errs[ERRMAX]; 1883be6ef06SEitan Adler static int errcnt; 1893be6ef06SEitan Adler static char *err_toomany = " too many errors occurred"; 1903be6ef06SEitan Adler static char *err_listem = 1913be6ef06SEitan Adler " Many errors occurred. Press `e' to display the list of errors."; 1923be6ef06SEitan Adler 1933be6ef06SEitan Adler /* These macros get used to reset and log the errors */ 1943be6ef06SEitan Adler #define ERR_RESET errcnt = 0 1953be6ef06SEitan Adler #define ERROR(p, e) if (errcnt >= ERRMAX) \ 1963be6ef06SEitan Adler { \ 1973be6ef06SEitan Adler return(err_toomany); \ 1983be6ef06SEitan Adler } \ 1993be6ef06SEitan Adler else \ 2003be6ef06SEitan Adler { \ 2013be6ef06SEitan Adler errs[errcnt].arg = (p); \ 2023be6ef06SEitan Adler errs[errcnt++].errnum = (e); \ 2033be6ef06SEitan Adler } 2043be6ef06SEitan Adler 2053be6ef06SEitan Adler /* 2063be6ef06SEitan Adler * err_string() - return an appropriate error string. This is what the 2073be6ef06SEitan Adler * command will return for displaying. If no errors were logged, then 2083be6ef06SEitan Adler * return NULL. The maximum length of the error string is defined by 2093be6ef06SEitan Adler * "STRMAX". 2103be6ef06SEitan Adler */ 2113be6ef06SEitan Adler 2123be6ef06SEitan Adler #define STRMAX 80 2133be6ef06SEitan Adler 2143be6ef06SEitan Adler char *err_string() 2153be6ef06SEitan Adler 2163be6ef06SEitan Adler { 2173be6ef06SEitan Adler register struct errs *errp; 2183be6ef06SEitan Adler register int cnt = 0; 2193be6ef06SEitan Adler register int first = Yes; 2203be6ef06SEitan Adler register int currerr = -1; 2213be6ef06SEitan Adler int stringlen; /* characters still available in "string" */ 2223be6ef06SEitan Adler static char string[STRMAX]; 2233be6ef06SEitan Adler 2243be6ef06SEitan Adler /* if there are no errors, return NULL */ 2253be6ef06SEitan Adler if (errcnt == 0) 2263be6ef06SEitan Adler { 2273be6ef06SEitan Adler return(NULL); 2283be6ef06SEitan Adler } 2293be6ef06SEitan Adler 2303be6ef06SEitan Adler /* sort the errors */ 2313be6ef06SEitan Adler qsort((char *)errs, errcnt, sizeof(struct errs), err_compar); 2323be6ef06SEitan Adler 2333be6ef06SEitan Adler /* need a space at the front of the error string */ 2343be6ef06SEitan Adler string[0] = ' '; 2353be6ef06SEitan Adler string[1] = '\0'; 2363be6ef06SEitan Adler stringlen = STRMAX - 2; 2373be6ef06SEitan Adler 2383be6ef06SEitan Adler /* loop thru the sorted list, building an error string */ 2393be6ef06SEitan Adler while (cnt < errcnt) 2403be6ef06SEitan Adler { 2413be6ef06SEitan Adler errp = &(errs[cnt++]); 2423be6ef06SEitan Adler if (errp->errnum != currerr) 2433be6ef06SEitan Adler { 2443be6ef06SEitan Adler if (currerr != -1) 2453be6ef06SEitan Adler { 2463be6ef06SEitan Adler if ((stringlen = str_adderr(string, stringlen, currerr)) < 2) 2473be6ef06SEitan Adler { 2483be6ef06SEitan Adler return(err_listem); 2493be6ef06SEitan Adler } 2503be6ef06SEitan Adler (void) strcat(string, "; "); /* we know there's more */ 2513be6ef06SEitan Adler } 2523be6ef06SEitan Adler currerr = errp->errnum; 2533be6ef06SEitan Adler first = Yes; 2543be6ef06SEitan Adler } 2553be6ef06SEitan Adler if ((stringlen = str_addarg(string, stringlen, errp->arg, first)) ==0) 2563be6ef06SEitan Adler { 2573be6ef06SEitan Adler return(err_listem); 2583be6ef06SEitan Adler } 2593be6ef06SEitan Adler first = No; 2603be6ef06SEitan Adler } 2613be6ef06SEitan Adler 2623be6ef06SEitan Adler /* add final message */ 2633be6ef06SEitan Adler stringlen = str_adderr(string, stringlen, currerr); 2643be6ef06SEitan Adler 2653be6ef06SEitan Adler /* return the error string */ 2663be6ef06SEitan Adler return(stringlen == 0 ? err_listem : string); 2673be6ef06SEitan Adler } 2683be6ef06SEitan Adler 2693be6ef06SEitan Adler /* 2703be6ef06SEitan Adler * str_adderr(str, len, err) - add an explanation of error "err" to 2713be6ef06SEitan Adler * the string "str". 2723be6ef06SEitan Adler */ 2733be6ef06SEitan Adler 2743be6ef06SEitan Adler static int 2753be6ef06SEitan Adler str_adderr(str, len, err) 2763be6ef06SEitan Adler 2773be6ef06SEitan Adler char *str; 2783be6ef06SEitan Adler int len; 2793be6ef06SEitan Adler int err; 2803be6ef06SEitan Adler 2813be6ef06SEitan Adler { 2823be6ef06SEitan Adler register char *msg; 2833be6ef06SEitan Adler register int msglen; 2843be6ef06SEitan Adler 2853be6ef06SEitan Adler msg = err == 0 ? "Not a number" : errmsg(err); 2863be6ef06SEitan Adler msglen = strlen(msg) + 2; 2873be6ef06SEitan Adler if (len <= msglen) 2883be6ef06SEitan Adler { 2893be6ef06SEitan Adler return(0); 2903be6ef06SEitan Adler } 2913be6ef06SEitan Adler (void) strcat(str, ": "); 2923be6ef06SEitan Adler (void) strcat(str, msg); 2933be6ef06SEitan Adler return(len - msglen); 2943be6ef06SEitan Adler } 2953be6ef06SEitan Adler 2963be6ef06SEitan Adler /* 2973be6ef06SEitan Adler * str_addarg(str, len, arg, first) - add the string argument "arg" to 2983be6ef06SEitan Adler * the string "str". This is the first in the group when "first" 2993be6ef06SEitan Adler * is set (indicating that a comma should NOT be added to the front). 3003be6ef06SEitan Adler */ 3013be6ef06SEitan Adler 3023be6ef06SEitan Adler static int 3033be6ef06SEitan Adler str_addarg(str, len, arg, first) 3043be6ef06SEitan Adler 3053be6ef06SEitan Adler char *str; 3063be6ef06SEitan Adler int len; 3073be6ef06SEitan Adler char *arg; 3083be6ef06SEitan Adler int first; 3093be6ef06SEitan Adler 3103be6ef06SEitan Adler { 3113be6ef06SEitan Adler register int arglen; 3123be6ef06SEitan Adler 3133be6ef06SEitan Adler arglen = strlen(arg); 3143be6ef06SEitan Adler if (!first) 3153be6ef06SEitan Adler { 3163be6ef06SEitan Adler arglen += 2; 3173be6ef06SEitan Adler } 3183be6ef06SEitan Adler if (len <= arglen) 3193be6ef06SEitan Adler { 3203be6ef06SEitan Adler return(0); 3213be6ef06SEitan Adler } 3223be6ef06SEitan Adler if (!first) 3233be6ef06SEitan Adler { 3243be6ef06SEitan Adler (void) strcat(str, ", "); 3253be6ef06SEitan Adler } 3263be6ef06SEitan Adler (void) strcat(str, arg); 3273be6ef06SEitan Adler return(len - arglen); 3283be6ef06SEitan Adler } 3293be6ef06SEitan Adler 3303be6ef06SEitan Adler /* 3313be6ef06SEitan Adler * err_compar(p1, p2) - comparison routine used by "qsort" 3323be6ef06SEitan Adler * for sorting errors. 3333be6ef06SEitan Adler */ 3343be6ef06SEitan Adler 3353be6ef06SEitan Adler int 3363be6ef06SEitan Adler err_compar(p1, p2) 3373be6ef06SEitan Adler 3383be6ef06SEitan Adler register struct errs *p1, *p2; 3393be6ef06SEitan Adler 3403be6ef06SEitan Adler { 3413be6ef06SEitan Adler register int result; 3423be6ef06SEitan Adler 3433be6ef06SEitan Adler if ((result = p1->errnum - p2->errnum) == 0) 3443be6ef06SEitan Adler { 3453be6ef06SEitan Adler return(strcmp(p1->arg, p2->arg)); 3463be6ef06SEitan Adler } 3473be6ef06SEitan Adler return(result); 3483be6ef06SEitan Adler } 3493be6ef06SEitan Adler 3503be6ef06SEitan Adler /* 3513be6ef06SEitan Adler * error_count() - return the number of errors currently logged. 3523be6ef06SEitan Adler */ 3533be6ef06SEitan Adler 3543be6ef06SEitan Adler int 3553be6ef06SEitan Adler error_count() 3563be6ef06SEitan Adler 3573be6ef06SEitan Adler { 3583be6ef06SEitan Adler return(errcnt); 3593be6ef06SEitan Adler } 3603be6ef06SEitan Adler 3613be6ef06SEitan Adler /* 3623be6ef06SEitan Adler * show_errors() - display on stdout the current log of errors. 3633be6ef06SEitan Adler */ 3643be6ef06SEitan Adler 3653be6ef06SEitan Adler void 3663be6ef06SEitan Adler show_errors() 3673be6ef06SEitan Adler 3683be6ef06SEitan Adler { 3693be6ef06SEitan Adler register int cnt = 0; 3703be6ef06SEitan Adler register struct errs *errp = errs; 3713be6ef06SEitan Adler 3723be6ef06SEitan Adler printf("%d error%s:\n\n", errcnt, errcnt == 1 ? "" : "s"); 3733be6ef06SEitan Adler while (cnt++ < errcnt) 3743be6ef06SEitan Adler { 3753be6ef06SEitan Adler printf("%5s: %s\n", errp->arg, 3763be6ef06SEitan Adler errp->errnum == 0 ? "Not a number" : errmsg(errp->errnum)); 3773be6ef06SEitan Adler errp++; 3783be6ef06SEitan Adler } 3793be6ef06SEitan Adler } 3803be6ef06SEitan Adler 3813be6ef06SEitan Adler /* 3823be6ef06SEitan Adler * kill_procs(str) - send signals to processes, much like the "kill" 3833be6ef06SEitan Adler * command does; invoked in response to 'k'. 3843be6ef06SEitan Adler */ 3853be6ef06SEitan Adler 3863be6ef06SEitan Adler char *kill_procs(str) 3873be6ef06SEitan Adler 3883be6ef06SEitan Adler char *str; 3893be6ef06SEitan Adler 3903be6ef06SEitan Adler { 3913be6ef06SEitan Adler register char *nptr; 3923be6ef06SEitan Adler int signum = SIGTERM; /* default */ 3933be6ef06SEitan Adler int procnum; 3943be6ef06SEitan Adler struct sigdesc *sigp; 3953be6ef06SEitan Adler int uid; 3963be6ef06SEitan Adler 3973be6ef06SEitan Adler /* reset error array */ 3983be6ef06SEitan Adler ERR_RESET; 3993be6ef06SEitan Adler 4003be6ef06SEitan Adler /* remember our uid */ 4013be6ef06SEitan Adler uid = getuid(); 4023be6ef06SEitan Adler 4033be6ef06SEitan Adler /* skip over leading white space */ 4043be6ef06SEitan Adler while (isspace(*str)) str++; 4053be6ef06SEitan Adler 4063be6ef06SEitan Adler if (str[0] == '-') 4073be6ef06SEitan Adler { 4083be6ef06SEitan Adler /* explicit signal specified */ 4093be6ef06SEitan Adler if ((nptr = next_field(str)) == NULL) 4103be6ef06SEitan Adler { 4113be6ef06SEitan Adler return(" kill: no processes specified"); 4123be6ef06SEitan Adler } 4133be6ef06SEitan Adler 4143be6ef06SEitan Adler if (isdigit(str[1])) 4153be6ef06SEitan Adler { 4163be6ef06SEitan Adler (void) scanint(str + 1, &signum); 4173be6ef06SEitan Adler if (signum <= 0 || signum >= NSIG) 4183be6ef06SEitan Adler { 4193be6ef06SEitan Adler return(" invalid signal number"); 4203be6ef06SEitan Adler } 4213be6ef06SEitan Adler } 4223be6ef06SEitan Adler else 4233be6ef06SEitan Adler { 4243be6ef06SEitan Adler /* translate the name into a number */ 4253be6ef06SEitan Adler for (sigp = sigdesc; sigp->name != NULL; sigp++) 4263be6ef06SEitan Adler { 4273be6ef06SEitan Adler if (strcmp(sigp->name, str + 1) == 0) 4283be6ef06SEitan Adler { 4293be6ef06SEitan Adler signum = sigp->number; 4303be6ef06SEitan Adler break; 4313be6ef06SEitan Adler } 4323be6ef06SEitan Adler } 4333be6ef06SEitan Adler 4343be6ef06SEitan Adler /* was it ever found */ 4353be6ef06SEitan Adler if (sigp->name == NULL) 4363be6ef06SEitan Adler { 4373be6ef06SEitan Adler return(" bad signal name"); 4383be6ef06SEitan Adler } 4393be6ef06SEitan Adler } 4403be6ef06SEitan Adler /* put the new pointer in place */ 4413be6ef06SEitan Adler str = nptr; 4423be6ef06SEitan Adler } 4433be6ef06SEitan Adler 4443be6ef06SEitan Adler /* loop thru the string, killing processes */ 4453be6ef06SEitan Adler do 4463be6ef06SEitan Adler { 4473be6ef06SEitan Adler if (scanint(str, &procnum) == -1) 4483be6ef06SEitan Adler { 4493be6ef06SEitan Adler ERROR(str, 0); 4503be6ef06SEitan Adler } 4513be6ef06SEitan Adler else 4523be6ef06SEitan Adler { 4533be6ef06SEitan Adler /* check process owner if we're not root */ 4543be6ef06SEitan Adler if (uid && (uid != proc_owner(procnum))) 4553be6ef06SEitan Adler { 4563be6ef06SEitan Adler ERROR(str, EACCES); 4573be6ef06SEitan Adler } 4583be6ef06SEitan Adler /* go in for the kill */ 4593be6ef06SEitan Adler else if (kill(procnum, signum) == -1) 4603be6ef06SEitan Adler { 4613be6ef06SEitan Adler /* chalk up an error */ 4623be6ef06SEitan Adler ERROR(str, errno); 4633be6ef06SEitan Adler } 4643be6ef06SEitan Adler } 4653be6ef06SEitan Adler } while ((str = next_field(str)) != NULL); 4663be6ef06SEitan Adler 4673be6ef06SEitan Adler /* return appropriate error string */ 4683be6ef06SEitan Adler return(err_string()); 4693be6ef06SEitan Adler } 4703be6ef06SEitan Adler 4713be6ef06SEitan Adler /* 4723be6ef06SEitan Adler * renice_procs(str) - change the "nice" of processes, much like the 4733be6ef06SEitan Adler * "renice" command does; invoked in response to 'r'. 4743be6ef06SEitan Adler */ 4753be6ef06SEitan Adler 4763be6ef06SEitan Adler char *renice_procs(str) 4773be6ef06SEitan Adler 4783be6ef06SEitan Adler char *str; 4793be6ef06SEitan Adler 4803be6ef06SEitan Adler { 4813be6ef06SEitan Adler register char negate; 4823be6ef06SEitan Adler int prio; 4833be6ef06SEitan Adler int procnum; 4843be6ef06SEitan Adler int uid; 4853be6ef06SEitan Adler 4863be6ef06SEitan Adler ERR_RESET; 4873be6ef06SEitan Adler uid = getuid(); 4883be6ef06SEitan Adler 4893be6ef06SEitan Adler /* allow for negative priority values */ 4903be6ef06SEitan Adler if ((negate = (*str == '-')) != 0) 4913be6ef06SEitan Adler { 4923be6ef06SEitan Adler /* move past the minus sign */ 4933be6ef06SEitan Adler str++; 4943be6ef06SEitan Adler } 4953be6ef06SEitan Adler 4963be6ef06SEitan Adler /* use procnum as a temporary holding place and get the number */ 4973be6ef06SEitan Adler procnum = scanint(str, &prio); 4983be6ef06SEitan Adler 4993be6ef06SEitan Adler /* negate if necessary */ 5003be6ef06SEitan Adler if (negate) 5013be6ef06SEitan Adler { 5023be6ef06SEitan Adler prio = -prio; 5033be6ef06SEitan Adler } 5043be6ef06SEitan Adler 5053be6ef06SEitan Adler #if defined(PRIO_MIN) && defined(PRIO_MAX) 5063be6ef06SEitan Adler /* check for validity */ 5073be6ef06SEitan Adler if (procnum == -1 || prio < PRIO_MIN || prio > PRIO_MAX) 5083be6ef06SEitan Adler { 5093be6ef06SEitan Adler return(" bad priority value"); 5103be6ef06SEitan Adler } 5113be6ef06SEitan Adler #endif 5123be6ef06SEitan Adler 5133be6ef06SEitan Adler /* move to the first process number */ 5143be6ef06SEitan Adler if ((str = next_field(str)) == NULL) 5153be6ef06SEitan Adler { 5163be6ef06SEitan Adler return(" no processes specified"); 5173be6ef06SEitan Adler } 5183be6ef06SEitan Adler 5193be6ef06SEitan Adler /* loop thru the process numbers, renicing each one */ 5203be6ef06SEitan Adler do 5213be6ef06SEitan Adler { 5223be6ef06SEitan Adler if (scanint(str, &procnum) == -1) 5233be6ef06SEitan Adler { 5243be6ef06SEitan Adler ERROR(str, 0); 5253be6ef06SEitan Adler } 5263be6ef06SEitan Adler 5273be6ef06SEitan Adler /* check process owner if we're not root */ 5283be6ef06SEitan Adler else if (uid && (uid != proc_owner(procnum))) 5293be6ef06SEitan Adler { 5303be6ef06SEitan Adler ERROR(str, EACCES); 5313be6ef06SEitan Adler } 5323be6ef06SEitan Adler else if (setpriority(PRIO_PROCESS, procnum, prio) == -1) 5333be6ef06SEitan Adler { 5343be6ef06SEitan Adler ERROR(str, errno); 5353be6ef06SEitan Adler } 5363be6ef06SEitan Adler } while ((str = next_field(str)) != NULL); 5373be6ef06SEitan Adler 5383be6ef06SEitan Adler /* return appropriate error string */ 5393be6ef06SEitan Adler return(err_string()); 5403be6ef06SEitan Adler } 5413be6ef06SEitan Adler 542