ps.c revision 1.46.2.2 1 1.46.2.2 nathanw /* $NetBSD: ps.c,v 1.46.2.2 2002/04/23 20:41:14 nathanw Exp $ */
2 1.46.2.2 nathanw
3 1.46.2.2 nathanw /*
4 1.46.2.2 nathanw * Copyright (c) 2000 The NetBSD Foundation, Inc.
5 1.46.2.2 nathanw * All rights reserved.
6 1.46.2.2 nathanw *
7 1.46.2.2 nathanw * This code is derived from software contributed to The NetBSD Foundation
8 1.46.2.2 nathanw * by Simon Burge.
9 1.46.2.2 nathanw *
10 1.46.2.2 nathanw * Redistribution and use in source and binary forms, with or without
11 1.46.2.2 nathanw * modification, are permitted provided that the following conditions
12 1.46.2.2 nathanw * are met:
13 1.46.2.2 nathanw * 1. Redistributions of source code must retain the above copyright
14 1.46.2.2 nathanw * notice, this list of conditions and the following disclaimer.
15 1.46.2.2 nathanw * 2. Redistributions in binary form must reproduce the above copyright
16 1.46.2.2 nathanw * notice, this list of conditions and the following disclaimer in the
17 1.46.2.2 nathanw * documentation and/or other materials provided with the distribution.
18 1.46.2.2 nathanw * 3. All advertising materials mentioning features or use of this software
19 1.46.2.2 nathanw * must display the following acknowledgement:
20 1.46.2.2 nathanw * This product includes software developed by the NetBSD
21 1.46.2.2 nathanw * Foundation, Inc. and its contributors.
22 1.46.2.2 nathanw * 4. Neither the name of The NetBSD Foundation nor the names of its
23 1.46.2.2 nathanw * contributors may be used to endorse or promote products derived
24 1.46.2.2 nathanw * from this software without specific prior written permission.
25 1.46.2.2 nathanw *
26 1.46.2.2 nathanw * THIS SOFTWARE IS PROVIDED BY THE NETBSD FOUNDATION, INC. AND CONTRIBUTORS
27 1.46.2.2 nathanw * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED
28 1.46.2.2 nathanw * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
29 1.46.2.2 nathanw * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE FOUNDATION OR CONTRIBUTORS
30 1.46.2.2 nathanw * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
31 1.46.2.2 nathanw * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
32 1.46.2.2 nathanw * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
33 1.46.2.2 nathanw * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
34 1.46.2.2 nathanw * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
35 1.46.2.2 nathanw * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
36 1.46.2.2 nathanw * POSSIBILITY OF SUCH DAMAGE.
37 1.46.2.2 nathanw */
38 1.46.2.2 nathanw
39 1.46.2.2 nathanw /*
40 1.46.2.2 nathanw * Copyright (c) 1990, 1993, 1994
41 1.46.2.2 nathanw * The Regents of the University of California. All rights reserved.
42 1.46.2.2 nathanw *
43 1.46.2.2 nathanw * Redistribution and use in source and binary forms, with or without
44 1.46.2.2 nathanw * modification, are permitted provided that the following conditions
45 1.46.2.2 nathanw * are met:
46 1.46.2.2 nathanw * 1. Redistributions of source code must retain the above copyright
47 1.46.2.2 nathanw * notice, this list of conditions and the following disclaimer.
48 1.46.2.2 nathanw * 2. Redistributions in binary form must reproduce the above copyright
49 1.46.2.2 nathanw * notice, this list of conditions and the following disclaimer in the
50 1.46.2.2 nathanw * documentation and/or other materials provided with the distribution.
51 1.46.2.2 nathanw * 3. All advertising materials mentioning features or use of this software
52 1.46.2.2 nathanw * must display the following acknowledgement:
53 1.46.2.2 nathanw * This product includes software developed by the University of
54 1.46.2.2 nathanw * California, Berkeley and its contributors.
55 1.46.2.2 nathanw * 4. Neither the name of the University nor the names of its contributors
56 1.46.2.2 nathanw * may be used to endorse or promote products derived from this software
57 1.46.2.2 nathanw * without specific prior written permission.
58 1.46.2.2 nathanw *
59 1.46.2.2 nathanw * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
60 1.46.2.2 nathanw * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
61 1.46.2.2 nathanw * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
62 1.46.2.2 nathanw * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
63 1.46.2.2 nathanw * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
64 1.46.2.2 nathanw * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
65 1.46.2.2 nathanw * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
66 1.46.2.2 nathanw * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
67 1.46.2.2 nathanw * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
68 1.46.2.2 nathanw * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
69 1.46.2.2 nathanw * SUCH DAMAGE.
70 1.46.2.2 nathanw */
71 1.46.2.2 nathanw
72 1.46.2.2 nathanw #include <sys/cdefs.h>
73 1.46.2.2 nathanw #ifndef lint
74 1.46.2.2 nathanw __COPYRIGHT("@(#) Copyright (c) 1990, 1993, 1994\n\
75 1.46.2.2 nathanw The Regents of the University of California. All rights reserved.\n");
76 1.46.2.2 nathanw #endif /* not lint */
77 1.46.2.2 nathanw
78 1.46.2.2 nathanw #ifndef lint
79 1.46.2.2 nathanw #if 0
80 1.46.2.2 nathanw static char sccsid[] = "@(#)ps.c 8.4 (Berkeley) 4/2/94";
81 1.46.2.2 nathanw #else
82 1.46.2.2 nathanw __RCSID("$NetBSD: ps.c,v 1.46.2.2 2002/04/23 20:41:14 nathanw Exp $");
83 1.46.2.2 nathanw #endif
84 1.46.2.2 nathanw #endif /* not lint */
85 1.46.2.2 nathanw
86 1.46.2.2 nathanw #include <sys/param.h>
87 1.46.2.2 nathanw #include <sys/user.h>
88 1.46.2.2 nathanw #include <sys/time.h>
89 1.46.2.2 nathanw #include <sys/resource.h>
90 1.46.2.2 nathanw #include <sys/lwp.h>
91 1.46.2.2 nathanw #include <sys/proc.h>
92 1.46.2.2 nathanw #include <sys/stat.h>
93 1.46.2.2 nathanw #include <sys/ioctl.h>
94 1.46.2.2 nathanw #include <sys/sysctl.h>
95 1.46.2.2 nathanw
96 1.46.2.2 nathanw #include <ctype.h>
97 1.46.2.2 nathanw #include <err.h>
98 1.46.2.2 nathanw #include <errno.h>
99 1.46.2.2 nathanw #include <fcntl.h>
100 1.46.2.2 nathanw #include <kvm.h>
101 1.46.2.2 nathanw #include <limits.h>
102 1.46.2.2 nathanw #include <nlist.h>
103 1.46.2.2 nathanw #include <paths.h>
104 1.46.2.2 nathanw #include <pwd.h>
105 1.46.2.2 nathanw #include <stdio.h>
106 1.46.2.2 nathanw #include <stdlib.h>
107 1.46.2.2 nathanw #include <string.h>
108 1.46.2.2 nathanw #include <unistd.h>
109 1.46.2.2 nathanw
110 1.46.2.2 nathanw #include "ps.h"
111 1.46.2.2 nathanw
112 1.46.2.2 nathanw /*
113 1.46.2.2 nathanw * ARGOPTS must contain all option characters that take arguments
114 1.46.2.2 nathanw * (except for 't'!) - it is used in kludge_oldps_options()
115 1.46.2.2 nathanw */
116 1.46.2.2 nathanw #define GETOPTSTR "acCeghjLlM:mN:O:o:p:rSsTt:U:uvW:wx"
117 1.46.2.2 nathanw #define ARGOPTS "MNOopUW"
118 1.46.2.2 nathanw
119 1.46.2.2 nathanw struct kinfo_proc2 *kinfo;
120 1.46.2.2 nathanw struct varent *vhead, *vtail;
121 1.46.2.2 nathanw
122 1.46.2.2 nathanw int eval; /* exit value */
123 1.46.2.2 nathanw int rawcpu; /* -C */
124 1.46.2.2 nathanw int sumrusage; /* -S */
125 1.46.2.2 nathanw int termwidth; /* width of screen (0 == infinity) */
126 1.46.2.2 nathanw int totwidth; /* calculated width of requested variables */
127 1.46.2.2 nathanw
128 1.46.2.2 nathanw int needcomm, needenv, commandonly;
129 1.46.2.2 nathanw uid_t myuid;
130 1.46.2.2 nathanw
131 1.46.2.2 nathanw enum sort { DEFAULT, SORTMEM, SORTCPU } sortby = DEFAULT;
132 1.46.2.2 nathanw
133 1.46.2.2 nathanw static struct kinfo_lwp
134 1.46.2.2 nathanw *pick_representative_lwp __P((struct kinfo_proc2 *,
135 1.46.2.2 nathanw struct kinfo_lwp *, int));
136 1.46.2.2 nathanw static struct kinfo_proc2
137 1.46.2.2 nathanw *getkinfo_kvm __P((kvm_t *, int, int, int *));
138 1.46.2.2 nathanw static char *kludge_oldps_options __P((char *));
139 1.46.2.2 nathanw static int pscomp __P((const void *, const void *));
140 1.46.2.2 nathanw static void scanvars __P((void));
141 1.46.2.2 nathanw static void usage __P((void));
142 1.46.2.2 nathanw int main __P((int, char *[]));
143 1.46.2.2 nathanw
144 1.46.2.2 nathanw char dfmt[] = "pid tt state time command";
145 1.46.2.2 nathanw char jfmt[] = "user pid ppid pgid sess jobc state tt time command";
146 1.46.2.2 nathanw char lfmt[] = "uid pid ppid cpu pri nice vsz rss wchan state tt time command";
147 1.46.2.2 nathanw char o1[] = "pid";
148 1.46.2.2 nathanw char o2[] = "tt state time command";
149 1.46.2.2 nathanw char sfmt[] = "uid pid ppid cpu lid nlwp pri nice vsz rss wchan state tt time command";
150 1.46.2.2 nathanw char ufmt[] = "user pid %cpu %mem vsz rss tt state start time command";
151 1.46.2.2 nathanw char vfmt[] = "pid state time sl re pagein vsz rss lim tsiz %cpu %mem command";
152 1.46.2.2 nathanw
153 1.46.2.2 nathanw kvm_t *kd;
154 1.46.2.2 nathanw
155 1.46.2.2 nathanw int
156 1.46.2.2 nathanw main(argc, argv)
157 1.46.2.2 nathanw int argc;
158 1.46.2.2 nathanw char *argv[];
159 1.46.2.2 nathanw {
160 1.46.2.2 nathanw struct varent *vent;
161 1.46.2.2 nathanw struct winsize ws;
162 1.46.2.2 nathanw struct kinfo_lwp *kl, *l;
163 1.46.2.2 nathanw int ch, flag, i, j, fmt, lineno, nentries, nlwps;
164 1.46.2.2 nathanw int prtheader, wflag, what, xflg, mode, showlwps;
165 1.46.2.2 nathanw char *nlistf, *memf, *swapf, errbuf[_POSIX2_LINE_MAX];
166 1.46.2.2 nathanw char *ttname;
167 1.46.2.2 nathanw
168 1.46.2.2 nathanw if ((ioctl(STDOUT_FILENO, TIOCGWINSZ, (char *)&ws) == -1 &&
169 1.46.2.2 nathanw ioctl(STDERR_FILENO, TIOCGWINSZ, (char *)&ws) == -1 &&
170 1.46.2.2 nathanw ioctl(STDIN_FILENO, TIOCGWINSZ, (char *)&ws) == -1) ||
171 1.46.2.2 nathanw ws.ws_col == 0)
172 1.46.2.2 nathanw termwidth = 79;
173 1.46.2.2 nathanw else
174 1.46.2.2 nathanw termwidth = ws.ws_col - 1;
175 1.46.2.2 nathanw
176 1.46.2.2 nathanw if (argc > 1)
177 1.46.2.2 nathanw argv[1] = kludge_oldps_options(argv[1]);
178 1.46.2.2 nathanw
179 1.46.2.2 nathanw fmt = prtheader = wflag = xflg = showlwps = 0;
180 1.46.2.2 nathanw what = KERN_PROC_UID;
181 1.46.2.2 nathanw flag = myuid = getuid();
182 1.46.2.2 nathanw memf = nlistf = swapf = NULL;
183 1.46.2.2 nathanw mode = PRINTMODE;
184 1.46.2.2 nathanw while ((ch = getopt(argc, argv, GETOPTSTR)) != -1)
185 1.46.2.2 nathanw switch((char)ch) {
186 1.46.2.2 nathanw case 'a':
187 1.46.2.2 nathanw what = KERN_PROC_ALL;
188 1.46.2.2 nathanw flag = 0;
189 1.46.2.2 nathanw break;
190 1.46.2.2 nathanw case 'c':
191 1.46.2.2 nathanw commandonly = 1;
192 1.46.2.2 nathanw break;
193 1.46.2.2 nathanw case 'e': /* XXX set ufmt */
194 1.46.2.2 nathanw needenv = 1;
195 1.46.2.2 nathanw break;
196 1.46.2.2 nathanw case 'C':
197 1.46.2.2 nathanw rawcpu = 1;
198 1.46.2.2 nathanw break;
199 1.46.2.2 nathanw case 'g':
200 1.46.2.2 nathanw break; /* no-op */
201 1.46.2.2 nathanw case 'h':
202 1.46.2.2 nathanw prtheader = ws.ws_row > 5 ? ws.ws_row : 22;
203 1.46.2.2 nathanw break;
204 1.46.2.2 nathanw case 'j':
205 1.46.2.2 nathanw parsefmt(jfmt);
206 1.46.2.2 nathanw fmt = 1;
207 1.46.2.2 nathanw jfmt[0] = '\0';
208 1.46.2.2 nathanw break;
209 1.46.2.2 nathanw case 'L':
210 1.46.2.2 nathanw showkey();
211 1.46.2.2 nathanw exit(0);
212 1.46.2.2 nathanw /* NOTREACHED */
213 1.46.2.2 nathanw case 'l':
214 1.46.2.2 nathanw parsefmt(lfmt);
215 1.46.2.2 nathanw fmt = 1;
216 1.46.2.2 nathanw lfmt[0] = '\0';
217 1.46.2.2 nathanw break;
218 1.46.2.2 nathanw case 'M':
219 1.46.2.2 nathanw memf = optarg;
220 1.46.2.2 nathanw break;
221 1.46.2.2 nathanw case 'm':
222 1.46.2.2 nathanw sortby = SORTMEM;
223 1.46.2.2 nathanw break;
224 1.46.2.2 nathanw case 'N':
225 1.46.2.2 nathanw nlistf = optarg;
226 1.46.2.2 nathanw break;
227 1.46.2.2 nathanw case 'O':
228 1.46.2.2 nathanw parsefmt(o1);
229 1.46.2.2 nathanw parsefmt(optarg);
230 1.46.2.2 nathanw parsefmt(o2);
231 1.46.2.2 nathanw o1[0] = o2[0] = '\0';
232 1.46.2.2 nathanw fmt = 1;
233 1.46.2.2 nathanw break;
234 1.46.2.2 nathanw case 'o':
235 1.46.2.2 nathanw parsefmt(optarg);
236 1.46.2.2 nathanw fmt = 1;
237 1.46.2.2 nathanw break;
238 1.46.2.2 nathanw case 'p':
239 1.46.2.2 nathanw what = KERN_PROC_PID;
240 1.46.2.2 nathanw flag = atol(optarg);
241 1.46.2.2 nathanw xflg = 1;
242 1.46.2.2 nathanw break;
243 1.46.2.2 nathanw case 'r':
244 1.46.2.2 nathanw sortby = SORTCPU;
245 1.46.2.2 nathanw break;
246 1.46.2.2 nathanw case 'S':
247 1.46.2.2 nathanw sumrusage = 1;
248 1.46.2.2 nathanw break;
249 1.46.2.2 nathanw case 's':
250 1.46.2.2 nathanw /* -L was already taken... */
251 1.46.2.2 nathanw showlwps = 1;
252 1.46.2.2 nathanw parsefmt(sfmt);
253 1.46.2.2 nathanw fmt = 1;
254 1.46.2.2 nathanw sfmt[0] = '\0';
255 1.46.2.2 nathanw break;
256 1.46.2.2 nathanw case 'T':
257 1.46.2.2 nathanw if ((ttname = ttyname(STDIN_FILENO)) == NULL)
258 1.46.2.2 nathanw errx(1, "stdin: not a terminal");
259 1.46.2.2 nathanw goto tty;
260 1.46.2.2 nathanw case 't':
261 1.46.2.2 nathanw ttname = optarg;
262 1.46.2.2 nathanw tty: {
263 1.46.2.2 nathanw struct stat sb;
264 1.46.2.2 nathanw char *ttypath, pathbuf[MAXPATHLEN];
265 1.46.2.2 nathanw
266 1.46.2.2 nathanw flag = 0;
267 1.46.2.2 nathanw if (strcmp(ttname, "?") == 0)
268 1.46.2.2 nathanw flag = KERN_PROC_TTY_NODEV;
269 1.46.2.2 nathanw else if (strcmp(ttname, "-") == 0)
270 1.46.2.2 nathanw flag = KERN_PROC_TTY_REVOKE;
271 1.46.2.2 nathanw else if (strcmp(ttname, "co") == 0)
272 1.46.2.2 nathanw ttypath = _PATH_CONSOLE;
273 1.46.2.2 nathanw else if (*ttname != '/')
274 1.46.2.2 nathanw (void)snprintf(ttypath = pathbuf,
275 1.46.2.2 nathanw sizeof(pathbuf), "%s%s", _PATH_TTY, ttname);
276 1.46.2.2 nathanw else
277 1.46.2.2 nathanw ttypath = ttname;
278 1.46.2.2 nathanw what = KERN_PROC_TTY;
279 1.46.2.2 nathanw if (flag == 0) {
280 1.46.2.2 nathanw if (stat(ttypath, &sb) == -1)
281 1.46.2.2 nathanw err(1, "%s", ttypath);
282 1.46.2.2 nathanw if (!S_ISCHR(sb.st_mode))
283 1.46.2.2 nathanw errx(1, "%s: not a terminal", ttypath);
284 1.46.2.2 nathanw flag = sb.st_rdev;
285 1.46.2.2 nathanw }
286 1.46.2.2 nathanw break;
287 1.46.2.2 nathanw }
288 1.46.2.2 nathanw case 'U':
289 1.46.2.2 nathanw if (*optarg != '\0') {
290 1.46.2.2 nathanw struct passwd *pw;
291 1.46.2.2 nathanw char *ep;
292 1.46.2.2 nathanw
293 1.46.2.2 nathanw what = KERN_PROC_UID;
294 1.46.2.2 nathanw pw = getpwnam(optarg);
295 1.46.2.2 nathanw if (pw == NULL) {
296 1.46.2.2 nathanw errno = 0;
297 1.46.2.2 nathanw flag = strtoul(optarg, &ep, 10);
298 1.46.2.2 nathanw if (errno)
299 1.46.2.2 nathanw err(1, "%s", optarg);
300 1.46.2.2 nathanw if (*ep != '\0')
301 1.46.2.2 nathanw errx(1, "%s: illegal user name",
302 1.46.2.2 nathanw optarg);
303 1.46.2.2 nathanw } else
304 1.46.2.2 nathanw flag = pw->pw_uid;
305 1.46.2.2 nathanw }
306 1.46.2.2 nathanw break;
307 1.46.2.2 nathanw case 'u':
308 1.46.2.2 nathanw parsefmt(ufmt);
309 1.46.2.2 nathanw sortby = SORTCPU;
310 1.46.2.2 nathanw fmt = 1;
311 1.46.2.2 nathanw ufmt[0] = '\0';
312 1.46.2.2 nathanw break;
313 1.46.2.2 nathanw case 'v':
314 1.46.2.2 nathanw parsefmt(vfmt);
315 1.46.2.2 nathanw sortby = SORTMEM;
316 1.46.2.2 nathanw fmt = 1;
317 1.46.2.2 nathanw vfmt[0] = '\0';
318 1.46.2.2 nathanw break;
319 1.46.2.2 nathanw case 'W':
320 1.46.2.2 nathanw swapf = optarg;
321 1.46.2.2 nathanw break;
322 1.46.2.2 nathanw case 'w':
323 1.46.2.2 nathanw if (wflag)
324 1.46.2.2 nathanw termwidth = UNLIMITED;
325 1.46.2.2 nathanw else if (termwidth < 131)
326 1.46.2.2 nathanw termwidth = 131;
327 1.46.2.2 nathanw wflag++;
328 1.46.2.2 nathanw break;
329 1.46.2.2 nathanw case 'x':
330 1.46.2.2 nathanw xflg = 1;
331 1.46.2.2 nathanw break;
332 1.46.2.2 nathanw case '?':
333 1.46.2.2 nathanw default:
334 1.46.2.2 nathanw usage();
335 1.46.2.2 nathanw }
336 1.46.2.2 nathanw argc -= optind;
337 1.46.2.2 nathanw argv += optind;
338 1.46.2.2 nathanw
339 1.46.2.2 nathanw #define BACKWARD_COMPATIBILITY
340 1.46.2.2 nathanw #ifdef BACKWARD_COMPATIBILITY
341 1.46.2.2 nathanw if (*argv) {
342 1.46.2.2 nathanw nlistf = *argv;
343 1.46.2.2 nathanw if (*++argv) {
344 1.46.2.2 nathanw memf = *argv;
345 1.46.2.2 nathanw if (*++argv)
346 1.46.2.2 nathanw swapf = *argv;
347 1.46.2.2 nathanw }
348 1.46.2.2 nathanw }
349 1.46.2.2 nathanw #endif
350 1.46.2.2 nathanw
351 1.46.2.2 nathanw if (memf == NULL && swapf == NULL) {
352 1.46.2.2 nathanw kd = kvm_openfiles(nlistf, memf, swapf, KVM_NO_FILES, errbuf);
353 1.46.2.2 nathanw donlist_sysctl();
354 1.46.2.2 nathanw } else
355 1.46.2.2 nathanw kd = kvm_openfiles(nlistf, memf, swapf, O_RDONLY, errbuf);
356 1.46.2.2 nathanw
357 1.46.2.2 nathanw if (kd == 0)
358 1.46.2.2 nathanw errx(1, "%s", errbuf);
359 1.46.2.2 nathanw
360 1.46.2.2 nathanw if (!fmt)
361 1.46.2.2 nathanw parsefmt(dfmt);
362 1.46.2.2 nathanw
363 1.46.2.2 nathanw /*
364 1.46.2.2 nathanw * scan requested variables, noting what structures are needed.
365 1.46.2.2 nathanw */
366 1.46.2.2 nathanw scanvars();
367 1.46.2.2 nathanw
368 1.46.2.2 nathanw /*
369 1.46.2.2 nathanw * select procs
370 1.46.2.2 nathanw */
371 1.46.2.2 nathanw if (!(kinfo = getkinfo_kvm(kd, what, flag, &nentries)))
372 1.46.2.2 nathanw err(1, "%s.", kvm_geterr(kd));
373 1.46.2.2 nathanw
374 1.46.2.2 nathanw if (nentries == 0) {
375 1.46.2.2 nathanw printheader();
376 1.46.2.2 nathanw exit(1);
377 1.46.2.2 nathanw }
378 1.46.2.2 nathanw /*
379 1.46.2.2 nathanw * sort proc list
380 1.46.2.2 nathanw */
381 1.46.2.2 nathanw qsort(kinfo, nentries, sizeof(struct kinfo_proc2), pscomp);
382 1.46.2.2 nathanw /*
383 1.46.2.2 nathanw * For each proc, call each variable output function in
384 1.46.2.2 nathanw * "setwidth" mode to determine the widest element of
385 1.46.2.2 nathanw * the column.
386 1.46.2.2 nathanw */
387 1.46.2.2 nathanw if (mode == PRINTMODE)
388 1.46.2.2 nathanw for (i = 0; i < nentries; i++) {
389 1.46.2.2 nathanw struct kinfo_proc2 *ki = &kinfo[i];
390 1.46.2.2 nathanw
391 1.46.2.2 nathanw if (xflg == 0 && (ki->p_tdev == NODEV ||
392 1.46.2.2 nathanw (ki->p_flag & P_CONTROLT) == 0))
393 1.46.2.2 nathanw continue;
394 1.46.2.2 nathanw
395 1.46.2.2 nathanw kl = kvm_getlwps(kd, ki->p_pid, ki->p_paddr,
396 1.46.2.2 nathanw sizeof(struct kinfo_lwp), &nlwps);
397 1.46.2.2 nathanw if (showlwps == 0) {
398 1.46.2.2 nathanw l = pick_representative_lwp(ki, kl, nlwps);
399 1.46.2.2 nathanw for (vent = vhead; vent; vent = vent->next)
400 1.46.2.2 nathanw OUTPUT(vent, ki, l, WIDTHMODE);
401 1.46.2.2 nathanw } else {
402 1.46.2.2 nathanw /* The printing is done with the loops
403 1.46.2.2 nathanw * reversed, but here we don't need that,
404 1.46.2.2 nathanw * and this improves the code locality a bit.
405 1.46.2.2 nathanw */
406 1.46.2.2 nathanw for (vent = vhead; vent; vent = vent->next)
407 1.46.2.2 nathanw for (j = 0; j < nlwps; j++)
408 1.46.2.2 nathanw OUTPUT(vent, ki, &kl[j],
409 1.46.2.2 nathanw WIDTHMODE);
410 1.46.2.2 nathanw }
411 1.46.2.2 nathanw free(kl);
412 1.46.2.2 nathanw }
413 1.46.2.2 nathanw /*
414 1.46.2.2 nathanw * Print header - AFTER determining process field widths.
415 1.46.2.2 nathanw * printheader() also adds up the total width of all
416 1.46.2.2 nathanw * fields the first time it's called.
417 1.46.2.2 nathanw */
418 1.46.2.2 nathanw printheader();
419 1.46.2.2 nathanw /*
420 1.46.2.2 nathanw * For each proc, call each variable output function in
421 1.46.2.2 nathanw * print mode.
422 1.46.2.2 nathanw */
423 1.46.2.2 nathanw for (i = lineno = 0; i < nentries; i++) {
424 1.46.2.2 nathanw struct kinfo_proc2 *ki = &kinfo[i];
425 1.46.2.2 nathanw
426 1.46.2.2 nathanw if (xflg == 0 && (ki->p_tdev == NODEV ||
427 1.46.2.2 nathanw (ki->p_flag & P_CONTROLT ) == 0))
428 1.46.2.2 nathanw continue;
429 1.46.2.2 nathanw kl = kvm_getlwps(kd, ki->p_pid, (u_long)ki->p_paddr,
430 1.46.2.2 nathanw sizeof(struct kinfo_lwp), &nlwps);
431 1.46.2.2 nathanw
432 1.46.2.2 nathanw if (showlwps == 0) {
433 1.46.2.2 nathanw l = pick_representative_lwp(ki, kl, nlwps);
434 1.46.2.2 nathanw for (vent = vhead; vent; vent = vent->next) {
435 1.46.2.2 nathanw OUTPUT(vent, ki, l, mode);
436 1.46.2.2 nathanw if (vent->next != NULL)
437 1.46.2.2 nathanw (void)putchar(' ');
438 1.46.2.2 nathanw }
439 1.46.2.2 nathanw (void)putchar('\n');
440 1.46.2.2 nathanw if (prtheader && lineno++ == prtheader - 4) {
441 1.46.2.2 nathanw (void)putchar('\n');
442 1.46.2.2 nathanw printheader();
443 1.46.2.2 nathanw lineno = 0;
444 1.46.2.2 nathanw }
445 1.46.2.2 nathanw } else {
446 1.46.2.2 nathanw for (j = 0; j < nlwps; j++) {
447 1.46.2.2 nathanw for (vent = vhead; vent; vent = vent->next) {
448 1.46.2.2 nathanw OUTPUT(vent, ki, &kl[j], mode);
449 1.46.2.2 nathanw if (vent->next != NULL)
450 1.46.2.2 nathanw (void)putchar(' ');
451 1.46.2.2 nathanw }
452 1.46.2.2 nathanw (void)putchar('\n');
453 1.46.2.2 nathanw if (prtheader && lineno++ == prtheader - 4) {
454 1.46.2.2 nathanw (void)putchar('\n');
455 1.46.2.2 nathanw printheader();
456 1.46.2.2 nathanw lineno = 0;
457 1.46.2.2 nathanw }
458 1.46.2.2 nathanw }
459 1.46.2.2 nathanw }
460 1.46.2.2 nathanw free(kl);
461 1.46.2.2 nathanw }
462 1.46.2.2 nathanw exit(eval);
463 1.46.2.2 nathanw /* NOTREACHED */
464 1.46.2.2 nathanw }
465 1.46.2.2 nathanw
466 1.46.2.2 nathanw static struct kinfo_lwp *
467 1.46.2.2 nathanw pick_representative_lwp(ki, kl, nlwps)
468 1.46.2.2 nathanw struct kinfo_proc2 *ki;
469 1.46.2.2 nathanw struct kinfo_lwp *kl;
470 1.46.2.2 nathanw int nlwps;
471 1.46.2.2 nathanw {
472 1.46.2.2 nathanw int i, onproc, run, sleep;
473 1.46.2.2 nathanw
474 1.46.2.2 nathanw /* Trivial case: only one LWP */
475 1.46.2.2 nathanw if (nlwps == 1)
476 1.46.2.2 nathanw return kl;
477 1.46.2.2 nathanw
478 1.46.2.2 nathanw switch (ki->p_stat) {
479 1.46.2.2 nathanw case SSTOP:
480 1.46.2.2 nathanw /* Pick the first stopped LWP */
481 1.46.2.2 nathanw for (i = 0; i < nlwps; i++) {
482 1.46.2.2 nathanw if (kl[i].l_stat == LSSTOP)
483 1.46.2.2 nathanw return &kl[i];
484 1.46.2.2 nathanw }
485 1.46.2.2 nathanw break;
486 1.46.2.2 nathanw case SACTIVE:
487 1.46.2.2 nathanw /* Pick the most live LWP */
488 1.46.2.2 nathanw onproc = run = sleep = 0;
489 1.46.2.2 nathanw for (i = 0; i < nlwps; i++) {
490 1.46.2.2 nathanw switch (kl[i].l_stat) {
491 1.46.2.2 nathanw case LSONPROC:
492 1.46.2.2 nathanw onproc = i;
493 1.46.2.2 nathanw break;
494 1.46.2.2 nathanw case LSRUN:
495 1.46.2.2 nathanw run = i;
496 1.46.2.2 nathanw break;
497 1.46.2.2 nathanw case LSSLEEP:
498 1.46.2.2 nathanw sleep = i;
499 1.46.2.2 nathanw break;
500 1.46.2.2 nathanw }
501 1.46.2.2 nathanw }
502 1.46.2.2 nathanw if (onproc)
503 1.46.2.2 nathanw return &kl[onproc];
504 1.46.2.2 nathanw if (run)
505 1.46.2.2 nathanw return &kl[run];
506 1.46.2.2 nathanw if (sleep)
507 1.46.2.2 nathanw return &kl[sleep];
508 1.46.2.2 nathanw break;
509 1.46.2.2 nathanw case SDEAD:
510 1.46.2.2 nathanw case SZOMB:
511 1.46.2.2 nathanw /* First will do */
512 1.46.2.2 nathanw return kl;
513 1.46.2.2 nathanw break;
514 1.46.2.2 nathanw }
515 1.46.2.2 nathanw /* Error condition! */
516 1.46.2.2 nathanw warnx("Inconsistent LWP state for process %d\n", ki->p_pid);
517 1.46.2.2 nathanw return kl;
518 1.46.2.2 nathanw }
519 1.46.2.2 nathanw
520 1.46.2.2 nathanw
521 1.46.2.2 nathanw static struct kinfo_proc2 *
522 1.46.2.2 nathanw getkinfo_kvm(kdp, what, flag, nentriesp)
523 1.46.2.2 nathanw kvm_t *kdp;
524 1.46.2.2 nathanw int what, flag, *nentriesp;
525 1.46.2.2 nathanw {
526 1.46.2.2 nathanw return (kvm_getproc2(kdp, what, flag, sizeof(struct kinfo_proc2),
527 1.46.2.2 nathanw nentriesp));
528 1.46.2.2 nathanw }
529 1.46.2.2 nathanw
530 1.46.2.2 nathanw static void
531 1.46.2.2 nathanw scanvars()
532 1.46.2.2 nathanw {
533 1.46.2.2 nathanw struct varent *vent;
534 1.46.2.2 nathanw VAR *v;
535 1.46.2.2 nathanw
536 1.46.2.2 nathanw for (vent = vhead; vent; vent = vent->next) {
537 1.46.2.2 nathanw v = vent->var;
538 1.46.2.2 nathanw if (v->flag & COMM) {
539 1.46.2.2 nathanw needcomm = 1;
540 1.46.2.2 nathanw break;
541 1.46.2.2 nathanw }
542 1.46.2.2 nathanw }
543 1.46.2.2 nathanw }
544 1.46.2.2 nathanw
545 1.46.2.2 nathanw static int
546 1.46.2.2 nathanw pscomp(a, b)
547 1.46.2.2 nathanw const void *a, *b;
548 1.46.2.2 nathanw {
549 1.46.2.2 nathanw struct kinfo_proc2 *ka = (struct kinfo_proc2 *)a;
550 1.46.2.2 nathanw struct kinfo_proc2 *kb = (struct kinfo_proc2 *)b;
551 1.46.2.2 nathanw
552 1.46.2.2 nathanw int i;
553 1.46.2.2 nathanw #define VSIZE(k) (k->p_vm_dsize + k->p_vm_ssize + k->p_vm_tsize)
554 1.46.2.2 nathanw
555 1.46.2.2 nathanw if (sortby == SORTCPU)
556 1.46.2.2 nathanw return (getpcpu(kb) - getpcpu(ka));
557 1.46.2.2 nathanw if (sortby == SORTMEM)
558 1.46.2.2 nathanw return (VSIZE(kb) - VSIZE(ka));
559 1.46.2.2 nathanw i = ka->p_tdev - kb->p_tdev;
560 1.46.2.2 nathanw
561 1.46.2.2 nathanw if (i == 0)
562 1.46.2.2 nathanw i = ka->p_pid - kb->p_pid;
563 1.46.2.2 nathanw return (i);
564 1.46.2.2 nathanw }
565 1.46.2.2 nathanw
566 1.46.2.2 nathanw /*
567 1.46.2.2 nathanw * ICK (all for getopt), would rather hide the ugliness
568 1.46.2.2 nathanw * here than taint the main code.
569 1.46.2.2 nathanw *
570 1.46.2.2 nathanw * ps foo -> ps -foo
571 1.46.2.2 nathanw * ps 34 -> ps -p34
572 1.46.2.2 nathanw *
573 1.46.2.2 nathanw * The old convention that 't' with no trailing tty arg means the user's
574 1.46.2.2 nathanw * tty, is only supported if argv[1] doesn't begin with a '-'. This same
575 1.46.2.2 nathanw * feature is available with the option 'T', which takes no argument.
576 1.46.2.2 nathanw */
577 1.46.2.2 nathanw static char *
578 1.46.2.2 nathanw kludge_oldps_options(s)
579 1.46.2.2 nathanw char *s;
580 1.46.2.2 nathanw {
581 1.46.2.2 nathanw size_t len;
582 1.46.2.2 nathanw char *newopts, *ns, *cp;
583 1.46.2.2 nathanw
584 1.46.2.2 nathanw len = strlen(s);
585 1.46.2.2 nathanw if ((newopts = ns = malloc(len + 3)) == NULL)
586 1.46.2.2 nathanw err(1, NULL);
587 1.46.2.2 nathanw /*
588 1.46.2.2 nathanw * options begin with '-'
589 1.46.2.2 nathanw */
590 1.46.2.2 nathanw if (*s != '-')
591 1.46.2.2 nathanw *ns++ = '-'; /* add option flag */
592 1.46.2.2 nathanw /*
593 1.46.2.2 nathanw * gaze to end of argv[1]
594 1.46.2.2 nathanw */
595 1.46.2.2 nathanw cp = s + len - 1;
596 1.46.2.2 nathanw /*
597 1.46.2.2 nathanw * if the last letter is a 't' flag and there are no other option
598 1.46.2.2 nathanw * characters that take arguments (eg U, p, o) in the option
599 1.46.2.2 nathanw * string and the option string doesn't start with a '-' then
600 1.46.2.2 nathanw * convert to 'T' (meaning *this* terminal, i.e. ttyname(0)).
601 1.46.2.2 nathanw */
602 1.46.2.2 nathanw if (*cp == 't' && *s != '-' && strpbrk(s, ARGOPTS) == NULL)
603 1.46.2.2 nathanw *cp = 'T';
604 1.46.2.2 nathanw else {
605 1.46.2.2 nathanw /*
606 1.46.2.2 nathanw * otherwise check for trailing number, which *may* be a
607 1.46.2.2 nathanw * pid.
608 1.46.2.2 nathanw */
609 1.46.2.2 nathanw while (cp >= s && isdigit(*cp))
610 1.46.2.2 nathanw --cp;
611 1.46.2.2 nathanw }
612 1.46.2.2 nathanw cp++;
613 1.46.2.2 nathanw memmove(ns, s, (size_t)(cp - s)); /* copy up to trailing number */
614 1.46.2.2 nathanw ns += cp - s;
615 1.46.2.2 nathanw /*
616 1.46.2.2 nathanw * if there's a trailing number, and not a preceding 'p' (pid) or
617 1.46.2.2 nathanw * 't' (tty) flag, then assume it's a pid and insert a 'p' flag.
618 1.46.2.2 nathanw */
619 1.46.2.2 nathanw if (isdigit(*cp) &&
620 1.46.2.2 nathanw (cp == s || (cp[-1] != 'U' && cp[-1] != 't' && cp[-1] != 'p' &&
621 1.46.2.2 nathanw (cp - 1 == s || cp[-2] != 't'))))
622 1.46.2.2 nathanw *ns++ = 'p';
623 1.46.2.2 nathanw /* and append the number */
624 1.46.2.2 nathanw (void)strcpy(ns, cp); /* XXX strcpy is safe here */
625 1.46.2.2 nathanw
626 1.46.2.2 nathanw return (newopts);
627 1.46.2.2 nathanw }
628 1.46.2.2 nathanw
629 1.46.2.2 nathanw static void
630 1.46.2.2 nathanw usage()
631 1.46.2.2 nathanw {
632 1.46.2.2 nathanw
633 1.46.2.2 nathanw (void)fprintf(stderr,
634 1.46.2.2 nathanw "usage:\t%s\n\t %s\n\t%s\n",
635 1.46.2.2 nathanw "ps [-acCehjKlmrSTuvwx] [-O|o fmt] [-p pid] [-t tty]",
636 1.46.2.2 nathanw "[-M core] [-N system] [-W swap] [-U username]",
637 1.46.2.2 nathanw "ps [-L]");
638 1.46.2.2 nathanw exit(1);
639 1.46.2.2 nathanw /* NOTREACHED */
640 1.46.2.2 nathanw }
641