Add barebones ps(1)

This commit is contained in:
sin 2013-08-14 15:38:43 +01:00
parent a4de4eb539
commit 5df65ecfd4
9 changed files with 357 additions and 3 deletions

View File

@ -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 \

32
proc.h Normal file
View File

@ -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);

116
ps.c Normal file
View File

@ -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);
}

7
util.h
View File

@ -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);

18
util/agetcwd.c Normal file
View File

@ -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;
}

25
util/apathmax.c Normal file
View File

@ -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:");
}

73
util/proc.c Normal file
View File

@ -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;
}

40
util/recurse.c Normal file
View File

@ -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);
}

39
util/tty.c Normal file
View File

@ -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;
}