Add barebones ps(1)
This commit is contained in:
parent
a4de4eb539
commit
5df65ecfd4
10
Makefile
10
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 \
|
||||
|
32
proc.h
Normal file
32
proc.h
Normal 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
116
ps.c
Normal 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
7
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);
|
||||
|
18
util/agetcwd.c
Normal file
18
util/agetcwd.c
Normal 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
25
util/apathmax.c
Normal 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
73
util/proc.c
Normal 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
40
util/recurse.c
Normal 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
39
util/tty.c
Normal 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;
|
||||
}
|
Loading…
Reference in New Issue
Block a user