xref: /netbsd-src/external/bsd/top/dist/commands.c (revision 3120750dcb3d30606964ef4ffaff0fd79f33a7fd)
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