1*9dc307c4Schristos /* $NetBSD: ps.c,v 1.97 2021/09/14 22:01:17 christos Exp $ */
249f0ad86Scgd
3d530ee00Ssimonb /*
4b35fbd45Sapb * Copyright (c) 2000-2008 The NetBSD Foundation, Inc.
5d530ee00Ssimonb * All rights reserved.
6d530ee00Ssimonb *
7d530ee00Ssimonb * This code is derived from software contributed to The NetBSD Foundation
8d530ee00Ssimonb * by Simon Burge.
9d530ee00Ssimonb *
10d530ee00Ssimonb * Redistribution and use in source and binary forms, with or without
11d530ee00Ssimonb * modification, are permitted provided that the following conditions
12d530ee00Ssimonb * are met:
13d530ee00Ssimonb * 1. Redistributions of source code must retain the above copyright
14d530ee00Ssimonb * notice, this list of conditions and the following disclaimer.
15d530ee00Ssimonb * 2. Redistributions in binary form must reproduce the above copyright
16d530ee00Ssimonb * notice, this list of conditions and the following disclaimer in the
17d530ee00Ssimonb * documentation and/or other materials provided with the distribution.
18d530ee00Ssimonb *
19d530ee00Ssimonb * THIS SOFTWARE IS PROVIDED BY THE NETBSD FOUNDATION, INC. AND CONTRIBUTORS
20d530ee00Ssimonb * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED
21d530ee00Ssimonb * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
22d530ee00Ssimonb * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE FOUNDATION OR CONTRIBUTORS
23d530ee00Ssimonb * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
24d530ee00Ssimonb * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
25d530ee00Ssimonb * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
26d530ee00Ssimonb * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
27d530ee00Ssimonb * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
28d530ee00Ssimonb * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
29d530ee00Ssimonb * POSSIBILITY OF SUCH DAMAGE.
30d530ee00Ssimonb */
31d530ee00Ssimonb
32d530ee00Ssimonb /*
334d1457ceScgd * Copyright (c) 1990, 1993, 1994
344d1457ceScgd * The Regents of the University of California. All rights reserved.
3561f28255Scgd *
3661f28255Scgd * Redistribution and use in source and binary forms, with or without
3761f28255Scgd * modification, are permitted provided that the following conditions
3861f28255Scgd * are met:
3961f28255Scgd * 1. Redistributions of source code must retain the above copyright
4061f28255Scgd * notice, this list of conditions and the following disclaimer.
4161f28255Scgd * 2. Redistributions in binary form must reproduce the above copyright
4261f28255Scgd * notice, this list of conditions and the following disclaimer in the
4361f28255Scgd * documentation and/or other materials provided with the distribution.
44b5b29542Sagc * 3. Neither the name of the University nor the names of its contributors
4561f28255Scgd * may be used to endorse or promote products derived from this software
4661f28255Scgd * without specific prior written permission.
4761f28255Scgd *
4861f28255Scgd * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
4961f28255Scgd * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
5061f28255Scgd * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
5161f28255Scgd * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
5261f28255Scgd * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
5361f28255Scgd * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
5461f28255Scgd * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
5561f28255Scgd * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
5661f28255Scgd * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
5761f28255Scgd * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
5861f28255Scgd * SUCH DAMAGE.
5961f28255Scgd */
6061f28255Scgd
6178295c8bSchristos #include <sys/cdefs.h>
6261f28255Scgd #ifndef lint
632fe2731dSlukem __COPYRIGHT("@(#) Copyright (c) 1990, 1993, 1994\
642fe2731dSlukem The Regents of the University of California. All rights reserved.");
6561f28255Scgd #endif /* not lint */
6661f28255Scgd
6761f28255Scgd #ifndef lint
6849f0ad86Scgd #if 0
694d1457ceScgd static char sccsid[] = "@(#)ps.c 8.4 (Berkeley) 4/2/94";
7049f0ad86Scgd #else
71*9dc307c4Schristos __RCSID("$NetBSD: ps.c,v 1.97 2021/09/14 22:01:17 christos Exp $");
7249f0ad86Scgd #endif
7361f28255Scgd #endif /* not lint */
7461f28255Scgd
7561f28255Scgd #include <sys/param.h>
7661f28255Scgd #include <sys/time.h>
7761f28255Scgd #include <sys/resource.h>
783fdac2b8Sthorpej #include <sys/lwp.h>
7961f28255Scgd #include <sys/proc.h>
8061f28255Scgd #include <sys/stat.h>
8161f28255Scgd #include <sys/ioctl.h>
824d1457ceScgd #include <sys/sysctl.h>
834d1457ceScgd
84036e2657Sdsl #include <stddef.h>
854d1457ceScgd #include <ctype.h>
864d1457ceScgd #include <err.h>
8761f28255Scgd #include <errno.h>
884d1457ceScgd #include <fcntl.h>
89e31566ddScjep #include <grp.h>
904d1457ceScgd #include <kvm.h>
91bf18a93aSpk #include <limits.h>
929655f5c2Schristos #include <locale.h>
93cc1877baSrin #include <math.h>
944d1457ceScgd #include <nlist.h>
954d1457ceScgd #include <paths.h>
96975ed852Smycroft #include <pwd.h>
9761f28255Scgd #include <stdio.h>
9861f28255Scgd #include <stdlib.h>
9961f28255Scgd #include <string.h>
1004d1457ceScgd #include <unistd.h>
101*9dc307c4Schristos #include <util.h>
1024d1457ceScgd
10361f28255Scgd #include "ps.h"
10461f28255Scgd
105d530ee00Ssimonb /*
106d530ee00Ssimonb * ARGOPTS must contain all option characters that take arguments
107d530ee00Ssimonb * (except for 't'!) - it is used in kludge_oldps_options()
108d530ee00Ssimonb */
109e31566ddScjep #define GETOPTSTR "aAcCdegG:hjk:LlM:mN:O:o:p:rSsTt:U:uvW:wx"
110e31566ddScjep #define ARGOPTS "GkMNOopUW"
111d530ee00Ssimonb
112d9463bc1Sapb struct varlist displaylist = SIMPLEQ_HEAD_INITIALIZER(displaylist);
113d9463bc1Sapb struct varlist sortlist = SIMPLEQ_HEAD_INITIALIZER(sortlist);
11461f28255Scgd
11561f28255Scgd int eval; /* exit value */
11661f28255Scgd int sumrusage; /* -S */
11761f28255Scgd int termwidth; /* width of screen (0 == infinity) */
11861f28255Scgd int totwidth; /* calculated width of requested variables */
11961f28255Scgd
1203fdac2b8Sthorpej int needcomm, needenv, commandonly;
1215801c247Ssimonb uid_t myuid;
12261f28255Scgd
1233fdac2b8Sthorpej static struct kinfo_lwp
12453474900Ssimonb *pick_representative_lwp(struct kinfo_proc2 *,
12553474900Ssimonb struct kinfo_lwp *, int);
126fd521aefSsimonb static struct kinfo_proc2
12753474900Ssimonb *getkinfo_kvm(kvm_t *, int, int, int *);
128cc1877baSrin static struct pinfo
129cc1877baSrin *setpinfo(struct kinfo_proc2 *, int, int, int);
13053474900Ssimonb static char *kludge_oldps_options(char *);
13153474900Ssimonb static int pscomp(const void *, const void *);
13253474900Ssimonb static void scanvars(void);
1335bb1ddccSjoerg __dead static void usage(void);
13410ed3a58Schristos static int parsenum(const char *, const char *);
1355a6cfab1Schristos static void descendant_sort(struct pinfo *, int);
13661f28255Scgd
13761f28255Scgd char dfmt[] = "pid tt state time command";
13861f28255Scgd char jfmt[] = "user pid ppid pgid sess jobc state tt time command";
13961f28255Scgd char lfmt[] = "uid pid ppid cpu pri nice vsz rss wchan state tt time command";
140abb32017Ssimonb char sfmt[] = "uid pid ppid cpu lid nlwp pri nice vsz rss wchan lstate tt "
141067314c6Smlelstv "ltime command";
14261f28255Scgd char ufmt[] = "user pid %cpu %mem vsz rss tt state start time command";
1434d1457ceScgd char vfmt[] = "pid state time sl re pagein vsz rss lim tsiz %cpu %mem command";
14461f28255Scgd
145ea03f830Syamt const char *default_fmt = dfmt;
146ea03f830Syamt
147d9463bc1Sapb struct varent *Opos = NULL; /* -O flag inserts after this point */
148d9463bc1Sapb
1494d1457ceScgd kvm_t *kd;
1504d1457ceScgd
151763e5791Sjoerg static long long
ttyname2dev(const char * ttname,int * xflg,int * what)152763e5791Sjoerg ttyname2dev(const char *ttname, int *xflg, int *what)
153763e5791Sjoerg {
154763e5791Sjoerg struct stat sb;
155763e5791Sjoerg const char *ttypath;
156763e5791Sjoerg char pathbuf[MAXPATHLEN];
157763e5791Sjoerg
158763e5791Sjoerg ttypath = NULL;
159763e5791Sjoerg if (strcmp(ttname, "?") == 0) {
160763e5791Sjoerg *xflg = 1;
161763e5791Sjoerg return KERN_PROC_TTY_NODEV;
162763e5791Sjoerg }
163763e5791Sjoerg if (strcmp(ttname, "-") == 0)
164763e5791Sjoerg return KERN_PROC_TTY_REVOKE;
165763e5791Sjoerg
166763e5791Sjoerg if (strcmp(ttname, "co") == 0)
167763e5791Sjoerg ttypath = _PATH_CONSOLE;
168763e5791Sjoerg else if (strncmp(ttname, "pts/", 4) == 0 ||
169763e5791Sjoerg strncmp(ttname, "tty", 3) == 0) {
170763e5791Sjoerg (void)snprintf(pathbuf,
171763e5791Sjoerg sizeof(pathbuf), "%s%s", _PATH_DEV, ttname);
172763e5791Sjoerg ttypath = pathbuf;
173763e5791Sjoerg } else if (*ttname != '/') {
174763e5791Sjoerg (void)snprintf(pathbuf,
175763e5791Sjoerg sizeof(pathbuf), "%s%s", _PATH_TTY, ttname);
176763e5791Sjoerg ttypath = pathbuf;
177763e5791Sjoerg } else
178763e5791Sjoerg ttypath = ttname;
179763e5791Sjoerg *what = KERN_PROC_TTY;
180763e5791Sjoerg if (stat(ttypath, &sb) == -1) {
181f86ebf39Sdholland devmajor_t pts;
182f86ebf39Sdholland int serrno;
183763e5791Sjoerg
184f86ebf39Sdholland serrno = errno;
185f86ebf39Sdholland pts = getdevmajor("pts", S_IFCHR);
186763e5791Sjoerg if (pts != NODEVMAJOR && strncmp(ttname, "pts/", 4) == 0) {
187763e5791Sjoerg int ptsminor = atoi(ttname + 4);
188763e5791Sjoerg
189763e5791Sjoerg snprintf(pathbuf, sizeof(pathbuf), "pts/%d", ptsminor);
190763e5791Sjoerg if (strcmp(pathbuf, ttname) == 0 && ptsminor >= 0)
191763e5791Sjoerg return makedev(pts, ptsminor);
192763e5791Sjoerg }
193f86ebf39Sdholland errno = serrno;
194b02b35c9Schristos err(EXIT_FAILURE, "%s", ttypath);
195763e5791Sjoerg }
196763e5791Sjoerg if (!S_ISCHR(sb.st_mode))
197b02b35c9Schristos errx(EXIT_FAILURE, "%s: not a terminal", ttypath);
198763e5791Sjoerg return sb.st_rdev;
199763e5791Sjoerg }
200763e5791Sjoerg
2014d1457ceScgd int
main(int argc,char * argv[])20253474900Ssimonb main(int argc, char *argv[])
20361f28255Scgd {
204cc1877baSrin struct kinfo_proc2 *kinfo;
205cc1877baSrin struct pinfo *pinfo;
2064d1457ceScgd struct varent *vent;
20761f28255Scgd struct winsize ws;
2083fdac2b8Sthorpej struct kinfo_lwp *kl, *l;
2095a6cfab1Schristos int ch, i, j, fmt, lineno, descendancy, nentries, nlwps;
210a5c6617dSchristos long long flag;
211cc1877baSrin int calc_pcpu, prtheader, wflag, what, xflg, rawcpu, showlwps;
212bf18a93aSpk char *nlistf, *memf, *swapf, errbuf[_POSIX2_LINE_MAX];
21326cc4401Skim char *ttname;
21461f28255Scgd
2159655f5c2Schristos setprogname(argv[0]);
2169655f5c2Schristos (void)setlocale(LC_ALL, "");
2179655f5c2Schristos
218fd521aefSsimonb if ((ioctl(STDOUT_FILENO, TIOCGWINSZ, (char *)&ws) == -1 &&
219fd521aefSsimonb ioctl(STDERR_FILENO, TIOCGWINSZ, (char *)&ws) == -1 &&
220fd521aefSsimonb ioctl(STDIN_FILENO, TIOCGWINSZ, (char *)&ws) == -1) ||
22161f28255Scgd ws.ws_col == 0)
22261f28255Scgd termwidth = 79;
22361f28255Scgd else
22461f28255Scgd termwidth = ws.ws_col - 1;
22561f28255Scgd
22661f28255Scgd if (argc > 1)
22761f28255Scgd argv[1] = kludge_oldps_options(argv[1]);
22861f28255Scgd
2290e68b604Skamil descendancy = fmt = prtheader = wflag = xflg = rawcpu = showlwps = 0;
230975ed852Smycroft what = KERN_PROC_UID;
2315801c247Ssimonb flag = myuid = getuid();
23261f28255Scgd memf = nlistf = swapf = NULL;
233a468ec49Sdholland
234d530ee00Ssimonb while ((ch = getopt(argc, argv, GETOPTSTR)) != -1)
23561f28255Scgd switch((char)ch) {
236b35fbd45Sapb case 'A':
237b35fbd45Sapb /* "-A" shows all processes, like "-ax" */
238b35fbd45Sapb xflg = 1;
239b35fbd45Sapb /*FALLTHROUGH*/
24061f28255Scgd case 'a':
241975ed852Smycroft what = KERN_PROC_ALL;
242975ed852Smycroft flag = 0;
24361f28255Scgd break;
24407cdfa9cSmycroft case 'c':
24507cdfa9cSmycroft commandonly = 1;
24607cdfa9cSmycroft break;
2475a6cfab1Schristos case 'd':
2485a6cfab1Schristos descendancy = 1;
2495a6cfab1Schristos break;
2504d1457ceScgd case 'e': /* XXX set ufmt */
2514d1457ceScgd needenv = 1;
2524d1457ceScgd break;
25361f28255Scgd case 'C':
25461f28255Scgd rawcpu = 1;
25561f28255Scgd break;
25661f28255Scgd case 'g':
25761f28255Scgd break; /* no-op */
258e31566ddScjep case 'G':
259e31566ddScjep if (*optarg != '\0') {
260e31566ddScjep struct group *gr;
261e31566ddScjep
262e31566ddScjep what = KERN_PROC_GID;
263e31566ddScjep gr = getgrnam(optarg);
264e31566ddScjep if (gr == NULL) {
2657c3f3593Schristos flag = parsenum(optarg, "group id");
266e31566ddScjep } else
267e31566ddScjep flag = gr->gr_gid;
268e31566ddScjep }
269e31566ddScjep break;
270e31566ddScjep
27161f28255Scgd case 'h':
27261f28255Scgd prtheader = ws.ws_row > 5 ? ws.ws_row : 22;
27361f28255Scgd break;
27461f28255Scgd case 'j':
27561f28255Scgd parsefmt(jfmt);
2763541700dSmycroft fmt = 1;
27761f28255Scgd jfmt[0] = '\0';
27861f28255Scgd break;
279036e2657Sdsl case 'k':
280036e2657Sdsl parsesort(optarg);
281036e2657Sdsl break;
28205e0706aSbgrayson case 'K':
283fc257046Sjdolecek break; /* no-op - was dontuseprocfs */
28461f28255Scgd case 'L':
28561f28255Scgd showkey();
286078edf9cSrin return 0;
28761f28255Scgd case 'l':
28861f28255Scgd parsefmt(lfmt);
2893541700dSmycroft fmt = 1;
29061f28255Scgd lfmt[0] = '\0';
29161f28255Scgd break;
29261f28255Scgd case 'M':
29361f28255Scgd memf = optarg;
29461f28255Scgd break;
29561f28255Scgd case 'm':
296036e2657Sdsl parsesort("vsz");
29761f28255Scgd break;
29861f28255Scgd case 'N':
29961f28255Scgd nlistf = optarg;
30061f28255Scgd break;
30161f28255Scgd case 'O':
302d9463bc1Sapb /*
303d9463bc1Sapb * If this is not the first -O option, insert
304d9463bc1Sapb * just after the previous one.
305d9463bc1Sapb *
306d9463bc1Sapb * If there is no format yet, start with the default
307d9463bc1Sapb * format, and insert after the pid column.
308d9463bc1Sapb *
309d9463bc1Sapb * If there is already a format, insert after
310d9463bc1Sapb * the pid column, or at the end if there's no
311d9463bc1Sapb * pid column.
312d9463bc1Sapb */
313d9463bc1Sapb if (!Opos) {
314d9463bc1Sapb if (!fmt)
315ea03f830Syamt parsefmt(default_fmt);
316d9463bc1Sapb Opos = varlist_find(&displaylist, "pid");
317d9463bc1Sapb }
318d9463bc1Sapb parsefmt_insert(optarg, &Opos);
3193541700dSmycroft fmt = 1;
32061f28255Scgd break;
32161f28255Scgd case 'o':
32261f28255Scgd parsefmt(optarg);
3233541700dSmycroft fmt = 1;
32461f28255Scgd break;
32561f28255Scgd case 'p':
326975ed852Smycroft what = KERN_PROC_PID;
32710ed3a58Schristos flag = parsenum(optarg, "process id");
32861f28255Scgd xflg = 1;
32961f28255Scgd break;
33061f28255Scgd case 'r':
331036e2657Sdsl parsesort("%cpu");
33261f28255Scgd break;
33361f28255Scgd case 'S':
33461f28255Scgd sumrusage = 1;
33561f28255Scgd break;
3363fdac2b8Sthorpej case 's':
3373fdac2b8Sthorpej /* -L was already taken... */
3383fdac2b8Sthorpej showlwps = 1;
339ea03f830Syamt default_fmt = sfmt;
3403fdac2b8Sthorpej break;
34161f28255Scgd case 'T':
3420e2f9ea9Smycroft if ((ttname = ttyname(STDIN_FILENO)) == NULL)
343b02b35c9Schristos errx(EXIT_FAILURE, "stdin: not a terminal");
344763e5791Sjoerg flag = ttyname2dev(ttname, &xflg, &what);
34561f28255Scgd break;
346763e5791Sjoerg case 't':
347763e5791Sjoerg flag = ttyname2dev(optarg, &xflg, &what);
348763e5791Sjoerg break;
349975ed852Smycroft case 'U':
350975ed852Smycroft if (*optarg != '\0') {
351975ed852Smycroft struct passwd *pw;
352975ed852Smycroft
353975ed852Smycroft what = KERN_PROC_UID;
354975ed852Smycroft pw = getpwnam(optarg);
355975ed852Smycroft if (pw == NULL) {
3567c3f3593Schristos flag = parsenum(optarg, "user id");
357975ed852Smycroft } else
358975ed852Smycroft flag = pw->pw_uid;
359975ed852Smycroft }
360975ed852Smycroft break;
36161f28255Scgd case 'u':
36261f28255Scgd parsefmt(ufmt);
363036e2657Sdsl parsesort("%cpu");
3643541700dSmycroft fmt = 1;
36561f28255Scgd ufmt[0] = '\0';
36661f28255Scgd break;
36761f28255Scgd case 'v':
36861f28255Scgd parsefmt(vfmt);
369036e2657Sdsl parsesort("vsz");
3703541700dSmycroft fmt = 1;
37161f28255Scgd vfmt[0] = '\0';
37261f28255Scgd break;
37361f28255Scgd case 'W':
37461f28255Scgd swapf = optarg;
37561f28255Scgd break;
37661f28255Scgd case 'w':
3774434a6edScgd if (wflag)
37861f28255Scgd termwidth = UNLIMITED;
3794434a6edScgd else if (termwidth < 131)
3804434a6edScgd termwidth = 131;
3814434a6edScgd wflag++;
38261f28255Scgd break;
38361f28255Scgd case 'x':
38461f28255Scgd xflg = 1;
38561f28255Scgd break;
38661f28255Scgd case '?':
38761f28255Scgd default:
38861f28255Scgd usage();
38961f28255Scgd }
39061f28255Scgd argc -= optind;
39161f28255Scgd argv += optind;
39261f28255Scgd
39361f28255Scgd #define BACKWARD_COMPATIBILITY
39461f28255Scgd #ifdef BACKWARD_COMPATIBILITY
39561f28255Scgd if (*argv) {
39661f28255Scgd nlistf = *argv;
39761f28255Scgd if (*++argv) {
39861f28255Scgd memf = *argv;
39961f28255Scgd if (*++argv)
40061f28255Scgd swapf = *argv;
40161f28255Scgd }
40261f28255Scgd }
40361f28255Scgd #endif
4044d1457ceScgd
405036e2657Sdsl if (memf == NULL) {
406036e2657Sdsl kd = kvm_openfiles(NULL, NULL, NULL, KVM_NO_FILES, errbuf);
407fd521aefSsimonb donlist_sysctl();
408fd521aefSsimonb } else
4094d1457ceScgd kd = kvm_openfiles(nlistf, memf, swapf, O_RDONLY, errbuf);
410fd521aefSsimonb
411078edf9cSrin if (kd == NULL)
412b02b35c9Schristos errx(EXIT_FAILURE, "%s", errbuf);
41361f28255Scgd
4143541700dSmycroft if (!fmt)
415ea03f830Syamt parsefmt(default_fmt);
41661f28255Scgd
417036e2657Sdsl /* Add default sort criteria */
418036e2657Sdsl parsesort("tdev,pid");
419cc1877baSrin calc_pcpu = 0;
420d9463bc1Sapb SIMPLEQ_FOREACH(vent, &sortlist, next) {
421036e2657Sdsl if (vent->var->flag & LWP || vent->var->type == UNSPECIFIED)
4227da746abSchristos warnx("Cannot sort on %s, sort key ignored",
423036e2657Sdsl vent->var->name);
424cc1877baSrin if (vent->var->type == PCPU)
425cc1877baSrin calc_pcpu = 1;
426cc1877baSrin }
427cc1877baSrin if (!calc_pcpu)
428cc1877baSrin SIMPLEQ_FOREACH(vent, &displaylist, next)
429cc1877baSrin if (vent->var->type == PCPU) {
430cc1877baSrin calc_pcpu = 1;
431cc1877baSrin break;
432036e2657Sdsl }
433036e2657Sdsl
43461f28255Scgd /*
435a98dd470Ssimonb * scan requested variables, noting what structures are needed.
43661f28255Scgd */
43761f28255Scgd scanvars();
438f848d2ecSjdolecek
43961f28255Scgd /*
44061f28255Scgd * select procs
44161f28255Scgd */
4423fdac2b8Sthorpej if (!(kinfo = getkinfo_kvm(kd, what, flag, &nentries)))
443ea7b2892Schristos errx(EXIT_FAILURE, "%s", kvm_geterr(kd));
444a98dd470Ssimonb if (nentries == 0) {
44561f28255Scgd printheader();
446078edf9cSrin return 1;
447a98dd470Ssimonb }
448cc1877baSrin pinfo = setpinfo(kinfo, nentries, calc_pcpu, rawcpu);
449cc1877baSrin
45061f28255Scgd /*
45161f28255Scgd * sort proc list
45261f28255Scgd */
453*9dc307c4Schristos qsort(pinfo, nentries, sizeof(*pinfo), pscomp);
4545a6cfab1Schristos
4555a6cfab1Schristos /*
4565a6cfab1Schristos * We want things in descendant order
4575a6cfab1Schristos */
4585a6cfab1Schristos if (descendancy)
4595a6cfab1Schristos descendant_sort(pinfo, nentries);
4605a6cfab1Schristos
46161f28255Scgd /*
462a98dd470Ssimonb * For each proc, call each variable output function in
463a98dd470Ssimonb * "setwidth" mode to determine the widest element of
464a98dd470Ssimonb * the column.
465a98dd470Ssimonb */
466a468ec49Sdholland
467a98dd470Ssimonb for (i = 0; i < nentries; i++) {
468cc1877baSrin struct pinfo *pi = &pinfo[i];
469cc1877baSrin struct kinfo_proc2 *ki = pi->ki;
470a98dd470Ssimonb
471a5c6617dSchristos if (xflg == 0 && (ki->p_tdev == (uint32_t)NODEV ||
472f5e7ca24Spavel (ki->p_flag & P_CONTROLT) == 0))
473a98dd470Ssimonb continue;
4743fdac2b8Sthorpej
4753fdac2b8Sthorpej kl = kvm_getlwps(kd, ki->p_pid, ki->p_paddr,
476*9dc307c4Schristos sizeof(*kl), &nlwps);
4773fdac2b8Sthorpej if (kl == 0)
4783fdac2b8Sthorpej nlwps = 0;
4793fdac2b8Sthorpej if (showlwps == 0) {
4803fdac2b8Sthorpej l = pick_representative_lwp(ki, kl, nlwps);
481d9463bc1Sapb SIMPLEQ_FOREACH(vent, &displaylist, next)
482cc1877baSrin OUTPUT(vent, l, pi, ki, WIDTHMODE);
4833fdac2b8Sthorpej } else {
4843fdac2b8Sthorpej /* The printing is done with the loops
4853fdac2b8Sthorpej * reversed, but here we don't need that,
4863fdac2b8Sthorpej * and this improves the code locality a bit.
4873fdac2b8Sthorpej */
488d9463bc1Sapb SIMPLEQ_FOREACH(vent, &displaylist, next)
4893fdac2b8Sthorpej for (j = 0; j < nlwps; j++)
490cc1877baSrin OUTPUT(vent, &kl[j], pi, ki, WIDTHMODE);
4913fdac2b8Sthorpej }
492a98dd470Ssimonb }
493a98dd470Ssimonb /*
494a98dd470Ssimonb * Print header - AFTER determining process field widths.
495a98dd470Ssimonb * printheader() also adds up the total width of all
496a98dd470Ssimonb * fields the first time it's called.
497a98dd470Ssimonb */
498a98dd470Ssimonb printheader();
499a98dd470Ssimonb /*
500a98dd470Ssimonb * For each proc, call each variable output function in
501a98dd470Ssimonb * print mode.
50261f28255Scgd */
50361f28255Scgd for (i = lineno = 0; i < nentries; i++) {
504cc1877baSrin struct pinfo *pi = &pinfo[i];
505cc1877baSrin struct kinfo_proc2 *ki = pi->ki;
506d70850c6Smycroft
507a5c6617dSchristos if (xflg == 0 && (ki->p_tdev == (uint32_t)NODEV ||
508f5e7ca24Spavel (ki->p_flag & P_CONTROLT ) == 0))
50961f28255Scgd continue;
5103fdac2b8Sthorpej kl = kvm_getlwps(kd, ki->p_pid, (u_long)ki->p_paddr,
511*9dc307c4Schristos sizeof(*kl), &nlwps);
5123fdac2b8Sthorpej if (kl == 0)
5133fdac2b8Sthorpej nlwps = 0;
5143fdac2b8Sthorpej if (showlwps == 0) {
5153fdac2b8Sthorpej l = pick_representative_lwp(ki, kl, nlwps);
516d9463bc1Sapb SIMPLEQ_FOREACH(vent, &displaylist, next) {
517cc1877baSrin OUTPUT(vent, l, pi, ki, PRINTMODE);
518d9463bc1Sapb if (SIMPLEQ_NEXT(vent, next) != NULL)
5193fdac2b8Sthorpej (void)putchar(' ');
5203fdac2b8Sthorpej }
5213fdac2b8Sthorpej (void)putchar('\n');
5223fdac2b8Sthorpej if (prtheader && lineno++ == prtheader - 4) {
5233fdac2b8Sthorpej (void)putchar('\n');
5243fdac2b8Sthorpej printheader();
5253fdac2b8Sthorpej lineno = 0;
5263fdac2b8Sthorpej }
5273fdac2b8Sthorpej } else {
5283fdac2b8Sthorpej for (j = 0; j < nlwps; j++) {
529d9463bc1Sapb SIMPLEQ_FOREACH(vent, &displaylist, next) {
530cc1877baSrin OUTPUT(vent, &kl[j], pi, ki, PRINTMODE);
531d9463bc1Sapb if (SIMPLEQ_NEXT(vent, next) != NULL)
53261f28255Scgd (void)putchar(' ');
53361f28255Scgd }
53461f28255Scgd (void)putchar('\n');
53561f28255Scgd if (prtheader && lineno++ == prtheader - 4) {
53661f28255Scgd (void)putchar('\n');
53761f28255Scgd printheader();
53861f28255Scgd lineno = 0;
53961f28255Scgd }
54061f28255Scgd }
5413fdac2b8Sthorpej }
5423fdac2b8Sthorpej }
543fd0c6ecfSkamil
5445626006fSkamil #ifdef __NO_LEAKS
545fd0c6ecfSkamil free(pinfo);
5465626006fSkamil #endif
547fd0c6ecfSkamil
548078edf9cSrin return eval;
54961f28255Scgd }
55061f28255Scgd
5513fdac2b8Sthorpej static struct kinfo_lwp *
pick_representative_lwp(struct kinfo_proc2 * ki,struct kinfo_lwp * kl,int nlwps)55253474900Ssimonb pick_representative_lwp(struct kinfo_proc2 *ki, struct kinfo_lwp *kl, int nlwps)
5533fdac2b8Sthorpej {
5543fdac2b8Sthorpej int i, onproc, running, sleeping, stopped, suspended;
5553fdac2b8Sthorpej static struct kinfo_lwp zero_lwp;
5563fdac2b8Sthorpej
5573fdac2b8Sthorpej if (kl == 0)
5583fdac2b8Sthorpej return &zero_lwp;
5593fdac2b8Sthorpej
5603fdac2b8Sthorpej /* Trivial case: only one LWP */
5613fdac2b8Sthorpej if (nlwps == 1)
5623fdac2b8Sthorpej return kl;
5633fdac2b8Sthorpej
5643fdac2b8Sthorpej switch (ki->p_realstat) {
5653fdac2b8Sthorpej case SSTOP:
5663fdac2b8Sthorpej case SACTIVE:
5673fdac2b8Sthorpej /* Pick the most live LWP */
5683fdac2b8Sthorpej onproc = running = sleeping = stopped = suspended = -1;
5693fdac2b8Sthorpej for (i = 0; i < nlwps; i++) {
5703fdac2b8Sthorpej switch (kl[i].l_stat) {
5713fdac2b8Sthorpej case LSONPROC:
5723fdac2b8Sthorpej onproc = i;
5733fdac2b8Sthorpej break;
5743fdac2b8Sthorpej case LSRUN:
5753fdac2b8Sthorpej running = i;
5763fdac2b8Sthorpej break;
5773fdac2b8Sthorpej case LSSLEEP:
5783fdac2b8Sthorpej sleeping = i;
5793fdac2b8Sthorpej break;
5803fdac2b8Sthorpej case LSSTOP:
5813fdac2b8Sthorpej stopped = i;
5823fdac2b8Sthorpej break;
5833fdac2b8Sthorpej case LSSUSPENDED:
5843fdac2b8Sthorpej suspended = i;
5853fdac2b8Sthorpej break;
5863fdac2b8Sthorpej }
5873fdac2b8Sthorpej }
5883fdac2b8Sthorpej if (onproc != -1)
5893fdac2b8Sthorpej return &kl[onproc];
5903fdac2b8Sthorpej if (running != -1)
5913fdac2b8Sthorpej return &kl[running];
5923fdac2b8Sthorpej if (sleeping != -1)
5933fdac2b8Sthorpej return &kl[sleeping];
5943fdac2b8Sthorpej if (stopped != -1)
5953fdac2b8Sthorpej return &kl[stopped];
5963fdac2b8Sthorpej if (suspended != -1)
5973fdac2b8Sthorpej return &kl[suspended];
5983fdac2b8Sthorpej break;
5993fdac2b8Sthorpej case SZOMB:
6003fdac2b8Sthorpej /* First will do */
6013fdac2b8Sthorpej return kl;
6023fdac2b8Sthorpej break;
6033fdac2b8Sthorpej }
6043fdac2b8Sthorpej /* Error condition! */
6057da746abSchristos warnx("Inconsistent LWP state for process %d", ki->p_pid);
6063fdac2b8Sthorpej return kl;
6073fdac2b8Sthorpej }
6083fdac2b8Sthorpej
609fd521aefSsimonb static struct kinfo_proc2 *
getkinfo_kvm(kvm_t * kdp,int what,int flag,int * nentriesp)61053474900Ssimonb getkinfo_kvm(kvm_t *kdp, int what, int flag, int *nentriesp)
611f848d2ecSjdolecek {
61253474900Ssimonb
613*9dc307c4Schristos return kvm_getproc2(kdp, what, flag, sizeof(struct kinfo_proc2),
614*9dc307c4Schristos nentriesp);
615f848d2ecSjdolecek }
616f848d2ecSjdolecek
617cc1877baSrin static struct pinfo *
setpinfo(struct kinfo_proc2 * ki,int nentries,int calc_pcpu,int rawcpu)618cc1877baSrin setpinfo(struct kinfo_proc2 *ki, int nentries, int calc_pcpu, int rawcpu)
619cc1877baSrin {
620cc1877baSrin struct pinfo *pi;
621cc1877baSrin int i;
622cc1877baSrin
623*9dc307c4Schristos pi = ecalloc(nentries, sizeof(*pi));
624cc1877baSrin if (calc_pcpu && !nlistread)
625cc1877baSrin donlist();
626cc1877baSrin
627cc1877baSrin for (i = 0; i < nentries; i++) {
628cc1877baSrin pi[i].ki = &ki[i];
629cc1877baSrin if (!calc_pcpu)
630cc1877baSrin continue;
631f637bb05Srin if (ki[i].p_swtime == 0 || ki[i].p_realstat == SZOMB) {
632cc1877baSrin pi[i].pcpu = 0.0;
633cc1877baSrin continue;
634cc1877baSrin }
635cc1877baSrin pi[i].pcpu = 100.0 * (double)ki[i].p_pctcpu / fscale;
636cc1877baSrin if (!rawcpu)
637cc1877baSrin pi[i].pcpu /= 1.0 - exp(ki[i].p_swtime * log_ccpu);
638cc1877baSrin }
639cc1877baSrin
640cc1877baSrin return pi;
641cc1877baSrin }
642cc1877baSrin
6434d1457ceScgd static void
scanvars(void)64453474900Ssimonb scanvars(void)
64561f28255Scgd {
6464d1457ceScgd struct varent *vent;
6474d1457ceScgd VAR *v;
64861f28255Scgd
649d9463bc1Sapb SIMPLEQ_FOREACH(vent, &displaylist, next) {
65061f28255Scgd v = vent->var;
651c6458f33Smatt if (v->flag & COMM) {
65261f28255Scgd needcomm = 1;
653c6458f33Smatt break;
654c6458f33Smatt }
65561f28255Scgd }
65661f28255Scgd }
65761f28255Scgd
6584d1457ceScgd static int
pscomp(const void * a,const void * b)659036e2657Sdsl pscomp(const void *a, const void *b)
66061f28255Scgd {
661cc1877baSrin const struct pinfo *pa = (const struct pinfo *)a;
662cc1877baSrin const struct pinfo *pb = (const struct pinfo *)b;
663cc1877baSrin const struct kinfo_proc2 *ka = pa->ki;
664cc1877baSrin const struct kinfo_proc2 *kb = pb->ki;
665fd521aefSsimonb
66661f28255Scgd int i;
667036e2657Sdsl int64_t i64;
668036e2657Sdsl VAR *v;
669036e2657Sdsl struct varent *ve;
6706310b596Schristos const sigset_t *sa, *sb;
67161f28255Scgd
672fcc02354Smrg #define V_SIZE(k) ((k)->p_vm_msize)
673036e2657Sdsl #define RDIFF_N(t, n) \
6746310b596Schristos if (((const t *)((const char *)ka + v->off))[n] > ((const t *)((const char *)kb + v->off))[n]) \
675036e2657Sdsl return 1; \
6766310b596Schristos if (((const t *)((const char *)ka + v->off))[n] < ((const t *)((const char *)kb + v->off))[n]) \
677036e2657Sdsl return -1;
678fd521aefSsimonb
679036e2657Sdsl #define RDIFF(type) RDIFF_N(type, 0); continue
680036e2657Sdsl
681d9463bc1Sapb SIMPLEQ_FOREACH(ve, &sortlist, next) {
682036e2657Sdsl v = ve->var;
683036e2657Sdsl if (v->flag & LWP)
684036e2657Sdsl /* LWP structure not available (yet) */
685036e2657Sdsl continue;
686036e2657Sdsl /* Sort on pvar() fields, + a few others */
687036e2657Sdsl switch (v->type) {
688036e2657Sdsl case CHAR:
689036e2657Sdsl RDIFF(char);
690036e2657Sdsl case UCHAR:
691036e2657Sdsl RDIFF(u_char);
692036e2657Sdsl case SHORT:
693036e2657Sdsl RDIFF(short);
694036e2657Sdsl case USHORT:
695036e2657Sdsl RDIFF(ushort);
696036e2657Sdsl case INT:
697036e2657Sdsl RDIFF(int);
698036e2657Sdsl case UINT:
699036e2657Sdsl RDIFF(uint);
700036e2657Sdsl case LONG:
701036e2657Sdsl RDIFF(long);
702036e2657Sdsl case ULONG:
703036e2657Sdsl RDIFF(ulong);
704036e2657Sdsl case INT32:
705036e2657Sdsl RDIFF(int32_t);
706036e2657Sdsl case UINT32:
707036e2657Sdsl RDIFF(uint32_t);
708036e2657Sdsl case SIGLIST:
709cc1877baSrin sa = (const void *)((const char *)ka + v->off);
710cc1877baSrin sb = (const void *)((const char *)kb + v->off);
711036e2657Sdsl i = 0;
712036e2657Sdsl do {
713036e2657Sdsl if (sa->__bits[i] > sb->__bits[i])
714036e2657Sdsl return 1;
715036e2657Sdsl if (sa->__bits[i] < sb->__bits[i])
716036e2657Sdsl return -1;
717036e2657Sdsl i++;
718990d25a9Slukem } while (i < (int)__arraycount(sa->__bits));
719036e2657Sdsl continue;
720036e2657Sdsl case INT64:
721036e2657Sdsl RDIFF(int64_t);
722036e2657Sdsl case KPTR:
723036e2657Sdsl case KPTR24:
724036e2657Sdsl case UINT64:
725036e2657Sdsl RDIFF(uint64_t);
726036e2657Sdsl case TIMEVAL:
727036e2657Sdsl /* compare xxx_sec then xxx_usec */
728036e2657Sdsl RDIFF_N(uint32_t, 0);
729036e2657Sdsl RDIFF_N(uint32_t, 1);
730036e2657Sdsl continue;
731036e2657Sdsl case CPUTIME:
732036e2657Sdsl i64 = ka->p_rtime_sec * 1000000 + ka->p_rtime_usec;
733036e2657Sdsl i64 -= kb->p_rtime_sec * 1000000 + kb->p_rtime_usec;
734036e2657Sdsl if (sumrusage) {
735036e2657Sdsl i64 += ka->p_uctime_sec * 1000000
736036e2657Sdsl + ka->p_uctime_usec;
737036e2657Sdsl i64 -= kb->p_uctime_sec * 1000000
738036e2657Sdsl + kb->p_uctime_usec;
739036e2657Sdsl }
740036e2657Sdsl if (i64 != 0)
741036e2657Sdsl return i64 > 0 ? 1 : -1;
742036e2657Sdsl continue;
743036e2657Sdsl case PCPU:
744cc1877baSrin i = pb->pcpu - pa->pcpu;
745036e2657Sdsl if (i != 0)
746036e2657Sdsl return i;
747036e2657Sdsl continue;
748036e2657Sdsl case VSIZE:
749036e2657Sdsl i = V_SIZE(kb) - V_SIZE(ka);
750036e2657Sdsl if (i != 0)
751036e2657Sdsl return i;
752036e2657Sdsl continue;
753036e2657Sdsl
754036e2657Sdsl default:
755036e2657Sdsl /* Ignore everything else */
756036e2657Sdsl break;
757036e2657Sdsl }
758036e2657Sdsl }
759036e2657Sdsl return 0;
760036e2657Sdsl
761036e2657Sdsl #undef VSIZE
76261f28255Scgd }
76361f28255Scgd
76461f28255Scgd /*
76561f28255Scgd * ICK (all for getopt), would rather hide the ugliness
76661f28255Scgd * here than taint the main code.
76761f28255Scgd *
76861f28255Scgd * ps foo -> ps -foo
76961f28255Scgd * ps 34 -> ps -p34
77061f28255Scgd *
771975ed852Smycroft * The old convention that 't' with no trailing tty arg means the user's
77261f28255Scgd * tty, is only supported if argv[1] doesn't begin with a '-'. This same
77361f28255Scgd * feature is available with the option 'T', which takes no argument.
77461f28255Scgd */
7754d1457ceScgd static char *
kludge_oldps_options(char * s)77653474900Ssimonb kludge_oldps_options(char *s)
77761f28255Scgd {
77861f28255Scgd size_t len;
77961f28255Scgd char *newopts, *ns, *cp;
78061f28255Scgd
78161f28255Scgd len = strlen(s);
782*9dc307c4Schristos newopts = ns = emalloc(len + 3);
78361f28255Scgd /*
78461f28255Scgd * options begin with '-'
78561f28255Scgd */
78661f28255Scgd if (*s != '-')
78761f28255Scgd *ns++ = '-'; /* add option flag */
78861f28255Scgd /*
78961f28255Scgd * gaze to end of argv[1]
79061f28255Scgd */
79161f28255Scgd cp = s + len - 1;
79261f28255Scgd /*
793d530ee00Ssimonb * if the last letter is a 't' flag and there are no other option
794d530ee00Ssimonb * characters that take arguments (eg U, p, o) in the option
795d530ee00Ssimonb * string and the option string doesn't start with a '-' then
796d530ee00Ssimonb * convert to 'T' (meaning *this* terminal, i.e. ttyname(0)).
79761f28255Scgd */
798d530ee00Ssimonb if (*cp == 't' && *s != '-' && strpbrk(s, ARGOPTS) == NULL)
79961f28255Scgd *cp = 'T';
80061f28255Scgd else {
80161f28255Scgd /*
80261f28255Scgd * otherwise check for trailing number, which *may* be a
80361f28255Scgd * pid.
80461f28255Scgd */
805238960afSdsl while (cp >= s && isdigit((unsigned char)*cp))
80661f28255Scgd --cp;
80761f28255Scgd }
80861f28255Scgd cp++;
8094d1457ceScgd memmove(ns, s, (size_t)(cp - s)); /* copy up to trailing number */
81061f28255Scgd ns += cp - s;
81161f28255Scgd /*
81261f28255Scgd * if there's a trailing number, and not a preceding 'p' (pid) or
81361f28255Scgd * 't' (tty) flag, then assume it's a pid and insert a 'p' flag.
81461f28255Scgd */
815238960afSdsl if (isdigit((unsigned char)*cp) &&
816975ed852Smycroft (cp == s || (cp[-1] != 'U' && cp[-1] != 't' && cp[-1] != 'p' &&
817fde0dde8Satatat cp[-1] != '/' && (cp - 1 == s || cp[-2] != 't'))))
81861f28255Scgd *ns++ = 'p';
819ecdc5967Smrg /* and append the number */
820d530ee00Ssimonb (void)strcpy(ns, cp); /* XXX strcpy is safe here */
82161f28255Scgd
82261f28255Scgd return (newopts);
82361f28255Scgd }
82461f28255Scgd
82510ed3a58Schristos static int
parsenum(const char * str,const char * msg)82610ed3a58Schristos parsenum(const char *str, const char *msg)
82710ed3a58Schristos {
82810ed3a58Schristos char *ep;
82910ed3a58Schristos unsigned long ul;
83010ed3a58Schristos
83110ed3a58Schristos ul = strtoul(str, &ep, 0);
83210ed3a58Schristos
83310ed3a58Schristos if (*str == '\0' || *ep != '\0')
834b02b35c9Schristos errx(EXIT_FAILURE, "Invalid %s: `%s'", msg, str);
83510ed3a58Schristos
83610ed3a58Schristos if (ul > INT_MAX)
837b02b35c9Schristos errx(EXIT_FAILURE, "Out of range %s: `%s'", msg, str);
83810ed3a58Schristos
83910ed3a58Schristos return (int)ul;
84010ed3a58Schristos }
84110ed3a58Schristos
8424d1457ceScgd static void
descendant_sort(struct pinfo * ki,int items)8435a6cfab1Schristos descendant_sort(struct pinfo *ki, int items)
8445a6cfab1Schristos {
8455a6cfab1Schristos int dst, lvl, maxlvl, n, ndst, nsrc, siblings, src;
8465a6cfab1Schristos unsigned char *path;
8475a6cfab1Schristos struct pinfo kn;
8485a6cfab1Schristos
8495a6cfab1Schristos /*
8505a6cfab1Schristos * First, sort the entries by descendancy, tracking the descendancy
8515a6cfab1Schristos * depth in the level field.
8525a6cfab1Schristos */
8535a6cfab1Schristos src = 0;
8545a6cfab1Schristos maxlvl = 0;
8555a6cfab1Schristos while (src < items) {
8565a6cfab1Schristos if (ki[src].level) {
8575a6cfab1Schristos src++;
8585a6cfab1Schristos continue;
8595a6cfab1Schristos }
8605a6cfab1Schristos for (nsrc = 1; src + nsrc < items; nsrc++)
8615a6cfab1Schristos if (!ki[src + nsrc].level)
8625a6cfab1Schristos break;
8635a6cfab1Schristos
8645a6cfab1Schristos for (dst = 0; dst < items; dst++) {
8655a6cfab1Schristos if (ki[dst].ki->p_pid == ki[src].ki->p_pid)
8665a6cfab1Schristos continue;
8675a6cfab1Schristos if (ki[dst].ki->p_pid == ki[src].ki->p_ppid)
8685a6cfab1Schristos break;
8695a6cfab1Schristos }
8705a6cfab1Schristos
8715a6cfab1Schristos if (dst == items) {
8725a6cfab1Schristos src += nsrc;
8735a6cfab1Schristos continue;
8745a6cfab1Schristos }
8755a6cfab1Schristos
8765a6cfab1Schristos for (ndst = 1; dst + ndst < items; ndst++)
8775a6cfab1Schristos if (ki[dst + ndst].level <= ki[dst].level)
8785a6cfab1Schristos break;
8795a6cfab1Schristos
8805a6cfab1Schristos for (n = src; n < src + nsrc; n++) {
8815a6cfab1Schristos ki[n].level += ki[dst].level + 1;
8825a6cfab1Schristos if (maxlvl < ki[n].level)
8835a6cfab1Schristos maxlvl = ki[n].level;
8845a6cfab1Schristos }
8855a6cfab1Schristos
8865a6cfab1Schristos while (nsrc) {
8875a6cfab1Schristos if (src < dst) {
8885a6cfab1Schristos kn = ki[src];
8895a6cfab1Schristos memmove(ki + src, ki + src + 1,
890*9dc307c4Schristos (dst - src + ndst - 1) * sizeof(*ki));
8915a6cfab1Schristos ki[dst + ndst - 1] = kn;
8925a6cfab1Schristos nsrc--;
8935a6cfab1Schristos dst--;
8945a6cfab1Schristos ndst++;
8955a6cfab1Schristos } else if (src != dst + ndst) {
8965a6cfab1Schristos kn = ki[src];
8975a6cfab1Schristos memmove(ki + dst + ndst + 1, ki + dst + ndst,
898*9dc307c4Schristos (src - dst - ndst) * sizeof(*ki));
8995a6cfab1Schristos ki[dst + ndst] = kn;
9005a6cfab1Schristos ndst++;
9015a6cfab1Schristos nsrc--;
9025a6cfab1Schristos src++;
9035a6cfab1Schristos } else {
9045a6cfab1Schristos ndst += nsrc;
9055a6cfab1Schristos src += nsrc;
9065a6cfab1Schristos nsrc = 0;
9075a6cfab1Schristos }
9085a6cfab1Schristos }
9095a6cfab1Schristos }
9105a6cfab1Schristos
9115a6cfab1Schristos /*
9125a6cfab1Schristos * Now populate prefix (instead of level) with the command
9135a6cfab1Schristos * prefix used to show descendancies.
9145a6cfab1Schristos */
915*9dc307c4Schristos path = ecalloc((maxlvl + 7) / 8, 1);
9165a6cfab1Schristos for (src = 0; src < items; src++) {
9175a6cfab1Schristos if ((lvl = ki[src].level) == 0) {
9185a6cfab1Schristos ki[src].prefix = NULL;
9195a6cfab1Schristos continue;
9205a6cfab1Schristos }
921*9dc307c4Schristos ki[src].prefix = emalloc(lvl * 2 + 1);
9225a6cfab1Schristos for (n = 0; n < lvl - 2; n++) {
9235a6cfab1Schristos ki[src].prefix[n * 2] =
9245a6cfab1Schristos path[n / 8] & 1 << (n % 8) ? '|' : ' ';
9255a6cfab1Schristos ki[src].prefix[n * 2 + 1] = ' ';
9265a6cfab1Schristos
9275a6cfab1Schristos }
9285a6cfab1Schristos if (n == lvl - 2) {
9295a6cfab1Schristos /* Have I any more siblings? */
9305a6cfab1Schristos for (siblings = 0, dst = src + 1; dst < items; dst++) {
9315a6cfab1Schristos if (ki[dst].level > lvl)
9325a6cfab1Schristos continue;
9335a6cfab1Schristos if (ki[dst].level == lvl)
9345a6cfab1Schristos siblings = 1;
9355a6cfab1Schristos break;
9365a6cfab1Schristos }
9375a6cfab1Schristos if (siblings)
9385a6cfab1Schristos path[n / 8] |= 1 << (n % 8);
9395a6cfab1Schristos else
9405a6cfab1Schristos path[n / 8] &= ~(1 << (n % 8));
9415a6cfab1Schristos ki[src].prefix[n * 2] = siblings ? '|' : '`';
9425a6cfab1Schristos ki[src].prefix[n * 2 + 1] = '-';
9435a6cfab1Schristos n++;
9445a6cfab1Schristos }
9455a6cfab1Schristos strcpy(ki[src].prefix + n * 2, "- ");
9465a6cfab1Schristos }
9475a6cfab1Schristos free(path);
9485a6cfab1Schristos }
9495a6cfab1Schristos
9505a6cfab1Schristos static void
usage(void)95153474900Ssimonb usage(void)
95261f28255Scgd {
9534d1457ceScgd
95461f28255Scgd (void)fprintf(stderr,
9554d1457ceScgd "usage:\t%s\n\t %s\n\t%s\n",
956de71cbe1Swiz "ps [-AaCcdehjlmrSsTuvwx] [-G group] [-k key] [-M core] [-N system]",
957de71cbe1Swiz "[-O fmt] [-o fmt] [-p pid] [-t tty] [-U user] [-W swap]",
9582869cb06Swiz "ps -L");
95961f28255Scgd exit(1);
9609dc385beSmycroft /* NOTREACHED */
96161f28255Scgd }
962