pstree: reimplement in awk, optionally restrict to a given process

This commit is contained in:
qwx 2024-10-30 23:43:47 +00:00
parent 5969b872bb
commit 493bac79b6
3 changed files with 56 additions and 185 deletions

49
rc/bin/pstree Executable file
View file

@ -0,0 +1,49 @@
#!/bin/rc
p=0
if(! ~ $#* 0)
p=$1
cd /proc || exit
ls -d [0-9]* | sort -n | awk -v 'this='^$p '
function cat(f, v){
getline v < f
close(f)
return v
}
BEGIN{
OFS="\t"
}
{
s = cat($1"/args")
if(s == ""){
s = cat($1"/status")
s = substr(s, 1, 27)
gsub(" *", "", s)
}
p = int(cat($1"/ppid"))
child[p,++nchild[p]] = $1
proc[$1] = s
ppid[$1] = p
pid[NR] = $1
}
function out(p, sep, k, m, i, n, c, s){
n = nchild[p]
if(p != 0 && proc[p] != "")
printf "%-11s%s%s%s\n", p, sep, k, proc[p]
s = m > 0 ? "│" : " "
k = "├"
for(i=1; i<=n; i++){
c = child[p,i]
if(i == n)
k = "└"
out(c, sep s, k, n - i)
}
}
END{
for(i=1; i<=length(pid); i++){
p = pid[i]
if(!(ppid[p] in proc) && ppid[p] != 0)
child[0,++nchild[0]] = p
}
out(this, "", "", 0)
}
'

View file

@ -16,6 +16,9 @@ ps, psu, pstree \- process status
]
.PP
.B pstree
[
.I pid
]
.SH DESCRIPTION
.I Ps
prints information about processes.
@ -113,6 +116,9 @@ prints the processes as a tree in a two-column layout where
the first column being the process id and second column
the program name and arguments indented and prefixed with
line drawing runes to reflect the nesting in the hierarchy.
It optionally accepts an argument
.I pid
to only print a tree for the corresponding process.
.SH FILES
.B /proc/*/status
.SH SOURCE
@ -120,7 +126,7 @@ line drawing runes to reflect the nesting in the hierarchy.
.br
.B /rc/bin/psu
.br
.B /sys/src/cmd/pstree.c
.B /rc/bin/pstree
.SH "SEE ALSO"
.IR acid (1),
.IR db (1),

View file

@ -1,184 +0,0 @@
#include <u.h>
#include <libc.h>
#include <bio.h>
typedef struct Proc Proc;
struct Proc {
int pid;
Proc *first, *parent, *next;
Proc *hash;
};
Proc *hash[1024];
Rune buf[512];
Biobuf bout;
Proc *
getproc(int pid)
{
Proc *p;
for(p = hash[pid % nelem(hash)]; p; p = p->hash)
if(p->pid == pid)
return p;
return nil;
}
void
addproc(int pid)
{
Proc *p;
p = mallocz(sizeof(*p), 1);
if(p == nil)
sysfatal("malloc: %r");
p->pid = pid;
p->hash = hash[pid % nelem(hash)];
hash[pid % nelem(hash)] = p;
}
int
theppid(int pid)
{
char b[128];
int fd, ppid;
ppid = 0;
snprint(b, sizeof(b), "%d/ppid", pid);
fd = open(b, OREAD);
if(fd >= 0){
memset(b, 0, sizeof b);
if(read(fd, b, sizeof b-1) >= 0){
ppid = atoi(b);
if(ppid < 0)
ppid = 0;
}
close(fd);
}
return ppid;
}
void
addppid(int pid)
{
Proc *p, *par, **l;
p = getproc(pid);
par = getproc(theppid(pid));
if(par == nil)
par = getproc(0);
p->parent = par;
for(l = &par->first; *l; l = &((*l)->next))
if((*l)->pid > pid)
break;
p->next = *l;
*l = p;
}
void
addprocs(void)
{
int fd, rc, i;
Dir *d;
fd = open(".", OREAD);
if(fd < 0)
sysfatal("open: %r");
rc = dirreadall(fd, &d);
if(rc < 0)
sysfatal("dirreadall: %r");
close(fd);
for(i = 0; i < rc; i++)
if(d[i].mode & DMDIR)
addproc(atoi(d[i].name));
for(i = 0; i < rc; i++)
if(d[i].mode & DMDIR)
addppid(atoi(d[i].name));
free(d);
}
int
readout(char *file)
{
int fd, rc, i, n;
char b[512];
fd = open(file, OREAD);
if(fd < 0)
return -1;
n = 0;
while((rc = read(fd, b, sizeof b)) > 0){
for(i=0; i<rc; i++)
if(b[i] == '\n')
b[i] = ' ';
n += Bwrite(&bout, b, rc);
}
close(fd);
return n;
}
void
printargs(int pid)
{
char b[128], *p;
int fd;
snprint(b, sizeof(b), "%d/args", pid);
if(readout(b) > 0)
return;
snprint(b, sizeof(b), "%d/status", pid);
fd = open(b, OREAD);
if(fd >= 0){
memset(b, 0, sizeof b);
if(read(fd, b, 27) > 0){
p = b + strlen(b);
while(p > b && p[-1] == ' ')
*--p = 0;
Bprint(&bout, "%s", b);
}
close(fd);
}
}
void
descend(Proc *p, Rune *r)
{
Rune last;
Proc *q;
last = *--r;
*r = last == L' ' ? L'' : L'';
if(p->pid != 0){
Bprint(&bout, "%-11d %S", p->pid, buf);
printargs(p->pid);
Bprint(&bout, "\n");
}
*r = last;
*++r = L'';
for(q = p->first; q; q = q->next) {
if(q->next == nil)
*r = L' ';
descend(q, r + 1);
}
*r = 0;
}
void
printprocs(void)
{
descend(getproc(0), buf);
}
void
main()
{
Binit(&bout, 1, OWRITE);
if(chdir("/proc")==-1)
sysfatal("chdir: %r");
addproc(0);
addprocs();
printprocs();
exits(0);
}