110dd2532Schristos /*
210dd2532Schristos * Copyright (c) 1984 through 2008, William LeFebvre
310dd2532Schristos * All rights reserved.
410dd2532Schristos *
510dd2532Schristos * Redistribution and use in source and binary forms, with or without
610dd2532Schristos * modification, are permitted provided that the following conditions are met:
710dd2532Schristos *
810dd2532Schristos * * Redistributions of source code must retain the above copyright
910dd2532Schristos * notice, this list of conditions and the following disclaimer.
1010dd2532Schristos *
1110dd2532Schristos * * Redistributions in binary form must reproduce the above
1210dd2532Schristos * copyright notice, this list of conditions and the following disclaimer
1310dd2532Schristos * in the documentation and/or other materials provided with the
1410dd2532Schristos * distribution.
1510dd2532Schristos *
1610dd2532Schristos * * Neither the name of William LeFebvre nor the names of other
1710dd2532Schristos * contributors may be used to endorse or promote products derived from
1810dd2532Schristos * this software without specific prior written permission.
1910dd2532Schristos *
2010dd2532Schristos * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
2110dd2532Schristos * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
2210dd2532Schristos * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
2310dd2532Schristos * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
2410dd2532Schristos * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
2510dd2532Schristos * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
2610dd2532Schristos * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
2710dd2532Schristos * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
2810dd2532Schristos * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
2910dd2532Schristos * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
3010dd2532Schristos * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
3110dd2532Schristos */
3210dd2532Schristos
3310dd2532Schristos /*
3410dd2532Schristos * Top users/processes display for Unix
3510dd2532Schristos * Version 3
3610dd2532Schristos */
3710dd2532Schristos
3810dd2532Schristos /*
3910dd2532Schristos * This file contains the routines that implement some of the interactive
4010dd2532Schristos * mode commands. Note that some of the commands are implemented in-line
4110dd2532Schristos * in "main". This is necessary because they change the global state of
4210dd2532Schristos * "top" (i.e.: changing the number of processes to display).
4310dd2532Schristos */
4410dd2532Schristos
4510dd2532Schristos #include "os.h"
4610dd2532Schristos #include <ctype.h>
4710dd2532Schristos #include <signal.h>
4810dd2532Schristos #include <stdarg.h>
4910dd2532Schristos #include <unistd.h>
5010dd2532Schristos #include <color.h>
5110dd2532Schristos #include <errno.h>
5210dd2532Schristos #ifdef HAVE_SYS_RESOURCE_H
5310dd2532Schristos #include <sys/resource.h>
5410dd2532Schristos #endif
5510dd2532Schristos
5610dd2532Schristos #if defined(HAVE_DECL_SYS_SIGLIST) & defined(HAVE_STRCASECMP)
5710dd2532Schristos #define USE_SYS_SIGLIST
5810dd2532Schristos #endif
5910dd2532Schristos
6010dd2532Schristos #ifdef USE_SYS_SIGLIST
6110dd2532Schristos extern const char * const sys_siglist[];
6210dd2532Schristos extern const char * const sys_signame[];
6310dd2532Schristos #else
6410dd2532Schristos #include "sigdesc.h" /* generated automatically */
6510dd2532Schristos #endif
6610dd2532Schristos #include "top.h"
6710dd2532Schristos #include "machine.h"
6810dd2532Schristos #include "globalstate.h"
6910dd2532Schristos #include "boolean.h"
7010dd2532Schristos #include "color.h"
7110dd2532Schristos #include "commands.h"
7210dd2532Schristos #include "display.h"
7310dd2532Schristos #include "screen.h"
7410dd2532Schristos #include "username.h"
7510dd2532Schristos #include "utils.h"
7610dd2532Schristos #include "version.h"
7710dd2532Schristos
7810dd2532Schristos extern char *copyright;
7910dd2532Schristos
8010dd2532Schristos typedef struct command {
8110dd2532Schristos int ch;
8210dd2532Schristos int (*cmd_func)(globalstate *);
83213e7ef1Schristos const char *help;
8410dd2532Schristos } command;
8510dd2532Schristos
8610dd2532Schristos /*
8710dd2532Schristos * Some of the commands make system calls that could generate errors.
8810dd2532Schristos * These errors are collected up in an array of structures for later
8910dd2532Schristos * contemplation and display. Such routines return a string containing an
9010dd2532Schristos * error message, or NULL if no errors occurred. We need an upper limit on
9110dd2532Schristos * the number of errors, so we arbitrarily choose 20.
9210dd2532Schristos */
9310dd2532Schristos
9410dd2532Schristos #define ERRMAX 20
9510dd2532Schristos
9610dd2532Schristos struct errs /* structure for a system-call error */
9710dd2532Schristos {
9810dd2532Schristos int errnum; /* value of errno (that is, the actual error) */
9910dd2532Schristos char *arg; /* argument that caused the error */
10010dd2532Schristos };
10110dd2532Schristos
10210dd2532Schristos static struct errs errs[ERRMAX];
10310dd2532Schristos static int errcnt;
10410dd2532Schristos
10510dd2532Schristos /* These macros get used to reset and log the errors */
10610dd2532Schristos #define ERR_RESET errcnt = 0
10710dd2532Schristos #define ERROR(p, e) if (errcnt < ERRMAX) \
10810dd2532Schristos { \
10910dd2532Schristos errs[errcnt].arg = (p); \
11010dd2532Schristos errs[errcnt++].errnum = (e); \
11110dd2532Schristos }
11210dd2532Schristos
11310dd2532Schristos /*
11410dd2532Schristos * err_compar(p1, p2) - comparison routine used by "qsort"
11510dd2532Schristos * for sorting errors.
11610dd2532Schristos */
11710dd2532Schristos
118213e7ef1Schristos static int
err_compar(const void * p1,const void * p2)11910dd2532Schristos err_compar(const void *p1, const void *p2)
12010dd2532Schristos
12110dd2532Schristos {
12210dd2532Schristos register int result;
12310dd2532Schristos
124213e7ef1Schristos if ((result = ((const struct errs *)p1)->errnum -
125213e7ef1Schristos ((const struct errs *)p2)->errnum) == 0)
12610dd2532Schristos {
127213e7ef1Schristos return(strcmp(((const struct errs *)p1)->arg,
128213e7ef1Schristos ((const struct errs *)p2)->arg));
12910dd2532Schristos }
13010dd2532Schristos return(result);
13110dd2532Schristos }
13210dd2532Schristos
13310dd2532Schristos /*
13410dd2532Schristos * str_adderr(str, len, err) - add an explanation of error "err" to
13510dd2532Schristos * the string "str" without overflowing length "len". return
13610dd2532Schristos * number of characters remaining in str, or 0 if overflowed.
13710dd2532Schristos */
13810dd2532Schristos
139213e7ef1Schristos static int
str_adderr(char * str,int len,int err)14010dd2532Schristos str_adderr(char *str, int len, int err)
14110dd2532Schristos
14210dd2532Schristos {
143213e7ef1Schristos register const char *msg;
14410dd2532Schristos register int msglen;
14510dd2532Schristos
14610dd2532Schristos msg = err == 0 ? "Not a number" : errmsg(err);
14710dd2532Schristos msglen = strlen(msg) + 2;
14810dd2532Schristos if (len <= msglen)
14910dd2532Schristos {
15010dd2532Schristos return(0);
15110dd2532Schristos }
15210dd2532Schristos (void) strcat(str, ": ");
15310dd2532Schristos (void) strcat(str, msg);
15410dd2532Schristos return(len - msglen);
15510dd2532Schristos }
15610dd2532Schristos
15710dd2532Schristos /*
15810dd2532Schristos * str_addarg(str, len, arg, first) - add the string argument "arg" to
15910dd2532Schristos * the string "str" without overflowing length "len". This is the
16010dd2532Schristos * first in the group when "first" is set (indicating that a comma
16110dd2532Schristos * should NOT be added to the front). Return number of characters
16210dd2532Schristos * remaining in str, or 0 if overflowed.
16310dd2532Schristos */
16410dd2532Schristos
165213e7ef1Schristos static int
str_addarg(char * str,int len,char * arg,int first)16610dd2532Schristos str_addarg(char *str, int len, char *arg, int first)
16710dd2532Schristos
16810dd2532Schristos {
16910dd2532Schristos register int arglen;
17010dd2532Schristos
17110dd2532Schristos arglen = strlen(arg);
17210dd2532Schristos if (!first)
17310dd2532Schristos {
17410dd2532Schristos arglen += 2;
17510dd2532Schristos }
17610dd2532Schristos if (len <= arglen)
17710dd2532Schristos {
17810dd2532Schristos return(0);
17910dd2532Schristos }
18010dd2532Schristos if (!first)
18110dd2532Schristos {
18210dd2532Schristos (void) strcat(str, ", ");
18310dd2532Schristos }
18410dd2532Schristos (void) strcat(str, arg);
18510dd2532Schristos return(len - arglen);
18610dd2532Schristos }
18710dd2532Schristos
18810dd2532Schristos /*
18910dd2532Schristos * void err_string()
19010dd2532Schristos *
19110dd2532Schristos * Use message_error to log errors in the errs array. This function
19210dd2532Schristos * will combine identical errors to make the message short, but if
19310dd2532Schristos * there is more than one type of error it will call message_error
19410dd2532Schristos * for each one.
19510dd2532Schristos */
19610dd2532Schristos
19710dd2532Schristos #define STRMAX 80
19810dd2532Schristos
199213e7ef1Schristos static void
err_string(void)200213e7ef1Schristos err_string(void)
20110dd2532Schristos
20210dd2532Schristos {
20310dd2532Schristos register struct errs *errp;
20410dd2532Schristos register int cnt = 0;
20510dd2532Schristos register int first = Yes;
20610dd2532Schristos register int currerr = -1;
20710dd2532Schristos int stringlen = 0; /* characters still available in "string" */
20810dd2532Schristos char string[STRMAX];
20910dd2532Schristos
21010dd2532Schristos /* if there are no errors, our job is easy */
21110dd2532Schristos if (errcnt == 0)
21210dd2532Schristos {
21310dd2532Schristos return;
21410dd2532Schristos }
21510dd2532Schristos
21610dd2532Schristos /* sort the errors */
21710dd2532Schristos qsort((char *)errs, errcnt, sizeof(struct errs), err_compar);
21810dd2532Schristos
21910dd2532Schristos /* initialize the buffer (probably not necessary) */
22010dd2532Schristos string[0] = '\0';
22110dd2532Schristos stringlen = STRMAX - 1;
22210dd2532Schristos
22310dd2532Schristos /* loop thru the sorted list, logging errors */
22410dd2532Schristos while (cnt < errcnt)
22510dd2532Schristos {
22610dd2532Schristos /* point to the current error */
22710dd2532Schristos errp = &(errs[cnt++]);
22810dd2532Schristos
22910dd2532Schristos /* note that on overflow "stringlen" will become 0 and all
23010dd2532Schristos subsequent calls to str_addarg or str_adderr will return 0 */
23110dd2532Schristos
23210dd2532Schristos /* if the error number is different then add the error string */
23310dd2532Schristos if (errp->errnum != currerr)
23410dd2532Schristos {
23510dd2532Schristos if (currerr != -1)
23610dd2532Schristos {
23710dd2532Schristos /* add error string and log the error */
23810dd2532Schristos stringlen = str_adderr(string, stringlen, currerr);
23910dd2532Schristos message_error(" %s", string);
24010dd2532Schristos
24110dd2532Schristos }
24210dd2532Schristos /* reset the buffer */
24310dd2532Schristos string[0] = '\0';
24410dd2532Schristos stringlen = STRMAX - 1;
24510dd2532Schristos
24610dd2532Schristos /* move to next error num */
24710dd2532Schristos currerr = errp->errnum;
24810dd2532Schristos first = Yes;
24910dd2532Schristos }
25010dd2532Schristos
25110dd2532Schristos /* add this arg */
25210dd2532Schristos stringlen = str_addarg(string, stringlen, errp->arg, first);
25310dd2532Schristos first = No;
25410dd2532Schristos }
25510dd2532Schristos
25610dd2532Schristos /* add final message */
25710dd2532Schristos stringlen = str_adderr(string, stringlen, currerr);
25810dd2532Schristos
25910dd2532Schristos /* write the error string */
26010dd2532Schristos message_error(" %s", string);
26110dd2532Schristos }
26210dd2532Schristos
26310dd2532Schristos /*
26410dd2532Schristos * Utility routines that help with some of the commands.
26510dd2532Schristos */
26610dd2532Schristos
267213e7ef1Schristos static char *
next_field(char * str)26810dd2532Schristos next_field(char *str)
26910dd2532Schristos
27010dd2532Schristos
27110dd2532Schristos {
27210dd2532Schristos if ((str = strchr(str, ' ')) == NULL)
27310dd2532Schristos {
27410dd2532Schristos return(NULL);
27510dd2532Schristos }
27610dd2532Schristos *str = '\0';
27710dd2532Schristos while (*++str == ' ') /* loop */;
27810dd2532Schristos
27910dd2532Schristos /* if there is nothing left of the string, return NULL */
28010dd2532Schristos /* This fix is dedicated to Greg Earle */
28110dd2532Schristos return(*str == '\0' ? NULL : str);
28210dd2532Schristos }
28310dd2532Schristos
284213e7ef1Schristos static int
scanint(char * str,int * intp)28510dd2532Schristos scanint(char *str, int *intp)
28610dd2532Schristos
28710dd2532Schristos {
28810dd2532Schristos register int val = 0;
28910dd2532Schristos register int ch;
29010dd2532Schristos
29110dd2532Schristos /* if there is nothing left of the string, flag it as an error */
29210dd2532Schristos /* This fix is dedicated to Greg Earle */
29310dd2532Schristos if (*str == '\0')
29410dd2532Schristos {
29510dd2532Schristos return(-1);
29610dd2532Schristos }
29710dd2532Schristos
29810dd2532Schristos while ((ch = *str++) != '\0')
29910dd2532Schristos {
30010dd2532Schristos if (isdigit(ch))
30110dd2532Schristos {
30210dd2532Schristos val = val * 10 + (ch - '0');
30310dd2532Schristos }
30410dd2532Schristos else if (isspace(ch))
30510dd2532Schristos {
30610dd2532Schristos break;
30710dd2532Schristos }
30810dd2532Schristos else
30910dd2532Schristos {
31010dd2532Schristos return(-1);
31110dd2532Schristos }
31210dd2532Schristos }
31310dd2532Schristos *intp = val;
31410dd2532Schristos return(0);
31510dd2532Schristos }
31610dd2532Schristos
317213e7ef1Schristos #ifdef notdef
31810dd2532Schristos /*
31910dd2532Schristos * error_count() - return the number of errors currently logged.
32010dd2532Schristos */
32110dd2532Schristos
322213e7ef1Schristos static int
error_count(void)323213e7ef1Schristos error_count(void)
32410dd2532Schristos
32510dd2532Schristos {
32610dd2532Schristos return(errcnt);
32710dd2532Schristos }
32810dd2532Schristos
32910dd2532Schristos /*
33010dd2532Schristos * show_errors() - display on stdout the current log of errors.
33110dd2532Schristos */
33210dd2532Schristos
333213e7ef1Schristos static void
show_errors(void)334213e7ef1Schristos show_errors(void)
33510dd2532Schristos
33610dd2532Schristos {
33710dd2532Schristos register int cnt = 0;
33810dd2532Schristos register struct errs *errp = errs;
33910dd2532Schristos
34010dd2532Schristos printf("%d error%s:\n\n", errcnt, errcnt == 1 ? "" : "s");
34110dd2532Schristos while (cnt++ < errcnt)
34210dd2532Schristos {
34310dd2532Schristos printf("%5s: %s\n", errp->arg,
34410dd2532Schristos errp->errnum == 0 ? "Not a number" : errmsg(errp->errnum));
34510dd2532Schristos errp++;
34610dd2532Schristos }
34710dd2532Schristos }
348213e7ef1Schristos #endif
34910dd2532Schristos
35010dd2532Schristos /*
35110dd2532Schristos * kill_procs(str) - send signals to processes, much like the "kill"
35210dd2532Schristos * command does; invoked in response to 'k'.
35310dd2532Schristos */
35410dd2532Schristos
355213e7ef1Schristos static void
kill_procs(char * str)35610dd2532Schristos kill_procs(char *str)
35710dd2532Schristos
35810dd2532Schristos {
35910dd2532Schristos register char *nptr;
36010dd2532Schristos int signum = SIGTERM; /* default */
36110dd2532Schristos int procnum;
36210dd2532Schristos int uid;
36310dd2532Schristos int owner;
36410dd2532Schristos #ifndef USE_SYS_SIGLIST
36510dd2532Schristos struct sigdesc *sigp;
36610dd2532Schristos #endif
36710dd2532Schristos
36810dd2532Schristos /* reset error array */
36910dd2532Schristos ERR_RESET;
37010dd2532Schristos
37110dd2532Schristos /* remember our uid */
37210dd2532Schristos uid = getuid();
37310dd2532Schristos
37410dd2532Schristos /* skip over leading white space */
37510dd2532Schristos while (isspace((int)*str)) str++;
37610dd2532Schristos
37710dd2532Schristos if (str[0] == '-')
37810dd2532Schristos {
37910dd2532Schristos /* explicit signal specified */
38010dd2532Schristos if ((nptr = next_field(str)) == NULL)
38110dd2532Schristos {
38210dd2532Schristos message_error(" kill: no processes specified");
38310dd2532Schristos return;
38410dd2532Schristos }
38510dd2532Schristos
38610dd2532Schristos str++;
38710dd2532Schristos if (isdigit((int)str[0]))
38810dd2532Schristos {
38910dd2532Schristos (void) scanint(str, &signum);
39010dd2532Schristos if (signum <= 0 || signum >= NSIG)
39110dd2532Schristos {
39210dd2532Schristos message_error(" kill: invalid signal number");
39310dd2532Schristos return;
39410dd2532Schristos }
39510dd2532Schristos }
39610dd2532Schristos else
39710dd2532Schristos {
39810dd2532Schristos /* translate the name into a number */
39910dd2532Schristos #ifdef USE_SYS_SIGLIST
40010dd2532Schristos for (signum = 1; signum < NSIG; signum++)
40110dd2532Schristos {
40210dd2532Schristos if (strcasecmp(sys_signame[signum], str) == 0)
40310dd2532Schristos {
40410dd2532Schristos break;
40510dd2532Schristos }
40610dd2532Schristos }
40710dd2532Schristos if (signum == NSIG)
40810dd2532Schristos {
40910dd2532Schristos message_error(" kill: bad signal name");
41010dd2532Schristos return;
41110dd2532Schristos }
41210dd2532Schristos #else
41310dd2532Schristos for (sigp = sigdesc; sigp->name != NULL; sigp++)
41410dd2532Schristos {
41510dd2532Schristos #ifdef HAVE_STRCASECMP
41610dd2532Schristos if (strcasecmp(sigp->name, str) == 0)
41710dd2532Schristos #else
41810dd2532Schristos if (strcmp(sigp->name, str) == 0)
41910dd2532Schristos #endif
42010dd2532Schristos {
42110dd2532Schristos signum = sigp->number;
42210dd2532Schristos break;
42310dd2532Schristos }
42410dd2532Schristos }
42510dd2532Schristos
42610dd2532Schristos /* was it ever found */
42710dd2532Schristos if (sigp->name == NULL)
42810dd2532Schristos {
42910dd2532Schristos message_error(" kill: bad signal name");
43010dd2532Schristos return;
43110dd2532Schristos }
43210dd2532Schristos #endif
43310dd2532Schristos }
43410dd2532Schristos /* put the new pointer in place */
43510dd2532Schristos str = nptr;
43610dd2532Schristos }
43710dd2532Schristos
43810dd2532Schristos /* loop thru the string, killing processes */
43910dd2532Schristos do
44010dd2532Schristos {
44110dd2532Schristos if (scanint(str, &procnum) == -1)
44210dd2532Schristos {
44310dd2532Schristos ERROR(str, 0);
44410dd2532Schristos }
44510dd2532Schristos else
44610dd2532Schristos {
44710dd2532Schristos /* check process owner if we're not root */
44810dd2532Schristos owner = proc_owner(procnum);
44910dd2532Schristos if (uid && (uid != owner))
45010dd2532Schristos {
45110dd2532Schristos ERROR(str, owner == -1 ? ESRCH : EACCES);
45210dd2532Schristos }
45310dd2532Schristos /* go in for the kill */
45410dd2532Schristos else if (kill(procnum, signum) == -1)
45510dd2532Schristos {
45610dd2532Schristos /* chalk up an error */
45710dd2532Schristos ERROR(str, errno);
45810dd2532Schristos }
45910dd2532Schristos }
46010dd2532Schristos } while ((str = next_field(str)) != NULL);
46110dd2532Schristos
46210dd2532Schristos /* process errors */
46310dd2532Schristos err_string();
46410dd2532Schristos }
46510dd2532Schristos
46610dd2532Schristos /*
46710dd2532Schristos * renice_procs(str) - change the "nice" of processes, much like the
46810dd2532Schristos * "renice" command does; invoked in response to 'r'.
46910dd2532Schristos */
47010dd2532Schristos
471213e7ef1Schristos static void
renice_procs(char * str)47210dd2532Schristos renice_procs(char *str)
47310dd2532Schristos
47410dd2532Schristos {
47510dd2532Schristos register char negate;
47610dd2532Schristos int prio;
47710dd2532Schristos int procnum;
47810dd2532Schristos int uid;
47910dd2532Schristos
48010dd2532Schristos ERR_RESET;
48110dd2532Schristos uid = getuid();
48210dd2532Schristos
48310dd2532Schristos /* allow for negative priority values */
48410dd2532Schristos if ((negate = (*str == '-')) != 0)
48510dd2532Schristos {
48610dd2532Schristos /* move past the minus sign */
48710dd2532Schristos str++;
48810dd2532Schristos }
48910dd2532Schristos
49010dd2532Schristos /* use procnum as a temporary holding place and get the number */
49110dd2532Schristos procnum = scanint(str, &prio);
49210dd2532Schristos
49310dd2532Schristos /* negate if necessary */
49410dd2532Schristos if (negate)
49510dd2532Schristos {
49610dd2532Schristos prio = -prio;
49710dd2532Schristos }
49810dd2532Schristos
49910dd2532Schristos #if defined(PRIO_MIN) && defined(PRIO_MAX)
50010dd2532Schristos /* check for validity */
50110dd2532Schristos if (procnum == -1 || prio < PRIO_MIN || prio > PRIO_MAX)
50210dd2532Schristos {
50310dd2532Schristos message_error(" renice: bad priority value");
5042b60e3f2Schristos return;
50510dd2532Schristos }
50610dd2532Schristos #endif
50710dd2532Schristos
50810dd2532Schristos /* move to the first process number */
50910dd2532Schristos if ((str = next_field(str)) == NULL)
51010dd2532Schristos {
511*3120750dSsnj message_error(" renice: no processes specified");
5122b60e3f2Schristos return;
51310dd2532Schristos }
51410dd2532Schristos
51510dd2532Schristos #ifdef HAVE_SETPRIORITY
51610dd2532Schristos /* loop thru the process numbers, renicing each one */
51710dd2532Schristos do
51810dd2532Schristos {
51910dd2532Schristos if (scanint(str, &procnum) == -1)
52010dd2532Schristos {
52110dd2532Schristos ERROR(str, 0);
52210dd2532Schristos }
52310dd2532Schristos
52410dd2532Schristos /* check process owner if we're not root */
52510dd2532Schristos else if (uid && (uid != proc_owner(procnum)))
52610dd2532Schristos {
52710dd2532Schristos ERROR(str, EACCES);
52810dd2532Schristos }
52910dd2532Schristos else if (setpriority(PRIO_PROCESS, procnum, prio) == -1)
53010dd2532Schristos {
53110dd2532Schristos ERROR(str, errno);
53210dd2532Schristos }
53310dd2532Schristos } while ((str = next_field(str)) != NULL);
53410dd2532Schristos err_string();
53510dd2532Schristos #else
53610dd2532Schristos message_error(" renice operation not supported");
53710dd2532Schristos #endif
53810dd2532Schristos }
53910dd2532Schristos
54010dd2532Schristos /* COMMAND ROUTINES */
54110dd2532Schristos
54210dd2532Schristos /*
54310dd2532Schristos * Each command routine is called by command_process and is passed a
54410dd2532Schristos * pointer to the current global state. Command routines are free
54510dd2532Schristos * to change anything in the global state, although changes to the
54610dd2532Schristos * statics structure are discouraged. Whatever a command routine
54710dd2532Schristos * returns will be returned by command_process.
54810dd2532Schristos */
54910dd2532Schristos
550213e7ef1Schristos static void
cmd_quit(globalstate * gstate)55110dd2532Schristos cmd_quit(globalstate *gstate)
55210dd2532Schristos
55310dd2532Schristos {
55410dd2532Schristos quit(EX_OK);
55510dd2532Schristos /*NOTREACHED*/
55610dd2532Schristos }
55710dd2532Schristos
558213e7ef1Schristos static int
cmd_update(globalstate * gstate)55910dd2532Schristos cmd_update(globalstate *gstate)
56010dd2532Schristos
56110dd2532Schristos {
56210dd2532Schristos /* go home for visual feedback */
56310dd2532Schristos screen_home();
56410dd2532Schristos fflush(stdout);
56510dd2532Schristos message_expire();
56610dd2532Schristos return CMD_REFRESH;
56710dd2532Schristos }
56810dd2532Schristos
569213e7ef1Schristos static int
cmd_redraw(globalstate * gstate)57010dd2532Schristos cmd_redraw(globalstate *gstate)
57110dd2532Schristos
57210dd2532Schristos {
57310dd2532Schristos gstate->fulldraw = Yes;
57410dd2532Schristos return CMD_REFRESH;
57510dd2532Schristos }
57610dd2532Schristos
577213e7ef1Schristos static int
cmd_color(globalstate * gstate)57810dd2532Schristos cmd_color(globalstate *gstate)
57910dd2532Schristos
58010dd2532Schristos {
58110dd2532Schristos gstate->use_color = color_activate(-1);
58210dd2532Schristos gstate->fulldraw = Yes;
58310dd2532Schristos return CMD_REFRESH;
58410dd2532Schristos }
58510dd2532Schristos
586213e7ef1Schristos static int
cmd_number(globalstate * gstate)58710dd2532Schristos cmd_number(globalstate *gstate)
58810dd2532Schristos
58910dd2532Schristos {
59010dd2532Schristos int newval;
59110dd2532Schristos char tmpbuf[20];
59210dd2532Schristos
59310dd2532Schristos message_prompt("Number of processes to show: ");
59410dd2532Schristos newval = readline(tmpbuf, 8, Yes);
59510dd2532Schristos if (newval > -1)
59610dd2532Schristos {
59710dd2532Schristos if (newval > gstate->max_topn)
59810dd2532Schristos {
59910dd2532Schristos message_error(" This terminal can only display %d processes",
60010dd2532Schristos gstate->max_topn);
60110dd2532Schristos }
60210dd2532Schristos
60310dd2532Schristos if (newval == 0)
60410dd2532Schristos {
60510dd2532Schristos /* inhibit the header */
60610dd2532Schristos display_header(No);
60710dd2532Schristos }
60810dd2532Schristos
60910dd2532Schristos else if (gstate->topn == 0)
61010dd2532Schristos {
61110dd2532Schristos display_header(Yes);
61210dd2532Schristos }
61310dd2532Schristos
61410dd2532Schristos gstate->topn = newval;
61510dd2532Schristos }
61610dd2532Schristos return CMD_REFRESH;
61710dd2532Schristos }
61810dd2532Schristos
619213e7ef1Schristos static int
cmd_delay(globalstate * gstate)62010dd2532Schristos cmd_delay(globalstate *gstate)
62110dd2532Schristos
62210dd2532Schristos {
623a8f5847fSchristos double newval;
62410dd2532Schristos char tmpbuf[20];
62510dd2532Schristos
62610dd2532Schristos message_prompt("Seconds to delay: ");
627a8f5847fSchristos if (readline(tmpbuf, 8, No) > 0)
62810dd2532Schristos {
629a8f5847fSchristos newval = atof(tmpbuf);
630a8f5847fSchristos if (newval == 0 && getuid() != 0)
63110dd2532Schristos {
63210dd2532Schristos gstate->delay = 1;
63310dd2532Schristos }
634a8f5847fSchristos else
635a8f5847fSchristos {
636a8f5847fSchristos gstate->delay = newval;
637a8f5847fSchristos }
63810dd2532Schristos }
63910dd2532Schristos return CMD_REFRESH;
64010dd2532Schristos }
64110dd2532Schristos
642213e7ef1Schristos static int
cmd_idle(globalstate * gstate)64310dd2532Schristos cmd_idle(globalstate *gstate)
64410dd2532Schristos
64510dd2532Schristos {
64610dd2532Schristos gstate->pselect.idle = !gstate->pselect.idle;
64710dd2532Schristos message_error(" %sisplaying idle processes.",
64810dd2532Schristos gstate->pselect.idle ? "D" : "Not d");
64910dd2532Schristos return CMD_REFRESH;
65010dd2532Schristos }
65110dd2532Schristos
652213e7ef1Schristos static int
cmd_displays(globalstate * gstate)65310dd2532Schristos cmd_displays(globalstate *gstate)
65410dd2532Schristos
65510dd2532Schristos {
65610dd2532Schristos int i;
65710dd2532Schristos char tmpbuf[20];
65810dd2532Schristos
65910dd2532Schristos message_prompt("Displays to show (currently %s): ",
66010dd2532Schristos gstate->displays == -1 ? "infinite" :
66110dd2532Schristos itoa(gstate->displays));
66210dd2532Schristos
66310dd2532Schristos if ((i = readline(tmpbuf, 10, Yes)) > 0)
66410dd2532Schristos {
66510dd2532Schristos gstate->displays = i;
66610dd2532Schristos }
66710dd2532Schristos else if (i == 0)
66810dd2532Schristos {
66910dd2532Schristos quit(EX_OK);
67010dd2532Schristos /*NOTREACHED*/
67110dd2532Schristos }
67210dd2532Schristos return CMD_OK;
67310dd2532Schristos }
67410dd2532Schristos
675213e7ef1Schristos static int
cmd_cmdline(globalstate * gstate)67610dd2532Schristos cmd_cmdline(globalstate *gstate)
67710dd2532Schristos
67810dd2532Schristos {
67910dd2532Schristos if (gstate->statics->flags.fullcmds)
68010dd2532Schristos {
68110dd2532Schristos gstate->pselect.fullcmd = !gstate->pselect.fullcmd;
68210dd2532Schristos message_error(" %sisplaying full command lines.",
68310dd2532Schristos gstate->pselect.fullcmd ? "D" : "Not d");
68410dd2532Schristos return CMD_REFRESH;
68510dd2532Schristos }
68610dd2532Schristos message_error(" Full command display not supported.");
68710dd2532Schristos return CMD_OK;
68810dd2532Schristos }
68910dd2532Schristos
690213e7ef1Schristos static int
cmd_order(globalstate * gstate)69110dd2532Schristos cmd_order(globalstate *gstate)
69210dd2532Schristos
69310dd2532Schristos {
69410dd2532Schristos char tmpbuf[MAX_COLS];
69510dd2532Schristos int i;
69610dd2532Schristos
69710dd2532Schristos if (gstate->statics->order_names != NULL)
69810dd2532Schristos {
69910dd2532Schristos message_prompt("Column to sort: ");
70010dd2532Schristos if (readline(tmpbuf, sizeof(tmpbuf), No) > 0)
70110dd2532Schristos {
70210dd2532Schristos if ((i = string_index(tmpbuf, gstate->statics->order_names)) == -1)
70310dd2532Schristos {
70410dd2532Schristos message_error(" Sort order \"%s\" not recognized", tmpbuf);
70510dd2532Schristos }
70610dd2532Schristos else
70710dd2532Schristos {
70810dd2532Schristos gstate->order_index = i;
70910dd2532Schristos return CMD_REFRESH;
71010dd2532Schristos }
71110dd2532Schristos }
71210dd2532Schristos }
71310dd2532Schristos return CMD_OK;
71410dd2532Schristos }
71510dd2532Schristos
716213e7ef1Schristos static int
cmd_order_x(globalstate * gstate,const char * name,...)717213e7ef1Schristos cmd_order_x(globalstate *gstate, const char *name, ...)
71810dd2532Schristos
71910dd2532Schristos {
72010dd2532Schristos va_list ap;
72110dd2532Schristos char *p;
722213e7ef1Schristos const char **names;
72310dd2532Schristos int i;
72410dd2532Schristos
72510dd2532Schristos names = gstate->statics->order_names;
72610dd2532Schristos if (names != NULL)
72710dd2532Schristos {
72810dd2532Schristos if ((i = string_index(name, names)) == -1)
72910dd2532Schristos {
73010dd2532Schristos /* check the alternate list */
73110dd2532Schristos va_start(ap, name);
73210dd2532Schristos p = va_arg(ap, char *);
73310dd2532Schristos while (p != NULL)
73410dd2532Schristos {
73510dd2532Schristos if ((i = string_index(p, names)) != -1)
73610dd2532Schristos {
73710dd2532Schristos gstate->order_index = i;
73810dd2532Schristos return CMD_REFRESH;
73910dd2532Schristos }
74010dd2532Schristos p = va_arg(ap, char *);
74110dd2532Schristos }
74210dd2532Schristos message_error(" Sort order not recognized");
74310dd2532Schristos }
74410dd2532Schristos else
74510dd2532Schristos {
74610dd2532Schristos gstate->order_index = i;
74710dd2532Schristos return CMD_REFRESH;
74810dd2532Schristos }
74910dd2532Schristos }
75010dd2532Schristos return CMD_OK;
75110dd2532Schristos }
75210dd2532Schristos
753213e7ef1Schristos static int
cmd_order_cpu(globalstate * gstate)75410dd2532Schristos cmd_order_cpu(globalstate *gstate)
75510dd2532Schristos
75610dd2532Schristos {
75710dd2532Schristos return cmd_order_x(gstate, "cpu", NULL);
75810dd2532Schristos }
75910dd2532Schristos
760213e7ef1Schristos static int
cmd_order_pid(globalstate * gstate)76110dd2532Schristos cmd_order_pid(globalstate *gstate)
76210dd2532Schristos
76310dd2532Schristos {
76410dd2532Schristos return cmd_order_x(gstate, "pid", NULL);
76510dd2532Schristos }
76610dd2532Schristos
767213e7ef1Schristos static int
cmd_order_mem(globalstate * gstate)76810dd2532Schristos cmd_order_mem(globalstate *gstate)
76910dd2532Schristos
77010dd2532Schristos {
77110dd2532Schristos return cmd_order_x(gstate, "mem", "size", NULL);
77210dd2532Schristos }
77310dd2532Schristos
774213e7ef1Schristos static int
cmd_order_time(globalstate * gstate)77510dd2532Schristos cmd_order_time(globalstate *gstate)
77610dd2532Schristos
77710dd2532Schristos {
77810dd2532Schristos return cmd_order_x(gstate, "time");
77910dd2532Schristos }
78010dd2532Schristos
78110dd2532Schristos #ifdef ENABLE_KILL
78210dd2532Schristos
783213e7ef1Schristos static int
cmd_kill(globalstate * gstate)78410dd2532Schristos cmd_kill(globalstate *gstate)
78510dd2532Schristos
78610dd2532Schristos {
78710dd2532Schristos char tmpbuf[MAX_COLS];
78810dd2532Schristos
78910dd2532Schristos message_prompt_plain("kill ");
79010dd2532Schristos if (readline(tmpbuf, sizeof(tmpbuf), No) > 0)
79110dd2532Schristos {
79210dd2532Schristos kill_procs(tmpbuf);
79310dd2532Schristos }
79410dd2532Schristos return CMD_OK;
79510dd2532Schristos }
79610dd2532Schristos
797213e7ef1Schristos static int
cmd_renice(globalstate * gstate)79810dd2532Schristos cmd_renice(globalstate *gstate)
79910dd2532Schristos
80010dd2532Schristos {
80110dd2532Schristos char tmpbuf[MAX_COLS];
80210dd2532Schristos
80310dd2532Schristos message_prompt_plain("renice ");
80410dd2532Schristos if (readline(tmpbuf, sizeof(tmpbuf), No) > 0)
80510dd2532Schristos {
80610dd2532Schristos renice_procs(tmpbuf);
80710dd2532Schristos }
80810dd2532Schristos return CMD_OK;
80910dd2532Schristos }
81010dd2532Schristos
81110dd2532Schristos #endif
81210dd2532Schristos
813213e7ef1Schristos static int
cmd_pid(globalstate * gstate)81414f5b40fSchristos cmd_pid(globalstate *gstate)
81514f5b40fSchristos
81614f5b40fSchristos {
81714f5b40fSchristos char tmpbuf[MAX_COLS];
81814f5b40fSchristos
81914f5b40fSchristos message_prompt_plain("select pid ");
82014f5b40fSchristos gstate->pselect.pid = -1;
82114f5b40fSchristos if (readline(tmpbuf, sizeof(tmpbuf), No) > 0)
82214f5b40fSchristos {
82314f5b40fSchristos int pid;
82414f5b40fSchristos if (scanint(tmpbuf, &pid) == 0)
82514f5b40fSchristos gstate->pselect.pid = pid;
82614f5b40fSchristos }
82714f5b40fSchristos return CMD_OK;
82814f5b40fSchristos }
82914f5b40fSchristos
830213e7ef1Schristos static int
cmd_user(globalstate * gstate)83110dd2532Schristos cmd_user(globalstate *gstate)
83210dd2532Schristos
83310dd2532Schristos {
83410dd2532Schristos char linebuf[MAX_COLS];
83510dd2532Schristos int i;
83610dd2532Schristos int ret = CMD_OK;
83710dd2532Schristos
83810dd2532Schristos message_prompt("Username to show: ");
83910dd2532Schristos if (readline(linebuf, sizeof(linebuf), No) > 0)
84010dd2532Schristos {
84110dd2532Schristos if (linebuf[0] == '+' &&
84210dd2532Schristos linebuf[1] == '\0')
84310dd2532Schristos {
84410dd2532Schristos gstate->pselect.uid = -1;
84510dd2532Schristos ret = CMD_REFRESH;
84610dd2532Schristos }
84710dd2532Schristos else if ((i = userid(linebuf)) == -1)
84810dd2532Schristos {
84910dd2532Schristos message_error(" %s: unknown user", linebuf);
85010dd2532Schristos }
85110dd2532Schristos else
85210dd2532Schristos {
85310dd2532Schristos gstate->pselect.uid = i;
85410dd2532Schristos ret = CMD_REFRESH;
85510dd2532Schristos }
85610dd2532Schristos }
85710dd2532Schristos return ret;
85810dd2532Schristos }
85910dd2532Schristos
860213e7ef1Schristos static int
cmd_command(globalstate * gstate)86110dd2532Schristos cmd_command(globalstate *gstate)
86210dd2532Schristos
86310dd2532Schristos {
86410dd2532Schristos char linebuf[MAX_COLS];
86510dd2532Schristos
86610dd2532Schristos if (gstate->pselect.command != NULL)
86710dd2532Schristos {
86810dd2532Schristos free(gstate->pselect.command);
86910dd2532Schristos gstate->pselect.command = NULL;
87010dd2532Schristos }
87110dd2532Schristos
87210dd2532Schristos message_prompt("Command to show: ");
87310dd2532Schristos if (readline(linebuf, sizeof(linebuf), No) > 0)
87410dd2532Schristos {
87510dd2532Schristos if (linebuf[0] != '\0')
87610dd2532Schristos {
87756a682bfSchristos gstate->pselect.command = estrdup(linebuf);
87810dd2532Schristos }
87910dd2532Schristos }
88010dd2532Schristos return CMD_REFRESH;
88110dd2532Schristos }
88210dd2532Schristos
883213e7ef1Schristos static int
cmd_useruid(globalstate * gstate)88410dd2532Schristos cmd_useruid(globalstate *gstate)
88510dd2532Schristos
88610dd2532Schristos {
88710dd2532Schristos gstate->pselect.usernames = !gstate->pselect.usernames;
88810dd2532Schristos display_header(2);
88910dd2532Schristos return CMD_REFRESH;
89010dd2532Schristos }
89110dd2532Schristos
892213e7ef1Schristos static int
cmd_mode(globalstate * gstate)89310dd2532Schristos cmd_mode(globalstate *gstate)
89410dd2532Schristos
89510dd2532Schristos {
89610dd2532Schristos if (gstate->statics->modemax <= 1)
89710dd2532Schristos {
89810dd2532Schristos return CMD_NA;
89910dd2532Schristos }
90010dd2532Schristos gstate->pselect.mode = (gstate->pselect.mode + 1) % gstate->statics->modemax;
90110dd2532Schristos display_header(2);
90210dd2532Schristos return CMD_REFRESH;
90310dd2532Schristos }
90410dd2532Schristos
905213e7ef1Schristos static int
cmd_system(globalstate * gstate)90610dd2532Schristos cmd_system(globalstate *gstate)
90710dd2532Schristos
90810dd2532Schristos {
90910dd2532Schristos gstate->pselect.system = !gstate->pselect.system;
91010dd2532Schristos display_header(2);
91110dd2532Schristos return CMD_REFRESH;
91210dd2532Schristos }
91310dd2532Schristos
914213e7ef1Schristos static int
cmd_threads(globalstate * gstate)91510dd2532Schristos cmd_threads(globalstate *gstate)
91610dd2532Schristos
91710dd2532Schristos {
91810dd2532Schristos if (gstate->statics->flags.threads)
91910dd2532Schristos {
92010dd2532Schristos gstate->pselect.threads = !gstate->pselect.threads;
92110dd2532Schristos display_header(2);
92210dd2532Schristos return CMD_REFRESH;
92310dd2532Schristos }
92410dd2532Schristos return CMD_NA;
92510dd2532Schristos }
92610dd2532Schristos
927213e7ef1Schristos static int
cmd_percpustates(globalstate * gstate)9282b60e3f2Schristos cmd_percpustates(globalstate *gstate)
9292b60e3f2Schristos {
9302b60e3f2Schristos gstate->percpustates = !gstate->percpustates;
9312b60e3f2Schristos gstate->fulldraw = Yes;
9322b60e3f2Schristos gstate->max_topn += display_setmulti(gstate->percpustates);
9332b60e3f2Schristos return CMD_REFRESH;
9342b60e3f2Schristos }
9352b60e3f2Schristos
9362b60e3f2Schristos
93710dd2532Schristos /* forward reference for cmd_help, as it needs to see the command_table */
93810dd2532Schristos int cmd_help(globalstate *gstate);
93910dd2532Schristos
94010dd2532Schristos /* command table */
94110dd2532Schristos command command_table[] = {
94210dd2532Schristos { '\014', cmd_redraw, "redraw screen" },
94310dd2532Schristos { ' ', cmd_update, "update screen" },
94410dd2532Schristos { '?', cmd_help, "help; show this text" },
94510dd2532Schristos { 'h', cmd_help, NULL },
946e02c5b57Ssborrill { '1', cmd_percpustates, "toggle the display of cpu states per cpu" },
94710dd2532Schristos { 'C', cmd_color, "toggle the use of color" },
94810dd2532Schristos { 'H', cmd_threads, "toggle the display of individual threads" },
94910dd2532Schristos { 't', cmd_threads, NULL },
95010dd2532Schristos { 'M', cmd_order_mem, "sort by memory usage" },
95110dd2532Schristos { 'N', cmd_order_pid, "sort by process id" },
95210dd2532Schristos { 'P', cmd_order_cpu, "sort by CPU usage" },
95310dd2532Schristos { 'S', cmd_system, "toggle the display of system processes" },
95410dd2532Schristos { 'T', cmd_order_time, "sort by CPU time" },
95510dd2532Schristos { 'U', cmd_useruid, "toggle the display of usernames or uids" },
95610dd2532Schristos { 'c', cmd_command, "display processes by command name" },
95710dd2532Schristos { 'd', cmd_displays, "change number of displays to show" },
95810dd2532Schristos { 'f', cmd_cmdline, "toggle the display of full command paths" },
95910dd2532Schristos { 'i', cmd_idle, "toggle the displaying of idle processes" },
96010dd2532Schristos { 'I', cmd_idle, NULL },
96110dd2532Schristos #ifdef ENABLE_KILL
96210dd2532Schristos { 'k', cmd_kill, "kill processes; send a signal to a list of processes" },
96310dd2532Schristos #endif
96410dd2532Schristos { 'm', cmd_mode, "toggle between display modes" },
96510dd2532Schristos { 'n', cmd_number, "change number of processes to display" },
96610dd2532Schristos { '#', cmd_number, NULL },
96710dd2532Schristos { 'o', cmd_order, "specify sort order (see below)" },
96814f5b40fSchristos { 'p', cmd_pid, "select a single pid" },
96910dd2532Schristos { 'q', (int (*)(globalstate *))cmd_quit, "quit" },
97010dd2532Schristos #ifdef ENABLE_KILL
97110dd2532Schristos { 'r', cmd_renice, "renice a process" },
97210dd2532Schristos #endif
97310dd2532Schristos { 's', cmd_delay, "change number of seconds to delay between updates" },
97410dd2532Schristos { 'u', cmd_user, "display processes for only one user (+ selects all users)" },
97510dd2532Schristos { '\0', NULL, NULL },
97610dd2532Schristos };
97710dd2532Schristos
97810dd2532Schristos int
cmd_help(globalstate * gstate)97910dd2532Schristos cmd_help(globalstate *gstate)
98010dd2532Schristos
98110dd2532Schristos {
98210dd2532Schristos command *c;
98310dd2532Schristos char buf[12];
98410dd2532Schristos char *p;
985213e7ef1Schristos const char *help;
98610dd2532Schristos
98710dd2532Schristos display_pagerstart();
98810dd2532Schristos
98910dd2532Schristos display_pager("Top version %s, %s\n", version_string(), copyright);
99010dd2532Schristos display_pager("Platform module: %s\n\n", MODULE);
99110dd2532Schristos display_pager("A top users display for Unix\n\n");
99210dd2532Schristos display_pager("These single-character commands are available:\n\n");
99310dd2532Schristos
99410dd2532Schristos c = command_table;
99510dd2532Schristos while (c->cmd_func != NULL)
99610dd2532Schristos {
99710dd2532Schristos /* skip null help strings */
99810dd2532Schristos if ((help = c->help) == NULL)
99910dd2532Schristos {
100010dd2532Schristos continue;
100110dd2532Schristos }
100210dd2532Schristos
100310dd2532Schristos /* translate character in to something readable */
100410dd2532Schristos if (c->ch < ' ')
100510dd2532Schristos {
100610dd2532Schristos buf[0] = '^';
100710dd2532Schristos buf[1] = c->ch + '@';
100810dd2532Schristos buf[2] = '\0';
100910dd2532Schristos }
101010dd2532Schristos else if (c->ch == ' ')
101110dd2532Schristos {
101210dd2532Schristos strcpy(buf, "<sp>");
101310dd2532Schristos }
101410dd2532Schristos else
101510dd2532Schristos {
101610dd2532Schristos buf[0] = c->ch;
101710dd2532Schristos buf[1] = '\0';
101810dd2532Schristos }
101910dd2532Schristos
102010dd2532Schristos /* if the next command is the same, fold them onto one line */
102110dd2532Schristos if ((c+1)->cmd_func == c->cmd_func)
102210dd2532Schristos {
102310dd2532Schristos strcat(buf, " or ");
102410dd2532Schristos p = buf + strlen(buf);
102510dd2532Schristos *p++ = (c+1)->ch;
102610dd2532Schristos *p = '\0';
102710dd2532Schristos c++;
102810dd2532Schristos }
102910dd2532Schristos
103010dd2532Schristos display_pager("%-7s - %s\n", buf, help);
103110dd2532Schristos c++;
103210dd2532Schristos }
103310dd2532Schristos
103410dd2532Schristos display_pager("\nNot all commands are available on all systems.\n\n");
103510dd2532Schristos display_pager("Available sort orders: %s\n", gstate->order_namelist);
103610dd2532Schristos display_pagerend();
103710dd2532Schristos gstate->fulldraw = Yes;
103810dd2532Schristos return CMD_REFRESH;
103910dd2532Schristos }
104010dd2532Schristos
104110dd2532Schristos /*
104210dd2532Schristos * int command_process(globalstate *gstate, int cmd)
104310dd2532Schristos *
104410dd2532Schristos * Process the single-character command "cmd". The global state may
104510dd2532Schristos * be modified by the command to alter the output. Returns CMD_ERROR
104610dd2532Schristos * if there was a serious error that requires an immediate exit, CMD_OK
104710dd2532Schristos * to indicate success, CMD_REFRESH to indicate that the screen needs
104810dd2532Schristos * to be refreshed immediately, CMD_UNKNOWN when the command is not known,
104910dd2532Schristos * and CMD_NA when the command is not available. Error messages for
105010dd2532Schristos * CMD_NA and CMD_UNKNOWN must be handled by the caller.
105110dd2532Schristos */
105210dd2532Schristos
105310dd2532Schristos int
command_process(globalstate * gstate,int cmd)105410dd2532Schristos command_process(globalstate *gstate, int cmd)
105510dd2532Schristos
105610dd2532Schristos {
105710dd2532Schristos command *c;
105810dd2532Schristos
105910dd2532Schristos c = command_table;
106010dd2532Schristos while (c->cmd_func != NULL)
106110dd2532Schristos {
106210dd2532Schristos if (c->ch == cmd)
106310dd2532Schristos {
106410dd2532Schristos return (c->cmd_func)(gstate);
106510dd2532Schristos }
106610dd2532Schristos c++;
106710dd2532Schristos }
106810dd2532Schristos
106910dd2532Schristos return CMD_UNKNOWN;
107010dd2532Schristos }
1071