From 63537704d1fe9431a4473773c0635d34d052bfdb Mon Sep 17 00:00:00 2001 From: Martin Mares Date: Fri, 26 Sep 1997 20:25:30 +0000 Subject: [PATCH] Initial revision --- Makefile | 11 ++ ywho.c | 580 +++++++++++++++++++++++++++++++++++++++++++++++++++++++ 2 files changed, 591 insertions(+) create mode 100644 Makefile create mode 100644 ywho.c diff --git a/Makefile b/Makefile new file mode 100644 index 0000000..3d997d0 --- /dev/null +++ b/Makefile @@ -0,0 +1,11 @@ +# Makefile for YWHO + +ywho: ywho.c + gcc -s -N -O2 -m486 -fomit-frame-pointer -Wall -Wno-parentheses ywho.c -o ywho + +clean: + rm *.o ywho + +install: + strip ywho + mv ywho /usr/local/bin diff --git a/ywho.c b/ywho.c new file mode 100644 index 0000000..568ed64 --- /dev/null +++ b/ywho.c @@ -0,0 +1,580 @@ +/* + * Extended `who' command, version 1.3. + * + * (c) 1996 Martin Mares + * + * 1.3 (16-96-96) - idle derived from atime instead of mtime. + * - displaying of current command fixed. + */ + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#undef DEBUG + +struct procrec { + struct procrec *next; + int pid, ppid, pgrp, sess; + int usr, state; + time_t ctim, tim; + char cmd_line[34]; + }; + +static struct procrec *first_procrec; + +struct utrec { + struct utrec *next; + pid_t login_pid; + char line_id[4]; + time_t login_time, click_time, total_time; + char user_name[UT_NAMESIZE+1]; + int usr; + char host_name[17]; + char line_name[12]; + int mesg, detach; + struct procrec *proc; + }; + +static struct utrec *first_utrec; +static int usercnt, zombies; +static time_t now; + +static void * +xmalloc(int i) +{ +void *z; + z = malloc(i); + if (!z) + { + fprintf(stderr, "xwho: out of memory!\n"); + exit(1); + } + return z; +} + +static void +strcpy_padded(char *to, char *from, int size) +{ + memcpy(to, from, size); + to[size] = 0; +} + +static void +readutmp(void) +{ +static struct utmp *ut; +static struct passwd *pw; + utmpname(UTMP_FILE); + while (ut = getutent()) + if (ut->ut_type == USER_PROCESS && ut->ut_user[0]) + { + struct utrec *u = xmalloc(sizeof(struct utrec)); + struct stat st; + char device[32]; + u->next = first_utrec; + first_utrec = u; + u->login_pid = ut->ut_pid; + u->line_id[0] = ut->ut_id[0]; + u->line_id[1] = ut->ut_id[1]; + u->line_id[2] = 0; + u->login_time = ut->ut_time; + strcpy_padded(u->user_name, ut->ut_user, UT_NAMESIZE); + pw = getpwnam(u->user_name); + if (pw) + u->usr = pw->pw_uid; + else + u->usr = -1; + strcpy_padded(u->host_name, ut->ut_host, 16); + strcpy(u->line_name, ut->ut_line); + if (!u->line_id[0]) + { + char *z = u->line_name; + if (!strncmp(u->line_name, "tty", 3)) + z += 3; + strncpy(u->line_id, z, 3); + u->line_id[3] = 0; + } + strcpy(device, "/dev/"); + strcat(device, u->line_name); + if (stat(device, &st)) + u->mesg = 2; + else + { + u->mesg = !!(S_IWOTH & st.st_mode); + u->click_time = st.st_atime; + if (u->click_time < st.st_atime) + u->click_time = st.st_atime; + if (u->click_time < st.st_ctime) + u->click_time = st.st_ctime; + } + u->detach = 0; + usercnt++; +#ifdef DEBUG + printf("UT %s %s %d %d\n", u->user_name, u->host_name, + u->usr, u->login_pid); +#endif + } + endutent(); +} + +static void +puttime(int s) +{ +int d, h, m; + if (s < 100) + printf("%4ds", s); + else + { + m = s/60; + s %= 60; + h = m/60; + m %= 60; + if (h < 100) + printf("%02d.%02d", h, m); + else + { + d = h/24; + h %= 24; + if (d < 100) + printf("%2dd%02d", d, h); + else + printf("%4dd", d); + } + } +} + +static void +memory(unsigned int i) +{ + if (i < 1000) + printf("%dB", i); + else + { + i = (i+511)/1024; + if (i < 1000) + printf("%dK", i); + else + { + i = (i+511)/1024; + if (i < 1000) + printf("%dM", i); + else + printf("%dG", (i+511U)/1024U); + } + } +} + +static void +dispsys(void) +{ +FILE *f; +char line[256], a[32], b[32], c[32]; +char *z, *w; + w = NULL; + if (f = fopen("/proc/version", "r")) + { + fgets(line, 256, f); + z = strchr(line, '('); + if (z) + { + while (z != line && z[-1] == ' ') + z--; + } + else + z = line + strlen(line) - 1; + *z = 0; + z = strstr(line, " version"); + if (z) + memmove(z, z+8, strlen(z+8)+1); + printf(line); + fclose(f); + } + if (f = fopen("/proc/cpuinfo", "r")) + { + strcpy(a, "???"); + b[0] = 0; + c[0] = 0; + for(;;) + { + fgets(line, 256, f); + if (feof(f)) + break; + if (!strncmp(line, "cpu\t\t: ", 7)) + { + z = line+7; + w = a; + } + else if (!strncmp(line, "model\t\t: ", 9)) + { + z = line+9; + w = b; + } + else if (!strncmp(line, "mask\t\t: ", 8)) + { + z = line+8; + w = c; + } + else + z = NULL; + if (z) + { + line[strlen(line)-1] = 0; + strcpy(w, z); + if (!strcmp(w, "Unknown")) + w[0] = 0; + } + } + printf(" on %s", a); + if (*b) + printf("-%s", b); + if (*c) + printf("-%s", c); + fclose(f); + } + if (f = fopen("/proc/uptime", "r")) + { + int p,q,p1,q1; + fgets(line, 256, f); + sscanf(line, "%d.%d%d.%d", &p, &p1, &q, &q1); + printf(", up "); + puttime(p); + printf(", run "); + puttime(p-q); + fclose(f); + } + { + struct tm *tm; + now = time(NULL); + tm = localtime(&now); + printf(" at %02d-%02d-%02d/%d %02d.%02d:%02d\n", tm->tm_mday, tm->tm_mon+1, + tm->tm_year, (tm->tm_wday+6)%7, tm->tm_hour, tm->tm_min, tm->tm_sec); + } + if (f = fopen("/proc/loadavg", "r")) + { + int i = 3; + fgets(line, 256, f); + *strchr(line, '\n') = 0; + z = line-1; + while (i-- && z) + { + *z = '/'; + z = strchr(z, ' '); + } + if (z) + { + char *k; + *z++ = 0; + k = strchr(z, ' '); + if (k) + *k = 0; + printf("R/T=%s, ", z); + } + else + z = line; + printf("LAV=%s", line); + fclose(f); + } + if (f = fopen("/proc/meminfo", "r")) + { + int total, used, free, shared, buffers, totals, useds, frees; + fgets(line, 256, f); + fgets(line, 256, f); + sscanf(line, "Mem:%d%d%d%d%d", &total, &used, &free, &shared, &buffers); + fgets(line, 256, f); + sscanf(line, "Swap:%d%d%d", &totals, &useds, &frees); + printf(", free "); + memory(free+buffers); + printf(" of RAM"); + if (useds) + { + printf(", used "); + memory(useds); + printf(" of swap"); + } + } + printf(", %d user%s.\n", usercnt, usercnt == 1 ? "" : "s"); +} + +static void +readproc(void) +{ +DIR *d; +struct dirent *e; + if (d = opendir("/proc")) + { + while (e = readdir(d)) + { + int i; + sscanf(e->d_name, "%d", &i); + if (i) + { + struct procrec *p = xmalloc(sizeof(struct procrec)); + struct stat st; + char name[256], eman[1024]; + int fil; + p->pid = i; + strcpy(name, "/proc/"); + strcat(name, e->d_name); + if (!stat(name, &st)) + { + p->next = first_procrec; + first_procrec = p; + p->usr = st.st_uid; + strcpy(eman, name); + strcat(eman, "/cmdline"); + if ((fil = open(eman, O_RDONLY)) >= 0) + { + int z = read(fil, p->cmd_line, 33); + if (z < 0) + z = 0; + p->cmd_line[z] = 0xff; + close(fil); + } + strcpy(eman, name); + strcat(eman, "/stat"); + if ((fil = open(eman, O_RDONLY)) >= 0) + { + int z = read(fil, eman, 1023); + char *k; + int trash, utim, stim, cutim, cstim; + if (z < 0) + z = 0; + eman[z] = 0; + k = strchr(eman, ')'); + if (k) + { + p->state = k[1]; + if (p->state == 'Z') + zombies++; + sscanf(k+3, "%d%d%d%d%d%d%d%d%d%d%d%d%d%d", + &p->ppid, &p->pgrp, &p->sess, &trash, &trash, + &trash, &trash, &trash, &trash, &trash, &utim, + &stim, &cutim, &cstim); + } + p->tim = utim + stim; + p->ctim = cutim + cstim; + close(fil); + } + } + } + } + closedir(d); + } + else + { + perror("unable to scan /proc"); + exit(1); + } +} + +static void +solve(void) +{ +struct utrec *u = first_utrec; +struct procrec *m, *n, *o, *q; +struct passwd *pw; + while (u) + { + m = first_procrec; + while (m && m->pid != u->login_pid) + m = m->next; + o = m; + if (m) + { + retry: + n = first_procrec; + q = o; + while (n) + { + if (q->sess == n->sess) + n->usr = -1; + if (q->pid == n->ppid && n->usr == -1) + { + o = n; + goto retry; + } + n = n->next; + } + } + u->proc = o; + if (m) + u->total_time = m->ctim; +#ifdef DEBUG + if (o) + { + printf("%s %s\n", u->user_name, o->cmd_line); + } +#endif + u = u->next; + } + for(u=first_utrec; u; u=u->next) + { + for(m=first_procrec; m; m=m->next) + if (u->usr == m->usr) + { + m->usr = -1; + u->detach++; +#ifdef DEBUG + printf("** %s %s\n", u->user_name, m->cmd_line); +#endif + } + } + for(m=first_procrec; m; m=m->next) + if (m->usr >= 2 && m->ppid == 1) /* Exclude no_user,root,bin */ + { + for(u=first_utrec; u; u=u->next) + if (u->usr == m->usr) + break; + if (!u) + { + u = xmalloc(sizeof(struct utrec)); + u->next = first_utrec; + first_utrec = u; + u->login_pid = 0; + u->line_id[0] = 0; + pw = getpwuid(u->usr = m->usr); + if (pw) + strcpy(u->user_name, pw->pw_name); + else + sprintf(u->user_name, "<%d>", m->usr); + u->host_name[0] = 0; + u->line_name[0] = 0; + u->mesg = 3; + u->detach = 0; + u->proc = NULL; + u->total_time = 0; + } + if (!u->proc) + u->proc = m; + u->total_time += m->ctim; + u->detach ++; +#ifdef DEBUG + printf("// %s %s\n", u->user_name, m->cmd_line); +#endif + } +} + +static inline int +comp(struct utrec *a, struct utrec *b) +{ +int k; + if (b->mesg == 3) + return -1; + k = strcmp(a->user_name, b->user_name); + if (k) + return k; + if (!a->host_name[0] && b->host_name[0]) + return -1; + return strcmp(a->line_id, b->line_id); +} + +static void +sort(void) +{ +struct utrec *fi = NULL; +struct utrec *z, **y, **m, **l; + l = &fi; + while (first_utrec) + { + y = &first_utrec; + m = y; + while (z = *y) + { + if (comp(z, *m) < 0) + m = y; + y = &z->next; + } + z = *m; + *m = z->next; + *l = z; + z->next = NULL; + l = &z->next; + } + first_utrec = fi; +} + +static void +show(void) +{ +struct utrec *u; +int i; +unsigned char *c; + printf("Name Li MD From LogT IdleT RunT Command\n"); + for(u=first_utrec; u; u=u->next) + { + if (!u->line_id[1]) + { + if (u->line_id[0]) + { + u->line_id[1] = u->line_id[0]; + u->line_id[0] = 'c'; + } + else + u->line_id[0] = u->line_id[1] = '-'; + } + printf("%-8.8s %-3s %c%c %-17.17s ", + u->user_name, + u->line_id, + u->mesg ? ' ' : '-', + u->detach ? 'D' : ' ', + u->host_name); + if (u->mesg <= 1) + { + if (u->login_time > now) + u->login_time = now; + puttime(now - u->login_time); + putchar(' '); + if (u->click_time > now) + u->click_time = now; + if (now - u->click_time >= 60) + puttime(now - u->click_time); + else + printf(" "); + } + else + printf("????? "); + if (u->proc) + { + putchar(' '); + puttime((unsigned)u->total_time/(unsigned)HZ); + putchar(' '); + i = 24; + c = u->proc->cmd_line; + while (*c != 0xff && i--) + { + putchar(*c ? *c : ' '); + c++; + } + } + else + printf(" "); + putchar('\n'); + } +} + +int main(void) +{ + readutmp(); + dispsys(); + readproc(); + solve(); + sort(); + show(); + if (zombies) + { + printf("There %s %d zombie%s walking around.", + zombies == 1 ? "is" : "are", + zombies, + zombies == 1 ? "" : "s" ); + } + return 0; +} -- 2.39.2