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:
|
.POSIX:
|
||||||
.SUFFIXES: .c .o
|
.SUFFIXES: .c .o
|
||||||
|
|
||||||
HDR = arg.h ubase.h util.h
|
HDR = arg.h grabmntinfo.h proc.h util.h
|
||||||
LIB = \
|
LIB = \
|
||||||
|
util/agetcwd.o \
|
||||||
|
util/apathmax.o \
|
||||||
util/eprintf.o \
|
util/eprintf.o \
|
||||||
util/estrtol.o \
|
util/estrtol.o \
|
||||||
util/grabmntinfo.o
|
util/grabmntinfo.o \
|
||||||
|
util/proc.o \
|
||||||
|
util/recurse.o \
|
||||||
|
util/tty.o
|
||||||
|
|
||||||
SRC = \
|
SRC = \
|
||||||
df.c \
|
df.c \
|
||||||
@ -18,6 +23,7 @@ SRC = \
|
|||||||
mkswap.c \
|
mkswap.c \
|
||||||
mount.c \
|
mount.c \
|
||||||
pivot_root.c \
|
pivot_root.c \
|
||||||
|
ps.c \
|
||||||
reboot.c \
|
reboot.c \
|
||||||
rmmod.c \
|
rmmod.c \
|
||||||
stat.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;
|
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 enprintf(int, const char *, ...);
|
||||||
|
void eprintf(const char *, ...);
|
||||||
long estrtol(const char *, int);
|
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…
x
Reference in New Issue
Block a user