From: Alan Cox Date: Sat, 7 Jul 2018 14:01:19 +0000 (+0100) Subject: ps: make it work like it's supposed to X-Git-Url: https://git.ndcode.org/public/gitweb.cgi?a=commitdiff_plain;h=4d09dfc887ddbc079e11c537e2b9b437aca2ef65;p=FUZIX.git ps: make it work like it's supposed to This still needs work on times, but the kernel needs to catch up first! --- diff --git a/Applications/util/ps.c b/Applications/util/ps.c index fa5d88e2..1501054d 100644 --- a/Applications/util/ps.c +++ b/Applications/util/ps.c @@ -1,20 +1,73 @@ +/* + * An implementation of ps. Rewritten somewhat from the UZIX ps tool. + * + * Deviations from POSIX + * + * -G: not supported + * -u: uses the real uid + * + * The -o option is not supported + * + * Meaningless fields should be '-' but few people do this for all cases + * and the standard is at odds with reality. We use '-' where others do + * but use 0 for things like F. + * + * We show times as dummies until the kernel gets fixed up to put the + * right data in the right places. + * + * Many XSI extensions are not implemented + * + * XSI output formats are produced but not all values are available + * XSI says command data from the kernel not via grovelling in swap + * should be in [] but we don't bother as we don't go digging in swap + * anyway. + * + * BSD ps is a lot nicer in many ways. We should add some BSD functions + * if possible. + * + */ +#include +#include +#include +#include +#include #include #include #include -#include -#include -#include -#define F_a 0x01 /* all users flag */ -#define F_h 0x02 /* no header flag */ -#define F_r 0x04 /* running only flag */ -#define F_n 0x08 /* numeric output flag */ +#define TTY_MAJOR 2 /* Be nice if we didn't have to + just know this */ #define PTABSIZE 128 -int flags; +static uint16_t optflags; +#define F_e 1 /* All */ +#define F_N 2 /* Negate */ +#define F_r 4 /* Running */ +#define F_a 8 /* All associated with terminals */ +#define F_p 16 /* pid match */ +#define F_t 32 /* TTY match */ +#define F_u 64 /* UID match */ +#define F_l 128 /* Long */ -char mapstat(char s) +static uint16_t outflags; +#define OF_F 1 /* Flags (octal/additive) */ +#define OF_S 2 /* State */ +#define OF_UID 4 /* UID */ +#define OF_PID 8 /* PID */ +#define OF_PPID 16 /* PPID */ +#define OF_C 32 /* CPU utilization */ +#define OF_PRI 64 /* Priority bigger is lower */ +#define OF_NI 128 /* Nice value */ +#define OF_ADDR 256 /* Address */ +#define OF_SZ 512 /* Size in core */ +#define OF_WCHAN 1024 /* Wait channel */ +#define OF_STIME 2048 /* Starting time */ +#define OF_TTY 4096 /* Controlling tty */ +#define OF_TIME 8192 /* Cumulative execution time */ +#define OF_CMD 16384 /* Command line */ + +static char mapstat(char s) { switch (s) { case P_ZOMBIE: @@ -36,17 +89,209 @@ char mapstat(char s) } static struct p_tab_buffer ptab[PTABSIZE]; -static int ppid_slot[PTABSIZE]; -static int uid; +static pid_t ppid_slot[PTABSIZE]; +static uid_t uid; +static pid_t pid; +static uint8_t tty; + +static pid_t pid_max = 32767; /* FIXME */ +static uid_t uid_max = 32767; /* FIXME */ + +#define MAXMATCH 16 +struct matchtab { + uint8_t num; + uint16_t match[MAXMATCH]; + const char *type; +}; -void print_header(void) +static struct matchtab pidtab = { + 0, + { 0, }, + "pid" +}; + +static struct matchtab uidtab = { + 0, + { 0, }, + "uid" +}; + +static struct matchtab ttytab = { + 0, + { 0, }, + "tty" +}; + +static int match(struct matchtab *tab, uint16_t match) { - if (!(flags & F_h)) { - if (flags & F_n) - printf(" PID\t PPID\t UID\tSTAT\tWCHAN\tALARM\tCOMMAND\n"); - else - printf("USER\t PID\t PPID\tSTAT\tWCHAN\tALARM\tCOMMAND\n"); + uint16_t *p = tab->match; + uint8_t n = tab->num; + while(n--) { + if (*p++ == match) + return 1; + } + return 0; +} + +static int addmatch(struct matchtab *tab, uint16_t match) +{ + if (tab->num == MAXMATCH) { + fprintf(stderr, "ps: too many %s matches.\n", tab->type); + exit(1); } + tab->match[tab->num++] = match; + return 0; +} + +static uint16_t do_pidmatch(char *arg) +{ + unsigned long n; + errno = 0; + n = strtoul(arg, NULL, 0); + if (errno || n == 0 || n > pid_max) { + fprintf(stderr, "ps: invalid process id.\n"); + exit(1); + } + return n; +} + +static uint16_t do_uidmatch(char *arg) +{ + char *p = arg; + unsigned long n; + struct passwd *pw; + + errno = 0; + n = strtoul(arg, NULL, 0); + if (errno) { + pw = getpwnam(arg); + if (pw == NULL) { + fprintf(stderr, "ps: unknown user '%s'.\n", arg); + exit(1); + } + n = pw->pw_uid; + if (n > uid_max) { + fprintf(stderr, "ps: invalid process id.\n"); + exit(1); + } + } + return n; +} + +static char tbuf[] = "/dev/ttyXXX"; + +static uint16_t do_ttymatch(char *arg) +{ + char *t; + struct stat st; + + t = tbuf; + if (isdigit(*arg)) + strlcpy(tbuf + 8, arg, 3); + else if (strncmp(arg, "tty", 3) == 0) + strlcpy(tbuf + 8, arg + 3, 3); + else + t = arg; + if (stat(t, &st) == -1) { + perror(tbuf); + exit(1); + } + if (major(st.st_rdev) != TTY_MAJOR) { + fprintf(stderr, "%s: not a tty.\n"); + exit(1); + } + return minor(st.st_rdev); +} + +static void scan_match(struct matchtab *m, char *arg, uint16_t (*op)(char *)) +{ + char *p = arg; + char *b; + char *work; + + while((b = strtok_r(p, " \t\n,", &work)) != NULL) { + p = NULL; + addmatch(m, op(b)); + } +} + +static void add_pidmatch(char *arg) +{ + scan_match(&pidtab, arg, do_pidmatch); +} + + +static void add_uidmatch(char *arg) +{ + scan_match(&uidtab, arg, do_uidmatch); +} + +static void add_ttymatch(char *arg) +{ + scan_match(&ttytab, arg, do_ttymatch); +} + +static const char *hdrname[] = { + "F ", + "S ", + " UID ", + " PID ", + " PPID ", + " C ", + "PRI ", + " NI ", + " ADDR ", + " SZ ", + "WCHAN ", + "STIME ", + " TTY ", + " TIME ", + "CMD", + NULL +}; + +static void print_header(void) +{ + uint16_t i = 1; + uint8_t n = 0; + while(hdrname[n]) { + if (outflags & i) + fputs(hdrname[n], stdout); + i <<= 1; + n++; + } + putchar('\n'); +} + +static int compute_show_process(struct p_tab *pp) +{ + /* -e: select all */ + if (optflags & F_e) + return 1; + + /* -a: all associated with a terminal */ + if ((optflags & F_a) && pp->p_tty) + return 1; + + /* -p: PID match */ + if ((optflags & F_p) && match(&pidtab, pp->p_pid)) + return 1; + + /* -u: UID match */ + if ((optflags & F_u) && match(&uidtab, pp->p_uid)) + return 1; + + /* -t: TTY match */ + if ((optflags & F_t) && match(&ttytab, pp->p_tty)) + return 1; + + if ((optflags & F_r) && (pp->p_status != P_RUNNING && pp->p_status != P_READY)) + return 0; + /* Really we want euid but the euid isn't visible */ + if (pp->p_uid == uid && pp->p_tty == tty) + return 1; + + return 0; } int show_process(struct p_tab *pp) @@ -54,39 +299,88 @@ int show_process(struct p_tab *pp) if (pp->p_status == 0) return 0; - if ((flags & F_r) && (pp->p_status != P_RUNNING && pp->p_status != P_READY)) - return 0; + if (optflags & F_N) + return !compute_show_process(pp); + else + return compute_show_process(pp); +} - if (!(flags & F_a) && (pp->p_uid != uid)) - return 0; +static const char *username(uid_t uid) +{ + static char uname[6]; + struct passwd *pwd = getpwuid(uid); + if (pwd) + return pwd->pw_name; + sprintf(uname, "%d", uid); + return uname; +} + +static char tname[7] = "tty"; - return 1; +static const char *ttyshortname(uint8_t tty) +{ + sprintf(tname + 3, "%d", tty); + return tname; } void display_process(struct p_tab *pp, int i) { - struct passwd *pwd; - static char name[10], uname[20]; int j; - strncpy(name, pp->p_name, 8); - name[8] = '\0'; - - for (j = 0; j < 8; ++j) { - if (name[j] != 0) - if (name[j] < ' ') - name[j] = '?'; + if (outflags & OF_F) + fputs("0 ", stdout); + if (outflags & OF_S) { + putchar(mapstat(pp->p_status)); + putchar(' '); } - - if (flags & F_n) { - printf("%5d\t%5d\t%5d\t%c\t%04x\t%-5d\t%s\n", pp->p_pid, ptab[ppid_slot[i]].p_tab.p_pid, pp->p_uid, mapstat(pp->p_status), pp->p_wait, pp->p_alarm, name); - } else { - pwd = getpwuid(pp->p_uid); - if (pwd) - strcpy(uname, pwd->pw_name); + if (outflags & OF_UID) + printf("%5d ", pp->p_uid); + if (outflags & OF_PID) + printf("%5d ", pp->p_pid); + if (outflags & OF_PPID) + printf("%5d ", ptab[ppid_slot[i]].p_tab.p_pid); + if (outflags & OF_C) + fputs(" 0 ", stdout); + if (outflags & OF_PRI) + printf("%3d ", pp->p_priority); + if (outflags & OF_NI) + printf("%3d ", pp->p_nice); + if (outflags & OF_ADDR) + fputs(" - ", stdout); + if (outflags & OF_SZ) + fputs(" - ", stdout); + if (outflags & OF_WCHAN) { + if (pp->p_status > 2) + printf("%5d ", (unsigned int)pp->p_wait); else - sprintf(uname, "%d", pp->p_uid); - printf("%s\t%5d\t%5d\t%c\t%04x\t%-5d\t%s\n", uname, pp->p_pid, ptab[ppid_slot[i]].p_tab.p_pid, mapstat(pp->p_status), pp->p_wait, pp->p_alarm, name); + fputs(" - ", stdout); + } + /* We need to sort out the whole kernel and user handling of + times in ptab verus udata here */ + if (outflags & OF_STIME) + fputs("00:00 ", stdout); /* FIXME */ + if (outflags & OF_TTY) { + if (!pp->p_tty) + fputs(" ? ", stdout); + else + printf("%6s ", ttyshortname(pp->p_tty)); + } + if (outflags & OF_TIME) + fputs("00:00:00 ", stdout); /* FIXME */ + if (outflags & OF_CMD) { + char name[9]; + strncpy(name, pp->p_name, 8); + name[8] = '\0'; + + for (j = 0; j < 8; ++j) { + if (name[j] != 0) + if (name[j] < ' ' || name[j] > 126) + name[j] = '?'; + } + fputs(name, stdout); + if (pp->p_status == P_ZOMBIE) + fputs(" ", stdout); + putchar('\n'); } } @@ -96,7 +390,8 @@ int do_ps(void) struct p_tab_buffer *ppbuf; struct p_tab *pp; - uid = getuid(); + uid = geteuid(); + pid = getpid(); if ((pfd = open("/dev/proc", O_RDONLY)) < 0) { perror("ps"); @@ -130,6 +425,9 @@ int do_ps(void) return 1; } ppid_slot[i] = ptab[i].p_tab.p_pptr - ptab[0].p_tab.p_pptr; + /* Learn our tty internal reference as we go */ + if (ptab[i].p_tab.p_status && ptab[i].p_tab.p_pid == pid) + tty = ptab[i].p_tab.p_tty; } close(pfd); @@ -146,35 +444,69 @@ int do_ps(void) return 0; } -int main(int argc, char *argv[]) +static void usage(void) { - int i; + fputs("usage: ps -[eNr]\n", stderr); + exit(1); +} - flags = 0; - for (i = 1; i < argc; ++i) { - char *p = argv[i]; +int main(int argc, char *argv[]) +{ + int opt; - if (*p == '-') - ++p; - while (*p) - switch (*p++) { + optflags = 0; + outflags = OF_PID|OF_TTY|OF_TIME|OF_CMD; + + while((opt = getopt(argc, argv, "AeaNrp:t:U:u:lf")) != -1) { + switch(opt) { + case 'A': + case 'e': + /* Show everything */ + optflags |= F_e; + break; case 'a': - flags |= F_a; + /* All except session leaders and not + associated with tty. We only do not assoc */ + optflags |= F_a; break; - case 'h': - flags |= F_h; + case 'N': + /* Invert match */ + optflags |= F_N; break; + /* BSDism : keep if doesn't clash */ case 'r': - flags |= F_r; + /* Only running processes */ + optflags |= F_r; + break; + case 'p': + /* Must match this pid */ + optflags |= F_p; + add_pidmatch(optarg); + break; + case 't': + optflags |= F_t; + add_ttymatch(optarg); break; - case 'n': - flags |= F_n; + case 'U': + case 'u': /* -u deviates from the standard */ + optflags |= F_u; + add_uidmatch(optarg); + break; + case 'l': + outflags |= OF_F|OF_S|OF_UID|OF_PID|OF_PPID| + OF_C|OF_PRI|OF_NI|OF_ADDR|OF_SZ| + OF_WCHAN|OF_TTY|OF_TIME|OF_CMD; + break; + case 'f': + outflags |= OF_UID|OF_PID|OF_PPID|OF_C| + OF_STIME|OF_TTY|OF_TIME|OF_CMD; break; default: - fprintf(stderr, "usage: ps [-][ahrn]\n"); - return 1; - } + usage(); + } } + if (optind != argc) + usage(); return do_ps(); }