commit 5df65ecfd4a57fe891eb11e6ccddc6c1949635ca
parent a4de4eb53951718b260fa79ae3535db795e1e6ef
Author: sin <sin@2f30.org>
Date: Wed, 14 Aug 2013 15:38:43 +0100
Add barebones ps(1)
Diffstat:
M | Makefile | | | 10 | ++++++++-- |
A | proc.h | | | 32 | ++++++++++++++++++++++++++++++++ |
A | ps.c | | | 116 | +++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ |
M | util.h | | | 7 | ++++++- |
A | util/agetcwd.c | | | 18 | ++++++++++++++++++ |
A | util/apathmax.c | | | 25 | +++++++++++++++++++++++++ |
A | util/proc.c | | | 73 | +++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ |
A | util/recurse.c | | | 40 | ++++++++++++++++++++++++++++++++++++++++ |
A | util/tty.c | | | 39 | +++++++++++++++++++++++++++++++++++++++ |
9 files changed, 357 insertions(+), 3 deletions(-)
diff --git a/Makefile b/Makefile
@@ -3,11 +3,16 @@ include config.mk
.POSIX:
.SUFFIXES: .c .o
-HDR = arg.h ubase.h util.h
+HDR = arg.h grabmntinfo.h proc.h util.h
LIB = \
+ util/agetcwd.o \
+ util/apathmax.o \
util/eprintf.o \
util/estrtol.o \
- util/grabmntinfo.o
+ util/grabmntinfo.o \
+ util/proc.o \
+ util/recurse.o \
+ util/tty.o
SRC = \
df.c \
@@ -18,6 +23,7 @@ SRC = \
mkswap.c \
mount.c \
pivot_root.c \
+ ps.c \
reboot.c \
rmmod.c \
stat.c \
diff --git a/proc.h b/proc.h
@@ -0,0 +1,32 @@
+/* See LICENSE file for copyright and license details. */
+struct procstat {
+ int pid;
+ char comm[PATH_MAX + 2]; /* + 2 for '(' and ')' */
+ unsigned char state;
+ int ppid;
+ int pgrp;
+ int sid;
+ int tty_nr;
+ int tpgid;
+ unsigned flags;
+ unsigned long minflt;
+ unsigned long cminflt;
+ unsigned long majflt;
+ unsigned long cmajflt;
+ unsigned long utime;
+ unsigned long stime;
+ long cutime;
+ long cstime;
+ long priority;
+ long nice;
+ long num_threads;
+ long itrealvalue;
+ unsigned long long starttime;
+ unsigned long vsize;
+ long rss;
+ long rsslim;
+};
+
+int parsestat(pid_t pid, struct procstat *ps);
+int proceuid(pid_t pid, uid_t *euid);
+int validps(const char *path);
diff --git a/ps.c b/ps.c
@@ -0,0 +1,116 @@
+/* See LICENSE file for copyright and license details. */
+#include <errno.h>
+#include <unistd.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <limits.h>
+#include "proc.h"
+#include "util.h"
+
+static void usage(void);
+static void psout(struct procstat *ps);
+static void psr(const char *path);
+
+enum {
+ PS_aflag = 1 << 0,
+ PS_Aflag = 1 << 1,
+ PS_dflag = 1 << 2
+};
+
+static int flags;
+
+int
+main(int argc, char *argv[])
+{
+ ARGBEGIN {
+ case 'a':
+ flags |= PS_aflag;
+ break;
+ case 'A':
+ flags |= PS_Aflag;
+ break;
+ case 'd':
+ flags |= PS_dflag;
+ break;
+ case 'e':
+ flags |= PS_Aflag;
+ break;
+ case 'f':
+ eprintf("not implemented\n");
+ default:
+ usage();
+ } ARGEND;
+
+ printf(" PID TTY TIME CMD\n");
+ recurse("/proc", psr);
+
+ return 0;
+}
+
+static void
+usage(void)
+{
+ eprintf("usage: [-aAdef] %s\n", argv0);
+}
+
+static void
+psout(struct procstat *ps)
+{
+ char *ttystr, *myttystr;
+ int tty_maj, tty_min;
+ uid_t myeuid, peuid;
+ unsigned sut;
+
+ /* Ignore session leaders */
+ if (flags & PS_dflag)
+ if (ps->pid == ps->sid)
+ return;
+
+ sut = (ps->stime + ps->utime) / 100;
+
+ devtotty(ps->tty_nr, &tty_maj, &tty_min);
+ ttystr = ttytostr(tty_maj, tty_min);
+ /* Only print processes that are associated with
+ * a terminal */
+ if (ttystr[0] == '?' && (flags & PS_aflag)) {
+ free(ttystr);
+ return;
+ }
+
+ if (!flags) {
+ myttystr = ttyname(STDIN_FILENO);
+ if (myttystr) {
+ if (strcmp(myttystr + strlen("/dev/"), ttystr)) {
+ free(ttystr);
+ return;
+ }
+ } else {
+ ttystr[0] = '?';
+ ttystr[1] = '\0';
+ }
+ proceuid(ps->pid, &peuid);
+ myeuid = geteuid();
+ if (myeuid != peuid) {
+ free(ttystr);
+ return;
+ }
+ }
+
+ printf("%5d %-6s %02u:%02u:%02u %s\n", ps->pid, ttystr,
+ sut / 3600, (sut % 3600) / 60, sut % 60, ps->comm);
+ free(ttystr);
+}
+
+static void
+psr(const char *path)
+{
+ struct procstat ps;
+ pid_t pid;
+
+ if (!validps(path))
+ return;
+ pid = estrtol(path, 10);
+ parsestat(pid, &ps);
+ psout(&ps);
+}
diff --git a/util.h b/util.h
@@ -6,6 +6,11 @@
extern char *argv0;
-void eprintf(const char *, ...);
+char *agetcwd(void);
+void apathmax(char **, long *);
+void devtotty(int dev, int *tty_maj, int *tty_min);
void enprintf(int, const char *, ...);
+void eprintf(const char *, ...);
long estrtol(const char *, int);
+void recurse(const char *, void (*)(const char *));
+char *ttytostr(int tty_maj, int tty_min);
diff --git a/util/agetcwd.c b/util/agetcwd.c
@@ -0,0 +1,18 @@
+/* See LICENSE file for copyright and license details. */
+#include <unistd.h>
+
+#include "../util.h"
+
+char *
+agetcwd(void)
+{
+ char *buf;
+ long size;
+
+ apathmax(&buf, &size);
+ if(!getcwd(buf, size))
+ eprintf("getcwd:");
+
+ return buf;
+}
+
diff --git a/util/apathmax.c b/util/apathmax.c
@@ -0,0 +1,25 @@
+/* See LICENSE file for copyright and license details. */
+#include <errno.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <unistd.h>
+
+#include "../util.h"
+
+void
+apathmax(char **p, long *size)
+{
+ errno = 0;
+
+ if((*size = pathconf("/", _PC_PATH_MAX)) == -1) {
+ if(errno == 0) {
+ *size = BUFSIZ;
+ } else {
+ eprintf("pathconf:");
+ }
+ }
+
+ if(!(*p = malloc(*size)))
+ eprintf("malloc:");
+}
+
diff --git a/util/proc.c b/util/proc.c
@@ -0,0 +1,73 @@
+/* See LICENSE file for copyright and license details. */
+#include <unistd.h>
+#include <errno.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <limits.h>
+#include "../proc.h"
+#include "../util.h"
+
+int
+proceuid(pid_t pid, uid_t *euid)
+{
+ FILE *fp;
+ char buf[BUFSIZ], *p;
+ char path[PATH_MAX];
+ uid_t procuid, proceuid;
+
+ snprintf(path, sizeof(path), "/proc/%d/status", pid);
+ if (!(fp = fopen(path, "r")))
+ eprintf("%s fopen:", path);
+ while (fgets(buf, sizeof(buf), fp)) {
+ if (!strncmp(buf, "Uid:", 4)) {
+ p = buf + strlen("Uid:");
+ sscanf(p, "%u %u", &procuid, &proceuid);
+ *euid = proceuid;
+ fclose(fp);
+ return 0;
+ }
+ }
+ fclose(fp);
+ return -1;
+}
+
+int
+parsestat(pid_t pid, struct procstat *ps)
+{
+ char path[PATH_MAX];
+ FILE *fp;
+
+ snprintf(path, sizeof(path), "/proc/%d/stat", pid);
+ if (!(fp = fopen(path, "r")))
+ eprintf("fopen %s:", path);
+ fscanf(fp, "%d %s %c %d %d %d %d %d %u %lu %lu %lu %lu %lu %lu",
+ &ps->pid, ps->comm,
+ &ps->state, &ps->ppid, &ps->pgrp,
+ &ps->sid, &ps->tty_nr, &ps->tpgid, &ps->flags,
+ &ps->minflt, &ps->cminflt, &ps->majflt, &ps->cmajflt,
+ &ps->utime, &ps->stime);
+ fscanf(fp, "%ld %ld %ld %ld %ld %ld %lld %lu %ld %ld",
+ &ps->cutime, &ps->cstime, &ps->priority, &ps->nice,
+ &ps->num_threads, &ps->itrealvalue, &ps->starttime,
+ &ps->vsize, &ps->rss, &ps->rsslim);
+ /* Filter out '(' and ')' from comm */
+ ps->comm[strlen(ps->comm) - 1] = '\0';
+ memmove(ps->comm, ps->comm + 1, strlen(ps->comm));
+ fclose(fp);
+ return 0;
+}
+
+int
+validps(const char *path)
+{
+ char *end;
+
+ errno = 0;
+ strtol(path, &end, 10);
+ if (*end != '\0')
+ return 0;
+ if (errno != 0)
+ return 0;
+ return 1;
+}
diff --git a/util/recurse.c b/util/recurse.c
@@ -0,0 +1,40 @@
+/* See LICENSE file for copyright and license details. */
+#include <dirent.h>
+#include <errno.h>
+#include <stdlib.h>
+#include <string.h>
+#include <unistd.h>
+#include <sys/stat.h>
+
+#include "../util.h"
+
+void
+recurse(const char *path, void (*fn)(const char *))
+{
+ char *cwd;
+ struct dirent *d;
+ struct stat st;
+ DIR *dp;
+
+ if(lstat(path, &st) == -1 || !S_ISDIR(st.st_mode)) {
+ return;
+ } else if(!(dp = opendir(path))) {
+ eprintf("opendir %s:", path);
+ }
+
+ cwd = agetcwd();
+ if(chdir(path) == -1)
+ eprintf("chdir %s:", path);
+
+ while((d = readdir(dp))) {
+ if(strcmp(d->d_name, ".") && strcmp(d->d_name, ".."))
+ fn(d->d_name);
+ }
+
+ closedir(dp);
+ if(chdir(cwd) == -1)
+ eprintf("chdir %s:", cwd);
+
+ free(cwd);
+}
+
diff --git a/util/tty.c b/util/tty.c
@@ -0,0 +1,39 @@
+/* See LICENSE file for copyright and license details. */
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include "../util.h"
+
+void
+devtotty(int dev, int *tty_maj, int *tty_min)
+{
+ *tty_maj = (dev >> 8) & 0xfff;
+ *tty_min = (dev & 0xff) | ((dev >> 12) & 0xfff00);
+}
+
+char *
+ttytostr(int tty_maj, int tty_min)
+{
+ const char *pts = "pts/";
+ const char *tty = "tty/";
+ char *ttystr;
+ size_t len;
+
+ /* Up to 10k ttys */
+ len = strlen(pts) + 4 + 1;
+ ttystr = malloc(len);
+ if (!ttystr)
+ eprintf("malloc:");
+ switch (tty_maj) {
+ case 136:
+ snprintf(ttystr, len, "%s%d", pts, tty_min);
+ break;
+ case 4:
+ snprintf(ttystr, len, "%s%d", tty, tty_min);
+ default:
+ ttystr[0] = '?';
+ ttystr[1] = '\0';
+ break;
+ }
+ return ttystr;
+}