Book a Demo!
CoCalc Logo Icon
StoreFeaturesDocsShareSupportNewsAboutPoliciesSign UpSign In
att
GitHub Repository: att/ast
Path: blob/master/src/cmd/std/ps.c
1808 views
1
/***********************************************************************
2
* *
3
* This software is part of the ast package *
4
* Copyright (c) 1989-2011 AT&T Intellectual Property *
5
* and is licensed under the *
6
* Eclipse Public License, Version 1.0 *
7
* by AT&T Intellectual Property *
8
* *
9
* A copy of the License is available at *
10
* http://www.eclipse.org/org/documents/epl-v10.html *
11
* (with md5 checksum b35adb5213ca9657e911e9befb180842) *
12
* *
13
* Information and Software Systems Research *
14
* AT&T Research *
15
* Florham Park NJ *
16
* *
17
* Glenn Fowler <[email protected]> *
18
* *
19
***********************************************************************/
20
#pragma prototyped
21
/*
22
* Glenn Fowler
23
* AT&T Research
24
*
25
* ps -- list process status
26
*
27
* fall back to /bin/ps if no support -- and you better match their args!
28
*/
29
30
#define FIELDS_default "pid,tty,time,comm"
31
#define FIELDS_c "pid,class,pri,tty,time,comm"
32
#define FIELDS_f "user,pid,ppid,start,tty,time,cmd"
33
#define FIELDS_j "pid,pgrp,sid,tty,time,comm"
34
#define FIELDS_l "flags,state,user,pid,ppid,pri,nice,size,rss,wchan,tty,time,cmd"
35
36
static const char usage[] =
37
"[-1o?\n@(#)$Id: ps (AT&T Research) 2011-12-13 $\n]"
38
USAGE_LICENSE
39
"[+NAME?ps - report process status]"
40
"[+DESCRIPTION?\bps\b lists process information subject to the appropriate"
41
" privilege. If \apid\a arguments are specified then only those"
42
" processes are listed, otherwise all processes with the effective"
43
" user id and controlling terminal of the caller are listed. The options"
44
" may alter this default behavior.]"
45
"[+?The listings are sorted by <\bUID,START,PID\b>. Options taking list"
46
" arguments accept either space or comma separators.]"
47
48
"[a:interactive?List all processes associated with terminals.]"
49
"[B!:branch?Print tree branch prefixes for \bcommand\b and \bargs\b."
50
" Implied by \b--children\b, \b--parents\b, and \b--tree\b.]"
51
"[c:class?Equivalent to \b--fields=" FIELDS_c "\b.]"
52
"[C:children?Display the process tree hierarchy, including the children"
53
" of all selected processes, in the \bCMD\b field list.]"
54
"[d:no-session?List all processes except session leaders.]"
55
"[D:define?Define \akey\a with optional \avalue\a. \avalue\a will be expanded"
56
" when \b%(\b\akey\a\b)\b is specified in \b--format\b. \akey\a may"
57
" override internal \b--format\b identifiers.]:[key[=value]]]"
58
"[e|A:all?List all processes.]"
59
"[E!:escape?Escape non-printing characters in \bcommand\b and \bargs\b.]"
60
"[f:full?Equivalent to \b--fields=" FIELDS_f "\b.]"
61
"[F:format?Append to the listing format string (if \b--format\b is specified"
62
" then \b--fields\b and all options that modify \b--fields\b are"
63
" ignored.) The \bdf\b(1), \bls\b(1) and \bpax\b(1) commands also have"
64
" \b--format\b options in this same style. \aformat\a follows"
65
" \bprintf\b(3) conventions, except that \bsfio\b(3) inline ids are used"
66
" instead of arguments:"
67
" %[#-+]][\awidth\a[.\aprecis\a[.\abase\a]]]]]](\aid\a[:\aheading\a]])\achar\a."
68
" If \b#\b is specified then the internal width and precision are used."
69
" If \achar\a is \bs\b then the string form of the item is listed,"
70
" otherwise the corresponding numeric form is listed. If \achar\a is"
71
" \bq\b then the string form of the item is $'...' quoted if it contains"
72
" space or non-printing characters. If \awidth\a is omitted then the"
73
" default width is assumed. \aheading\a overrides the default"
74
" heading for \aid\a. Supported \aid\as"
75
" are:]:[format]{\fformats\f}"
76
"[g:pgrps|process-groups?List processes with group leaders in the \apgrp\a"
77
" list.]:[pgrp...]"
78
"[G:groups?List processes with real group id names or numbers in the \agroup\a"
79
" list.]:[group...]"
80
"[h!:heading?Output a heading line.]"
81
"[j:jobs?Equivalent to \b--fields=" FIELDS_j "\b.]"
82
"[l:long?Equivalent to \b--fields=" FIELDS_l "\b.]"
83
"[L:leaders?List session leaders.]"
84
"[n:namelist?Specifies an alternate system namelist \afile\a. Ignored by"
85
" this implementation.]"
86
"[N:default?Equivalent to \b--fields=" FIELDS_default "\b. This is the"
87
" format when \b--fields\b is not specified.]"
88
"[o:fields?(\b--format\b is more general.) List information according to"
89
" \akey\a. Multiple \b--fields\b options may be specified; the"
90
" resulting format is a left-right ordered list with duplicate entries"
91
" deleted from the right. The default width can be overriden by"
92
" appending \a+width\a to \akey\a, and the default \alabel\a can be"
93
" overridden by appending \a=label\a to \akey\a. The keys, labels and"
94
" widths are listed under \b--format\b.]:[key[+width]][=label]]...]"
95
"[p:pids?List processes in the \apid\a list.]:[pid...]"
96
"[P:parents?Display the process tree hierarchy, including the parents"
97
" of all selected processes, in the \bCMD\b field list.]"
98
"[r|R:recursive?Recursively list the children of all selected processes.]"
99
"[s:sessions?List processes with session leaders in the \asid\a list.]:[sid...]"
100
"[t:terminals|ttys?List processes with controlling terminals in the \atty\a"
101
" list.]:[tty...]"
102
"[T:tree|forest?Display the process tree hierarchy, including the parents and"
103
" children of all selected processes, in the \bCMD\b field list.]"
104
"[u|U:users?List processes with real user id names or numbers in the \auser\a"
105
" list.]:[user...]"
106
"[v:verbose?List verbose error messages for inaccessible processes.]"
107
"[w:wide?Ignored by this implementation.]"
108
"[x:detached?List all processes not associated with terminals.]"
109
"[X:hex?List numeric entries in hexadecimal notation.]"
110
111
"\n"
112
"\n[ pid ... ]\n"
113
"\n"
114
115
"[+SEE ALSO?\bdf\b(1), \bkill\b(1), \bls\b(1), \bnice\b(1), \bpax\b(1),"
116
" \bps\b(1), \bsh\b(1), \btop\b(1)]"
117
;
118
119
#include <ast.h>
120
#include <ast_dir.h>
121
#include <cdt.h>
122
#include <ctype.h>
123
#include <dirent.h>
124
#include <error.h>
125
#include <ls.h>
126
#include <pss.h>
127
#include <sfdisc.h>
128
#include <tm.h>
129
130
#if !_mem_st_rdev_stat
131
#define st_rdev st_dev
132
#endif
133
134
#define KEY_environ (-1)
135
#define KEY_alias 0
136
137
#define KEY_addr 1
138
#define KEY_class 2
139
#define KEY_cmd 3
140
#define KEY_comm 4
141
#define KEY_cpu 5
142
#define KEY_etime 6
143
#define KEY_flags 7
144
#define KEY_gid 8
145
#define KEY_group 9
146
#define KEY_job 10
147
#define KEY_nice 11
148
#define KEY_npid 12
149
#define KEY_pgrp 13
150
#define KEY_pid 14
151
#define KEY_ppid 15
152
#define KEY_pri 16
153
#define KEY_proc 17
154
#define KEY_refcount 18
155
#define KEY_rss 19
156
#define KEY_sid 20
157
#define KEY_size 21
158
#define KEY_start 22
159
#define KEY_state 23
160
#define KEY_tgrp 24
161
#define KEY_time 25
162
#define KEY_tty 26
163
#define KEY_uid 27
164
#define KEY_user 28
165
#define KEY_wchan 29
166
167
typedef struct Key_s /* format key */
168
{
169
char* name; /* key name */
170
char* head; /* heading name */
171
char* desc; /* description */
172
unsigned long field; /* pss field */
173
short index; /* index */
174
short width; /* field width */
175
unsigned long maxval; /* max value if !=0 */
176
unsigned char hex; /* optional hex output */
177
unsigned char already; /* already specified */
178
short cancel; /* cancel this if specified */
179
short prec; /* field precision */
180
short disable; /* macro being expanded */
181
unsigned char skip; /* skip this */
182
char* macro; /* macro value */
183
const char* sep; /* next field separator */
184
Dtlink_t hashed; /* hash link */
185
struct Key_s* next; /* format link */
186
} Key_t;
187
188
typedef struct List_s /* pid list */
189
{
190
struct List_s* next; /* next in list */
191
char** argv; /* , separated string vector */
192
int argc; /* elementsof(argv) */
193
} List_t;
194
195
typedef struct Ps_s /* process state */
196
{
197
Dtlink_t hashed; /* pid hash link */
198
Dtlink_t sorted; /* sorted link */
199
Pssent_t* ps; /* ps info */
200
struct Ps_s* children; /* child list */
201
struct Ps_s* lastchild; /* end of children */
202
struct Ps_s* sibling; /* sibling list */
203
struct Ps_s* root; /* (partial) root list */
204
char* user; /* user name */
205
Pss_id_t pid; /* pid */
206
int level; /* process tree level */
207
int seen; /* already seen on chain */
208
int shown; /* list state */
209
} Ps_t;
210
211
typedef struct State_s /* program state */
212
{
213
int children; /* recursively list all children*/
214
int escape; /* escape { command args } */
215
int heading; /* output heading */
216
int parents; /* recursively list all parents */
217
int tree; /* list proc tree */
218
int hex; /* output optional hex key form */
219
int width; /* output width */
220
unsigned long now; /* current time */
221
Key_t* fields; /* format field list */
222
List_t* pids; /* pid vectors */
223
char* format; /* sfkeyprintf() format */
224
Key_t* lastfield; /* end of format list */
225
Dt_t* keys; /* format keys */
226
Dt_t* bypid; /* procs by pid */
227
Dt_t* byorder; /* procs by pid */
228
Ps_t* pp; /* next proc info slot */
229
Pss_t* pss; /* ps stream */
230
Pssdisc_t pssdisc; /* ps stream discipline */
231
Sfio_t* mac; /* temporary string stream */
232
Sfio_t* tmp; /* temporary string stream */
233
Sfio_t* wrk; /* temporary string stream */
234
char branch[1024]; /* process tree branch */
235
char buf[1024]; /* work buffer */
236
} State_t;
237
238
static Key_t keys[] =
239
{
240
{
241
0
242
},
243
{
244
"addr",
245
"ADDR",
246
"Physical address.",
247
PSS_addr,
248
KEY_addr,
249
8
250
},
251
{
252
"class",
253
"CLS",
254
"Scheduling class.",
255
PSS_sched,
256
KEY_class,
257
3,
258
},
259
{
260
"cmd",
261
"CMD",
262
"Command path with arguments.",
263
PSS_args,
264
KEY_cmd,
265
-32, 0,
266
0,0,0,
267
KEY_comm
268
},
269
{
270
"comm",
271
"COMMAND",
272
"Command file base name.",
273
PSS_command,
274
KEY_comm,
275
-24, 0,
276
0,0,0,
277
KEY_cmd
278
},
279
{
280
"cpu",
281
"%CPU",
282
"Cpu percent usage.",
283
PSS_cpu,
284
KEY_cpu,
285
4
286
},
287
{
288
"etime",
289
"ELAPSED",
290
"Elapsed time since start.",
291
0,
292
KEY_etime,
293
7
294
},
295
{
296
"flags",
297
"F",
298
"State flags (octal and additive).",
299
PSS_flags,
300
KEY_flags,
301
3
302
},
303
{
304
"gid",
305
"GROUP",
306
"Numeric group id.",
307
PSS_gid,
308
KEY_gid,
309
8, 0,
310
0,0,0,
311
KEY_group
312
},
313
{
314
"group",
315
"GROUP",
316
"Group id name.",
317
PSS_gid,
318
KEY_group,
319
8, 0,
320
0,0,0,
321
KEY_gid
322
},
323
{
324
"job",
325
"JOB",
326
"Job id.",
327
PSS_job,
328
KEY_job,
329
5, PID_MAX,
330
1,0,0
331
},
332
{
333
"nice",
334
"NI",
335
"Adjusted scheduling priority.",
336
PSS_nice,
337
KEY_nice,
338
4
339
},
340
{
341
"npid",
342
"NPID",
343
"Native process id.",
344
PSS_npid,
345
KEY_npid,
346
5, 0,
347
1,
348
},
349
{
350
"pgrp",
351
"PGRP",
352
"Process group id.",
353
PSS_pgrp,
354
KEY_pgrp,
355
5, PID_MAX,
356
1,0,0
357
},
358
{
359
"pid",
360
"PID",
361
"Process id.",
362
PSS_pid,
363
KEY_pid,
364
5, PID_MAX,
365
1,0,0
366
},
367
{
368
"ppid",
369
"PPID",
370
"Parent process id.",
371
PSS_ppid,
372
KEY_ppid,
373
5, PID_MAX,
374
1
375
},
376
{
377
"pri",
378
"PRI",
379
"Scheduling priority.",
380
PSS_pri,
381
KEY_pri,
382
3
383
},
384
{
385
"processor",
386
"PROC",
387
"Assigned processor.",
388
PSS_proc,
389
KEY_proc,
390
3
391
},
392
{
393
"refcount",
394
"REFS",
395
"Reference count.",
396
PSS_refcount,
397
KEY_refcount,
398
4, 0,
399
1,
400
},
401
{
402
"rss",
403
"RSS",
404
"Resident page set size in kilobytes.",
405
PSS_rss,
406
KEY_rss,
407
5
408
},
409
{
410
"sid",
411
"SID",
412
"Session id.",
413
PSS_sid,
414
KEY_sid,
415
5, PID_MAX,
416
1
417
},
418
{
419
"size",
420
"SIZE",
421
"Virtual memory size in kilobytes.",
422
PSS_size,
423
KEY_size,
424
6
425
},
426
{
427
"start",
428
"START",
429
"Start time.",
430
PSS_start,
431
KEY_start,
432
8
433
},
434
{
435
"state",
436
"S",
437
"Basic state.",
438
PSS_state,
439
KEY_state,
440
1
441
},
442
{
443
"tgrp",
444
"TGRP",
445
"Terminal group id.",
446
PSS_tgrp,
447
KEY_tgrp,
448
5, PID_MAX,
449
1,
450
},
451
{
452
"time",
453
"TIME",
454
"usr+sys time.",
455
PSS_time,
456
KEY_time,
457
6
458
},
459
{
460
"tty",
461
"TT",
462
"Controlling terminal base name.",
463
PSS_tty,
464
KEY_tty,
465
-7,
466
},
467
{
468
"uid",
469
"USER",
470
"Numeric user id.",
471
PSS_uid,
472
KEY_uid,
473
8, 0,
474
0,0,0,
475
KEY_user
476
},
477
{
478
"user",
479
"USER",
480
"User id name.",
481
PSS_uid,
482
KEY_user,
483
8, 0,
484
0,0,0,
485
KEY_uid
486
},
487
{
488
"wchan",
489
"WCHAN",
490
"Wait address.",
491
PSS_wchan,
492
KEY_wchan,
493
8
494
},
495
496
/* aliases after this point */
497
498
{ "args", 0, 0, 0, KEY_cmd },
499
{ "command", 0, 0, 0, KEY_cmd },
500
{ "f", 0, 0, 0, KEY_flags },
501
{ "jid", 0, 0, 0, KEY_job },
502
{ "ntpid", 0, 0, 0, KEY_npid },
503
{ "pcpu", 0, 0, 0, KEY_cpu },
504
{ "pgid", 0, 0, 0, KEY_pgrp },
505
{ "proc", 0, 0, 0, KEY_proc },
506
{ "psr", 0, 0, 0, KEY_proc },
507
{ "rgroup", 0, 0, 0, KEY_group },
508
{ "ruser", 0, 0, 0, KEY_user },
509
{ "s", 0, 0, 0, KEY_state },
510
{ "sess", 0, 0, 0, KEY_sid },
511
{ "stime", 0, 0, 0, KEY_start },
512
{ "tid", 0, 0, 0, KEY_tgrp },
513
{ "vsz", 0, 0, 0, KEY_size },
514
515
};
516
517
static const char fields_default[] = FIELDS_default;
518
static const char newline[] = "\n";
519
static const char space[] = " ";
520
521
static State_t state;
522
523
/*
524
* optget() info discipline function
525
*/
526
527
static int
528
optinfo(Opt_t* op, Sfio_t* sp, const char* s, Optdisc_t* dp)
529
{
530
register int i;
531
532
if (streq(s, "formats"))
533
for (i = 1; i < elementsof(keys); i++)
534
{
535
sfprintf(sp, "[+%s?", keys[i].name);
536
if (keys[i].head)
537
sfprintf(sp, "%s The title string is \b%s\b and the default width is %d.%s]", keys[i].desc, keys[i].head, keys[i].width, (!keys[i].field || (state.pss->meth->fields & keys[i].field)) ? "" : " Not available on this system.");
538
else
539
sfprintf(sp, "Equivalent to \b%s\b.]", keys[keys[i].index].name);
540
}
541
return 0;
542
}
543
544
/*
545
* return device id given tty base name
546
*/
547
548
static int
549
ttyid(const char* name)
550
{
551
return pssttydev(state.pss, name);
552
}
553
554
/*
555
* sfkeyprintf() lookup
556
* handle==0 for heading
557
*/
558
559
static int
560
key(void* handle, register Sffmt_t* fp, const char* arg, char** ps, Sflong_t* pn)
561
{
562
register Ps_t* pp = (Ps_t*)handle;
563
register char* s = 0;
564
register Sflong_t n = 0;
565
register Key_t* kp;
566
register int i;
567
int j;
568
unsigned long u;
569
570
static char sbuf[2];
571
572
if (!fp->t_str)
573
return 0;
574
if (!(kp = (Key_t*)dtmatch(state.keys, fp->t_str)))
575
{
576
if (*fp->t_str != '$')
577
{
578
error(3, "%s: unknown format key", fp->t_str);
579
return 0;
580
}
581
if (!(kp = newof(0, Key_t, 1, strlen(fp->t_str) + 1)))
582
error(ERROR_SYSTEM|3, "out of space");
583
kp->name = strcpy((char*)(kp + 1), fp->t_str);
584
kp->macro = getenv(fp->t_str + 1);
585
kp->index = KEY_environ;
586
kp->disable = 1;
587
dtinsert(state.keys, kp);
588
}
589
if (!kp->head && (state.pss->meth->fields & keys[kp->index].field))
590
kp = &keys[kp->index];
591
if (kp->macro && !kp->disable)
592
{
593
kp->disable = 1;
594
sfkeyprintf(state.mac, handle, kp->macro, key, NiL);
595
if (!(s = sfstruse(state.mac)))
596
error(ERROR_SYSTEM|3, "out of space");
597
kp->disable = 0;
598
}
599
else if (!pp)
600
{
601
if (!(state.pss->meth->fields & kp->field))
602
{
603
error(1, "%s: not available on this system", kp->name);
604
return -1;
605
}
606
state.pssdisc.fields |= kp->field;
607
if (fp->flags & SFFMT_ALTER)
608
{
609
if (kp->maxval)
610
{
611
for (i = 1; kp->maxval /= 10; i++);
612
if (kp->width < 0)
613
{
614
i = -i;
615
if (kp->width > i)
616
kp->width = i;
617
}
618
else if (kp->width < i)
619
kp->width = i;
620
}
621
if ((fp->width = kp->width) < 0)
622
{
623
fp->width = -fp->width;
624
fp->flags |= SFFMT_LEFT;
625
}
626
fp->precis = fp->width;
627
}
628
kp->width = fp->width;
629
if (fp->flags & SFFMT_LEFT)
630
kp->width = -kp->width;
631
fp->fmt = 's';
632
*ps = arg && (arg = (const char*)strdup(arg)) ? (char*)arg : kp->head;
633
}
634
else
635
{
636
if ((fp->flags & SFFMT_ALTER) && (fp->width = kp->width) < 0)
637
{
638
fp->width = -fp->width;
639
fp->flags |= SFFMT_LEFT;
640
}
641
switch (kp->index)
642
{
643
case KEY_addr:
644
if (pp->ps->state == PSS_ZOMBIE)
645
goto zombie;
646
n = (long)pp->ps->addr;
647
goto number;
648
case KEY_class:
649
if (pp->ps->state == PSS_ZOMBIE)
650
goto zombie;
651
s = pp->ps->sched;
652
break;
653
case KEY_cmd:
654
s = pp->ps->args;
655
goto branch;
656
case KEY_comm:
657
s = pp->ps->command;
658
branch:
659
if (!s)
660
s = "<defunct>";
661
if ((j = pp->level) > 0)
662
{
663
for (i = 0, j--; i < j; i++)
664
sfputr(state.wrk, state.branch[i] ? " | " : " ", -1);
665
sfputr(state.wrk, " \\_ ", -1);
666
i = sfstrtell(state.wrk);
667
sfputr(state.wrk, s, -1);
668
if (!(s = sfstruse(state.wrk)))
669
error(ERROR_SYSTEM|3, "out of space");
670
if (state.escape)
671
fmtesc(s + i);
672
}
673
break;
674
case KEY_cpu:
675
if (pp->ps->state == PSS_ZOMBIE)
676
goto zombie;
677
n = pp->ps->cpu;
678
goto percent;
679
case KEY_etime:
680
if (fp->fmt == 's')
681
s = fmtelapsed(state.now - (unsigned long)pp->ps->start, 1);
682
else
683
n = pp->ps->start;
684
break;
685
case KEY_flags:
686
n = pp->ps->flags & PSS_FLAGS;
687
goto number;
688
case KEY_group:
689
if (fp->fmt == 's')
690
{
691
s = fmtgid(pp->ps->gid);
692
break;
693
}
694
/*FALLTHROUGH*/
695
case KEY_gid:
696
n = pp->ps->gid;
697
goto number;
698
case KEY_nice:
699
if (pp->ps->state == PSS_ZOMBIE)
700
goto zombie;
701
n = pp->ps->nice;
702
goto number;
703
case KEY_npid:
704
n = pp->ps->npid;
705
goto number;
706
case KEY_pgrp:
707
n = pp->ps->pgrp;
708
goto number;
709
case KEY_pid:
710
n = pp->ps->pid;
711
goto number;
712
case KEY_ppid:
713
n = pp->ps->ppid;
714
break;
715
case KEY_pri:
716
if (pp->ps->state == PSS_ZOMBIE)
717
goto zombie;
718
n = pp->ps->pri;
719
goto number;
720
case KEY_refcount:
721
n = pp->ps->refcount;
722
goto number;
723
case KEY_rss:
724
if (pp->ps->state == PSS_ZOMBIE)
725
goto zombie;
726
n = pp->ps->rss;
727
goto number;
728
case KEY_sid:
729
n = pp->ps->sid;
730
goto number;
731
case KEY_size:
732
if (pp->ps->state == PSS_ZOMBIE)
733
goto zombie;
734
n = pp->ps->size;
735
goto number;
736
case KEY_start:
737
if (pp->ps->state == PSS_ZOMBIE)
738
goto zombie;
739
if (fp->fmt == 's')
740
{
741
u = pp->ps->start;
742
s = fmttime((state.now - u) >= (24 * 60 * 60) ? "%y-%m-%d" : "%H:%M:%S", u);
743
}
744
else
745
n = pp->ps->start;
746
break;
747
case KEY_state:
748
*(s = sbuf) = pp->ps->state;
749
*(s + 1) = 0;
750
break;
751
case KEY_tgrp:
752
n = pp->ps->tgrp;
753
goto number;
754
case KEY_time:
755
if (fp->fmt == 's')
756
s = fmtelapsed(pp->ps->time, 1);
757
else
758
n = pp->ps->time;
759
break;
760
case KEY_tty:
761
if (pp->ps->state == PSS_ZOMBIE)
762
goto zombie;
763
s = pssttyname(state.pss, pp->ps);
764
if (kp->prec && (i = strlen(s) - kp->prec) > 0)
765
{
766
if (s[0] == 'p' && s[1] == 't')
767
{
768
if (s[2] == 'y')
769
s += 3;
770
else
771
s += 2;
772
}
773
else if (s[0] == 't' && s[1] == 't' && s[2] == 'y')
774
s += 3;
775
else
776
s += i;
777
}
778
break;
779
case KEY_user:
780
if (fp->fmt == 's')
781
{
782
s = pp->user;
783
break;
784
}
785
/*FALLTHROUGH*/
786
case KEY_uid:
787
n = pp->ps->uid;
788
goto number;
789
case KEY_wchan:
790
if (pp->ps->state == PSS_ZOMBIE)
791
goto zombie;
792
n = (long)pp->ps->wchan;
793
goto number;
794
default:
795
return 0;
796
zombie:
797
s = "";
798
break;
799
percent:
800
sfprintf(state.tmp, "%%%I*d", sizeof(n), n);
801
if (!(s = sfstruse(state.tmp)))
802
error(ERROR_SYSTEM|3, "out of space");
803
break;
804
number:
805
if (state.hex)
806
{
807
fp->fmt = 'x';
808
if (!kp->hex)
809
fp->flags |= SFFMT_ZERO;
810
}
811
break;
812
}
813
if (s)
814
*ps = s;
815
else
816
*pn = n;
817
}
818
return 1;
819
}
820
821
/*
822
* ps a single proc
823
*/
824
825
static void
826
ps(Ps_t* pp)
827
{
828
register Key_t* kp;
829
register Pssent_t* pr;
830
register char* s;
831
register int i;
832
register long n;
833
unsigned long u;
834
int j;
835
char sbuf[2];
836
837
pp->shown = 1;
838
if (state.format)
839
{
840
sfkeyprintf(sfstdout, pp, state.format, key, NiL);
841
return;
842
}
843
pr = pp->ps;
844
for (kp = state.fields; kp; kp = kp->next)
845
{
846
switch (kp->index)
847
{
848
case KEY_addr:
849
if (pr->state == PSS_ZOMBIE)
850
goto zombie;
851
n = (long)pr->addr;
852
goto hex;
853
case KEY_class:
854
if (pr->state == PSS_ZOMBIE)
855
goto zombie;
856
s = pr->sched;
857
goto string;
858
case KEY_cmd:
859
s = pr->args;
860
goto branch;
861
case KEY_comm:
862
s = pr->command;
863
branch:
864
if (!s)
865
s = "<defunct>";
866
if ((j = pp->level) > 0)
867
{
868
for (i = 0, j--; i < j; i++)
869
sfputr(sfstdout, state.branch[i] ? " | " : " ", -1);
870
sfputr(sfstdout, " \\_ ", -1);
871
}
872
if (state.escape)
873
s = fmtesc(s);
874
goto string;
875
case KEY_cpu:
876
if (pr->state == PSS_ZOMBIE)
877
goto zombie;
878
n = pr->cpu;
879
goto percent;
880
case KEY_etime:
881
s = fmtelapsed(state.now - (unsigned long)pr->start, 1);
882
goto string;
883
case KEY_flags:
884
n = pr->flags & PSS_FLAGS;
885
goto octal;
886
case KEY_gid:
887
n = pr->gid;
888
goto number;
889
case KEY_group:
890
s = fmtgid(pr->gid);
891
goto string;
892
case KEY_nice:
893
if (pr->state == PSS_ZOMBIE)
894
goto zombie;
895
n = pr->nice;
896
goto number;
897
case KEY_npid:
898
n = pr->npid;
899
goto number;
900
case KEY_pgrp:
901
n = pr->pgrp;
902
goto number;
903
case KEY_pid:
904
n = pr->pid;
905
goto number;
906
case KEY_ppid:
907
n = pr->ppid;
908
goto number;
909
case KEY_pri:
910
if (pr->state == PSS_ZOMBIE)
911
goto zombie;
912
n = pr->pri;
913
goto number;
914
case KEY_refcount:
915
n = pr->refcount;
916
goto number;
917
case KEY_rss:
918
if (pr->state == PSS_ZOMBIE)
919
goto zombie;
920
n = pr->rss;
921
goto number;
922
case KEY_sid:
923
n = pr->sid;
924
goto number;
925
case KEY_size:
926
if (pr->state == PSS_ZOMBIE)
927
goto zombie;
928
n = pr->size;
929
goto number;
930
case KEY_start:
931
if (pr->state == PSS_ZOMBIE)
932
goto zombie;
933
u = pr->start;
934
s = fmttime((state.now - u) >= (24 * 60 * 60) ? "%y-%m-%d" : "%H:%M:%S", u);
935
goto string;
936
case KEY_state:
937
*(s = sbuf) = pr->state;
938
*(s + 1) = 0;
939
goto string;
940
case KEY_tgrp:
941
n = pr->tgrp;
942
goto number;
943
case KEY_time:
944
s = fmtelapsed(pr->time, 1);
945
goto string;
946
case KEY_tty:
947
if (pr->state == PSS_ZOMBIE)
948
goto zombie;
949
s = pssttyname(state.pss, pr);
950
if (kp->prec && (i = strlen(s) - kp->prec) > 0)
951
{
952
if (s[0] == 'p' && s[1] == 't')
953
{
954
if (s[2] == 'y')
955
s += 3;
956
else
957
s += 2;
958
}
959
else if (s[0] == 't' && s[1] == 't' && s[2] == 'y')
960
s += 3;
961
else
962
s += i;
963
}
964
goto string;
965
case KEY_uid:
966
n = pr->uid;
967
goto number;
968
case KEY_user:
969
s = pp->user;
970
goto string;
971
case KEY_wchan:
972
if (pr->state == PSS_ZOMBIE)
973
goto zombie;
974
n = (long)pr->wchan;
975
goto hex;
976
}
977
s = "????";
978
string:
979
if (kp->width == kp->prec)
980
sfprintf(sfstdout, "%0*s%s", kp->width, s, kp->sep);
981
else
982
sfprintf(sfstdout, "%*.*s%s", kp->width, kp->prec, s, kp->sep);
983
continue;
984
zombie:
985
s = "-";
986
goto string;
987
percent:
988
sfprintf(state.tmp, "%%%ld", n);
989
if (!(s = sfstruse(state.tmp)))
990
error(ERROR_SYSTEM|3, "out of space");
991
goto string;
992
number:
993
if (!state.hex || !kp->hex)
994
{
995
sfprintf(sfstdout, "%*ld%s", kp->width, n, kp->sep);
996
continue;
997
}
998
hex:
999
if (kp->hex)
1000
sfprintf(sfstdout, "%*lx%s", kp->width, n, kp->sep);
1001
else
1002
sfprintf(sfstdout, "%0*lx%s", kp->width, n, kp->sep);
1003
continue;
1004
octal:
1005
sfprintf(sfstdout, "%*lo%s", kp->width, n, kp->sep);
1006
continue;
1007
}
1008
}
1009
1010
/*
1011
* ps() a process and its children
1012
*/
1013
1014
static void
1015
kids(register Ps_t* pp, int level)
1016
{
1017
if (state.tree)
1018
{
1019
pp->level = level;
1020
ps(pp);
1021
if (level > 0)
1022
state.branch[level - 1] = pp->sibling != 0;
1023
if (level < elementsof(state.branch) - 1)
1024
level++;
1025
}
1026
else
1027
ps(pp);
1028
for (pp = pp->children; pp; pp = pp->sibling)
1029
kids(pp, level);
1030
}
1031
1032
/*
1033
* ps() the selected procs
1034
*/
1035
1036
static void
1037
list(void)
1038
{
1039
register Ps_t* pp;
1040
register Ps_t* xp;
1041
register Ps_t* zp;
1042
Ps_t* rp;
1043
1044
if (state.children || state.parents)
1045
{
1046
/*
1047
* list the child/parent branches of selected processes
1048
*/
1049
1050
if (state.parents)
1051
for (pp = (Ps_t*)dtfirst(state.byorder); pp; pp = (Ps_t*)dtnext(state.byorder, pp))
1052
if (pp->ps->pss & (PSS_EXPLICIT|PSS_MATCHED))
1053
{
1054
xp = pp;
1055
do
1056
{
1057
xp->ps->pss |= PSS_PARENT;
1058
} while ((xp = (Ps_t*)dtmatch(state.bypid, &xp->ps->ppid)) && !xp->ps->pss);
1059
}
1060
if (state.children)
1061
for (pp = (Ps_t*)dtfirst(state.byorder); pp; pp = (Ps_t*)dtnext(state.byorder, pp))
1062
if (!(pp->ps->pss & (PSS_EXPLICIT|PSS_MATCHED|PSS_PARENT)) && !pp->seen)
1063
{
1064
xp = pp;
1065
do
1066
{
1067
xp->seen = 1;
1068
if (xp->ps->pss & (PSS_ANCESTOR|PSS_EXPLICIT|PSS_MATCHED))
1069
{
1070
xp->ps->pss |= PSS_ANCESTOR;
1071
xp = pp;
1072
do
1073
{
1074
xp->ps->pss |= PSS_PARENT;
1075
} while ((xp = (Ps_t*)dtmatch(state.bypid, &xp->ps->ppid)) && !xp->ps->pss);
1076
break;
1077
}
1078
} while (xp->ps->ppid != xp->ps->pid && (xp = (Ps_t*)dtmatch(state.bypid, &xp->ps->ppid)));
1079
}
1080
rp = zp = 0;
1081
for (pp = (Ps_t*)dtfirst(state.byorder); pp; pp = (Ps_t*)dtnext(state.byorder, pp))
1082
if (pp->ps->pss)
1083
{
1084
if (pp->ps->ppid != pp->ps->pid && (xp = (Ps_t*)dtmatch(state.bypid, &pp->ps->ppid)) && (xp->ps->pss & (PSS_EXPLICIT|PSS_MATCHED|PSS_PARENT)))
1085
{
1086
xp->ps->pss |= PSS_CHILD;
1087
if (xp->lastchild)
1088
xp->lastchild = xp->lastchild->sibling = pp;
1089
else
1090
xp->children = xp->lastchild = pp;
1091
}
1092
else if (zp)
1093
zp = zp->root = pp;
1094
else
1095
rp = zp = pp;
1096
}
1097
for (pp = rp; pp; pp = pp->root)
1098
kids(pp, 0);
1099
}
1100
else
1101
{
1102
/*
1103
* list by order
1104
*/
1105
1106
for (pp = (Ps_t*)dtfirst(state.byorder); pp; pp = (Ps_t*)dtnext(state.byorder, pp))
1107
if (!pp->shown)
1108
{
1109
pp->shown = 1;
1110
pp->level = 0;
1111
ps(pp);
1112
}
1113
}
1114
}
1115
1116
/*
1117
* finalize the field formats and optionally list the heading
1118
*/
1119
1120
static void
1121
head(void)
1122
{
1123
register int n;
1124
register Key_t* kp;
1125
1126
if (state.fields)
1127
{
1128
while (state.fields->skip)
1129
state.fields = state.fields->next;
1130
kp = state.fields;
1131
while (kp->next)
1132
{
1133
if (!kp->next->skip)
1134
kp = kp->next;
1135
else if (!(kp->next = kp->next->next))
1136
{
1137
state.lastfield = kp;
1138
break;
1139
}
1140
}
1141
n = 0;
1142
for (kp = state.fields; kp; kp = kp->next)
1143
{
1144
if ((kp->prec = kp->width) < 0)
1145
kp->prec = -kp->prec;
1146
if (*kp->head)
1147
n = 1;
1148
}
1149
kp = state.lastfield;
1150
if (kp->width < 0)
1151
kp->width = 0;
1152
if (kp->index == KEY_cmd)
1153
kp->prec = 80;
1154
if (n && state.heading)
1155
{
1156
for (kp = state.fields; kp; kp = kp->next)
1157
sfprintf(sfstdout, "%*s%s", kp->width, kp->head, kp->sep);
1158
sfputc(sfstdout, '\n');
1159
}
1160
}
1161
else
1162
{
1163
sfkeyprintf(state.heading ? sfstdout : state.wrk, NiL, state.format, key, NiL);
1164
sfstrseek(state.wrk, 0, SEEK_SET);
1165
}
1166
}
1167
1168
/*
1169
* order procs by <uid,start,pid>
1170
*/
1171
1172
static int
1173
byorder(Dt_t* dt, void* a, void* b, Dtdisc_t* disc)
1174
{
1175
register Ps_t* pa = (Ps_t*)a;
1176
register Ps_t* pb = (Ps_t*)b;
1177
register int i;
1178
1179
NoP(dt);
1180
NoP(disc);
1181
if (i = strcmp(pa->user, pb->user))
1182
return i;
1183
if (pa->ps->pgrp < pb->ps->pgrp)
1184
return -1;
1185
if (pa->ps->pgrp > pb->ps->pgrp)
1186
return 1;
1187
if (i = (pa->ps->pgrp == pa->ps->pid) - (pb->ps->pgrp == pb->ps->pid))
1188
return i;
1189
if (pa->ps->start < pb->ps->start)
1190
return -1;
1191
if (pa->ps->start > pb->ps->start)
1192
return 1;
1193
if (pa->ps->pid < pb->ps->pid)
1194
return -1;
1195
if (pa->ps->pid > pb->ps->pid)
1196
return 1;
1197
return 0;
1198
}
1199
1200
/*
1201
* add the procs in the pid list
1202
*/
1203
1204
static void
1205
addpid(Pssent_t* pe, register char* s)
1206
{
1207
register char* t;
1208
register Ps_t* pp;
1209
register int c;
1210
char* e;
1211
Pss_id_t pid;
1212
long n;
1213
1214
do
1215
{
1216
if (s)
1217
{
1218
for (; isspace(*s) || *s == ','; s++);
1219
for (t = s; *s && !isspace(*s) && *s != ','; s++);
1220
c = *s;
1221
*s = 0;
1222
if (!*t)
1223
break;
1224
errno = 0;
1225
n = strtol(t, &e, 0);
1226
// deleting check for PID_MAX because on linux this relies on kernel instance
1227
// and the system will reject bad pids any way
1228
// if (errno || n <= 0 || n > PID_MAX || *e)
1229
if (errno || n <= 0 || *e)
1230
{
1231
error(2, "%s: invalid pid", t);
1232
continue;
1233
}
1234
pid = n;
1235
pe = pssread(state.pss, pid);
1236
}
1237
if (pe)
1238
{
1239
if (!(pp = state.pp) && !(state.pp = pp = newof(0, Ps_t, 1, 0)))
1240
error(ERROR_SYSTEM|3, "out of space");
1241
pp->user = fmtuid(pe->uid);
1242
pp->pid = pe->pid;
1243
pp->ps = pe;
1244
if (!dtsearch(state.byorder, pp))
1245
{
1246
if (!(pp->ps = psssave(state.pss, pe)))
1247
break;
1248
dtinsert(state.byorder, pp);
1249
state.pp = 0;
1250
}
1251
}
1252
} while (s && (*s++ = c));
1253
}
1254
1255
/*
1256
* add the ids in s into state.pssdisc.match
1257
* getid!=0 translates alnum to id number
1258
*/
1259
1260
static void
1261
addid(register char* s, int index, int (*getid)(const char*))
1262
{
1263
register char* t;
1264
register int c;
1265
char* e;
1266
long n;
1267
unsigned long field;
1268
Pssmatch_t* mp;
1269
Pssdata_t* dp;
1270
1271
if (!((field = keys[index].field) & PSS_match))
1272
error(3, "%s: cannot match on this field", keys[index].name);
1273
for (mp = state.pssdisc.match; mp && mp->field != field; mp = mp->next);
1274
if (!mp)
1275
{
1276
if (!(mp = newof(0, Pssmatch_t, 1, 0)))
1277
error(ERROR_SYSTEM|3, "out of space");
1278
mp->next = state.pssdisc.match;
1279
mp->field = field;
1280
state.pssdisc.match = mp;
1281
}
1282
do
1283
{
1284
for (; isspace(*s) || *s == ','; s++);
1285
for (t = s; *s && !isspace(*s) && *s != ','; s++);
1286
if ((c = s - t) >= sizeof(state.buf))
1287
c = sizeof(state.buf) - 1;
1288
memcpy(state.buf, t, c);
1289
(t = state.buf)[c] = 0;
1290
if (!*t)
1291
break;
1292
if (isdigit(*t))
1293
{
1294
n = strtol(t, &e, 10);
1295
if (*e)
1296
{
1297
error(1, "%s: invalid %s", t, keys[index].name);
1298
continue;
1299
}
1300
}
1301
else if (!getid || (n = (*getid)(t)) < 0)
1302
{
1303
error(1, "%s: invalid %s", t, keys[index].name);
1304
continue;
1305
}
1306
if (!(dp = newof(0, Pssdata_t, 1, 0)))
1307
error(ERROR_SYSTEM|3, "out of space");
1308
dp->next = mp->data;
1309
mp->data = dp;
1310
dp->data = n;
1311
} while (*s++);
1312
}
1313
1314
/*
1315
* add the format key in s into state.fields
1316
*/
1317
1318
static void
1319
addkey(const char* k, int ignore)
1320
{
1321
register char* s = (char*)k;
1322
register char* t;
1323
register int c;
1324
register Key_t* kp;
1325
register Key_t* ap;
1326
char* e;
1327
int w;
1328
1329
if (streq(s, "?"))
1330
{
1331
sfprintf(sfstdout, "%-8s %-8s %s\n", "KEY", "HEADING", "DESCRIPTION");
1332
for (kp = keys + 1; kp < keys + elementsof(keys); kp++)
1333
{
1334
ap = kp->head ? kp : (keys + kp->index);
1335
sfprintf(sfstdout, "%-8s %-8s %s%s%s\n", kp->name, ap->head, ap->desc, ap == kp ? "" : " [alias]", (!ap->field || (state.pss->meth->fields & ap->field)) ? "" : " [not available]");
1336
}
1337
exit(0);
1338
}
1339
do
1340
{
1341
for (; isspace(*s) || *s == ','; s++);
1342
for (t = s; *s && !isspace(*s) && *s != ',' && *s != '=' && *s != ':' && *s != '+'; s++);
1343
if ((c = s - t) >= sizeof(state.buf))
1344
c = sizeof(state.buf) - 1;
1345
memcpy(state.buf, t, c);
1346
(t = state.buf)[c] = 0;
1347
if (!*t)
1348
break;
1349
if (*s == ':' || *s == '+')
1350
{
1351
c = (int)strtol(s + 1, &e, 10);
1352
s = e;
1353
}
1354
else
1355
c = 0;
1356
if (!(kp = (Key_t*)dtmatch(state.keys, t)))
1357
{
1358
error(2, "%s: unknown format key", t);
1359
continue;
1360
}
1361
1362
/*
1363
* aliases have Key_t.head == 0
1364
*/
1365
1366
if (!kp->head)
1367
kp = keys + kp->index;
1368
1369
/*
1370
* adjust the width field
1371
*/
1372
1373
if (*s == '=')
1374
{
1375
for (t = ++s; *s && !isspace(*s) && *s != ','; s++);
1376
w = s - t;
1377
if (!(kp->head = newof(0, char, w, 1)))
1378
error(ERROR_SYSTEM|3, "out of space");
1379
memcpy(kp->head, t, w);
1380
if (w < c)
1381
w = c;
1382
if (w > kp->width)
1383
kp->width = w;
1384
}
1385
else if (c >= strlen(kp->head))
1386
kp->width = c;
1387
if (!(state.pss->meth->fields & kp->field))
1388
{
1389
if (!ignore)
1390
error(1, "%s: not available on this system", kp->name);
1391
continue;
1392
}
1393
1394
/*
1395
* except for width and head adjustments
1396
* we ignore keys already specified to let
1397
* shell aliases work with least suprise
1398
*/
1399
1400
if (!kp->already)
1401
{
1402
kp->already = keys[kp->cancel].already = keys[kp->cancel].skip = 1;
1403
if (state.lastfield)
1404
state.lastfield = state.lastfield->next = kp;
1405
else
1406
state.fields = state.lastfield = kp;
1407
kp->sep = space;
1408
if (kp->maxval)
1409
{
1410
for (c = 1; kp->maxval /= 10; c++);
1411
if (c >= kp->width)
1412
kp->width = c;
1413
}
1414
state.pssdisc.fields |= kp->field;
1415
}
1416
} while (*s != '=' && *s++);
1417
}
1418
1419
/*
1420
* add pid vector for subsequent poppids()
1421
*/
1422
1423
static void
1424
pushpids(void* argv, int argc)
1425
{
1426
register List_t* p;
1427
1428
if (!(p = newof(0, List_t, 1, 0)))
1429
error(ERROR_SYSTEM|3, "out of space");
1430
p->argv = (char**)argv;
1431
p->argc = argc;
1432
p->next = state.pids;
1433
state.pids = p;
1434
}
1435
1436
/*
1437
* pop state.pids by calling addpid()
1438
*/
1439
1440
static void
1441
poppids(void)
1442
{
1443
register List_t* p;
1444
register int i;
1445
unsigned long flags;
1446
1447
flags = state.pssdisc.flags;
1448
state.pssdisc.flags |= PSS_VERBOSE;
1449
while (p = state.pids)
1450
{
1451
state.pids = p->next;
1452
if (i = p->argc)
1453
while (--i >= 0)
1454
addpid(NiL, p->argv[i]);
1455
else
1456
addpid(NiL, (char*)p->argv);
1457
free(p);
1458
}
1459
state.pssdisc.flags = flags;
1460
}
1461
1462
int
1463
main(int argc, register char** argv)
1464
{
1465
register int n;
1466
register char* s;
1467
Sfio_t* fmt;
1468
Key_t* kp;
1469
Ps_t* pp;
1470
Pssent_t* pe;
1471
Dtdisc_t kd;
1472
Dtdisc_t nd;
1473
Dtdisc_t sd;
1474
Optdisc_t od;
1475
struct stat st;
1476
1477
NoP(argc);
1478
error_info.id = "ps";
1479
setlocale(LC_ALL, "");
1480
state.now = time((time_t*)0);
1481
state.escape = 1;
1482
state.heading = 1;
1483
if (!(fmt = sfstropen()) || !(state.tmp = sfstropen()) || !(state.wrk = sfstropen()))
1484
error(ERROR_SYSTEM|3, "out of space");
1485
1486
/*
1487
* set up the disciplines
1488
*/
1489
1490
pssinit(&state.pssdisc, argv[0], errorf);
1491
optinit(&od, optinfo);
1492
memset(&kd, 0, sizeof(kd));
1493
kd.key = offsetof(Key_t, name);
1494
kd.size = -1;
1495
kd.link = offsetof(Key_t, hashed);
1496
memset(&nd, 0, sizeof(nd));
1497
nd.key = offsetof(Ps_t, pid);
1498
nd.size = sizeof(Pss_id_t);
1499
nd.link = offsetof(Ps_t, hashed);
1500
memset(&sd, 0, sizeof(sd));
1501
sd.link = offsetof(Ps_t, sorted);
1502
sd.comparf = byorder;
1503
1504
/*
1505
* open the ps stream
1506
*/
1507
1508
if (!(state.pss = pssopen(&state.pssdisc)) || !state.pss->meth->fields)
1509
{
1510
s = "/bin/ps";
1511
if (!streq(argv[0], s) && !eaccess(s, X_OK))
1512
{
1513
argv[0] = s;
1514
error(1, "falling back to %s", s);
1515
execv(s, argv);
1516
exit(EXIT_NOTFOUND);
1517
}
1518
if (!state.pss)
1519
{
1520
state.pssdisc.flags |= PSS_VERBOSE;
1521
pssopen(&state.pssdisc);
1522
}
1523
error(3, "process status access error");
1524
}
1525
1526
/*
1527
* initialize the format key table
1528
*/
1529
1530
if (!(state.keys = dtopen(&kd, Dtset)) || !(state.bypid = dtopen(&nd, Dtset)) || !(state.byorder = dtopen(&sd, Dtset)))
1531
error(ERROR_SYSTEM|3, "out of space");
1532
for (n = 1; n < elementsof(keys); n++)
1533
dtinsert(state.keys, keys + n);
1534
1535
/*
1536
* grab the options
1537
*/
1538
1539
n = 0;
1540
for (;;)
1541
{
1542
switch (optget(argv, usage))
1543
{
1544
case 'a':
1545
state.pssdisc.flags |= PSS_ATTACHED|PSS_NOLEADER;
1546
continue;
1547
case 'c':
1548
addkey(FIELDS_c, 1);
1549
continue;
1550
case 'd':
1551
state.pssdisc.flags |= PSS_NOLEADER;
1552
continue;
1553
case 'e':
1554
case 'A':
1555
state.pssdisc.flags |= PSS_ALL;
1556
continue;
1557
case 'f':
1558
addkey(FIELDS_f, 1);
1559
continue;
1560
case 'h':
1561
state.heading = opt_info.num;
1562
continue;
1563
case 'g':
1564
addid(opt_info.arg, KEY_pgrp, NiL);
1565
continue;
1566
case 'j':
1567
addkey(FIELDS_j, 1);
1568
continue;
1569
case 'l':
1570
addkey(FIELDS_l, 1);
1571
continue;
1572
case 'n':
1573
continue;
1574
case 'o':
1575
addkey(opt_info.arg, 0);
1576
continue;
1577
case 'p':
1578
pushpids(opt_info.arg, 0);
1579
continue;
1580
case 'r':
1581
case 'R':
1582
state.children = opt_info.num;
1583
continue;
1584
case 's':
1585
addid(opt_info.arg, KEY_sid, NiL);
1586
continue;
1587
case 't':
1588
addid(opt_info.arg, KEY_tty, ttyid);
1589
continue;
1590
case 'u':
1591
addid(opt_info.arg, KEY_uid, struid);
1592
continue;
1593
case 'v':
1594
state.pssdisc.flags |= PSS_VERBOSE;
1595
continue;
1596
case 'w':
1597
/* ignored by this implementation */
1598
continue;
1599
case 'x':
1600
state.pssdisc.flags |= PSS_DETACHED;
1601
continue;
1602
case 'B':
1603
n = !opt_info.num;
1604
continue;
1605
case 'C':
1606
state.tree = state.children = opt_info.num;
1607
continue;
1608
case 'D':
1609
if (s = strchr(opt_info.arg, '='))
1610
*s++ = 0;
1611
if (*opt_info.arg == 'n' && *(opt_info.arg + 1) == 'o')
1612
{
1613
opt_info.arg += 2;
1614
s = 0;
1615
}
1616
if (!(kp = (Key_t*)dtmatch(state.keys, opt_info.arg)))
1617
{
1618
if (!s)
1619
continue;
1620
if (!(kp = newof(0, Key_t, 1, strlen(opt_info.arg) + 1)))
1621
error(ERROR_SYSTEM|3, "out of space");
1622
kp->name = strcpy((char*)(kp + 1), opt_info.arg);
1623
dtinsert(state.keys, kp);
1624
}
1625
if (kp->macro = s)
1626
stresc(s);
1627
continue;
1628
case 'E':
1629
state.escape = opt_info.num;
1630
continue;
1631
case 'F':
1632
if (sfstrtell(fmt))
1633
sfputc(fmt, ' ');
1634
sfputr(fmt, opt_info.arg, -1);
1635
continue;
1636
case 'G':
1637
addid(opt_info.arg, KEY_group, strgid);
1638
continue;
1639
case 'L':
1640
state.pssdisc.flags |= PSS_LEADER;
1641
continue;
1642
case 'N':
1643
addkey(fields_default, 1);
1644
continue;
1645
case 'P':
1646
state.tree = state.parents = opt_info.num;
1647
continue;
1648
case 'T':
1649
state.tree = state.parents = state.children = opt_info.num;
1650
continue;
1651
case 'X':
1652
state.hex = !state.hex;
1653
continue;
1654
case '?':
1655
error(ERROR_USAGE|4, "%s", opt_info.arg);
1656
break;
1657
case ':':
1658
error(2, "%s", opt_info.arg);
1659
break;
1660
}
1661
break;
1662
}
1663
argv += opt_info.index;
1664
argc -= opt_info.index;
1665
if (error_info.errors)
1666
error(ERROR_USAGE|4, "%s", optusage(NiL));
1667
if (n)
1668
state.tree = 0;
1669
if (sfstrtell(fmt))
1670
{
1671
sfputc(fmt, '\n');
1672
if (!(state.format = sfstruse(fmt)))
1673
error(ERROR_SYSTEM|3, "out of space");
1674
}
1675
else
1676
{
1677
sfclose(fmt);
1678
fmt = 0;
1679
if (!state.fields)
1680
addkey(fields_default, 1);
1681
}
1682
head();
1683
1684
/*
1685
* add each proc by name
1686
*/
1687
1688
if (*argv)
1689
pushpids(argv, argc);
1690
if (state.children || state.parents || !state.pids)
1691
{
1692
if (state.children || state.parents)
1693
state.pssdisc.flags |= PSS_UNMATCHED;
1694
if (!state.pids && !state.pssdisc.match && !(state.pssdisc.flags & (PSS_ALL|PSS_ATTACHED|PSS_DETACHED|PSS_LEADER|PSS_NOLEADER)))
1695
{
1696
state.pssdisc.flags |= PSS_UID;
1697
state.pssdisc.uid = geteuid();
1698
for (n = 0; n <= 2; n++)
1699
if (isatty(n) && !fstat(n, &st))
1700
{
1701
state.pssdisc.flags |= PSS_TTY;
1702
state.pssdisc.tty = st.st_rdev;
1703
break;
1704
}
1705
}
1706
poppids();
1707
while (pe = pssread(state.pss, PSS_SCAN))
1708
addpid(pe, NiL);
1709
if (state.children || state.parents)
1710
for (pp = (Ps_t*)dtfirst(state.byorder); pp; pp = (Ps_t*)dtnext(state.byorder, pp))
1711
dtinsert(state.bypid, pp);
1712
}
1713
else
1714
poppids();
1715
1716
/*
1717
* list the procs
1718
*/
1719
1720
if (state.fields)
1721
state.lastfield->sep = newline;
1722
list();
1723
pssclose(state.pss);
1724
return error_info.errors != 0;
1725
}
1726
1727