Print this page
OS-4408 /native/usr/bin/ps should work in a lx branded zone
Reviewed by: Jerry Jelinek <jerry.jelinek@joyent.com>
Reviewed by: Robert Mustacchi <rm@joyent.com>
| Split |
Close |
| Expand all |
| Collapse all |
--- old/usr/src/cmd/ps/ps.c
+++ new/usr/src/cmd/ps/ps.c
1 1 /*
2 2 * CDDL HEADER START
3 3 *
4 4 * The contents of this file are subject to the terms of the
5 5 * Common Development and Distribution License (the "License").
6 6 * You may not use this file except in compliance with the License.
7 7 *
8 8 * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
9 9 * or http://www.opensolaris.org/os/licensing.
10 10 * See the License for the specific language governing permissions
11 11 * and limitations under the License.
12 12 *
13 13 * When distributing Covered Code, include this CDDL HEADER in each
14 14 * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
15 15 * If applicable, add the following below this CDDL HEADER, with the
16 16 * fields enclosed by brackets "[]" replaced with your own identifying
17 17 * information: Portions Copyright [yyyy] [name of copyright owner]
18 18 *
19 19 * CDDL HEADER END
|
↓ open down ↓ |
19 lines elided |
↑ open up ↑ |
20 20 */
21 21
22 22 /*
23 23 * Copyright (c) 2013 Gary Mills
24 24 *
25 25 * Copyright 2009 Sun Microsystems, Inc. All rights reserved.
26 26 * Use is subject to license terms.
27 27 */
28 28
29 29 /*
30 - * Copyright (c) 2012, Joyent, Inc. All rights reserved.
30 + * Copyright 2015 Joyent, Inc.
31 31 */
32 32
33 33 /* Copyright (c) 1984, 1986, 1987, 1988, 1989 AT&T */
34 34 /* All Rights Reserved */
35 35
36 36 /*
37 37 * ps -- print things about processes.
38 38 */
39 39 #include <stdio.h>
40 40 #include <ctype.h>
41 41 #include <string.h>
42 42 #include <errno.h>
43 43 #include <fcntl.h>
44 44 #include <pwd.h>
45 45 #include <grp.h>
46 46 #include <sys/types.h>
47 47 #include <sys/stat.h>
48 48 #include <sys/mkdev.h>
49 49 #include <unistd.h>
50 50 #include <stdlib.h>
51 51 #include <limits.h>
52 52 #include <dirent.h>
53 53 #include <sys/signal.h>
54 54 #include <sys/fault.h>
55 55 #include <sys/syscall.h>
56 56 #include <sys/time.h>
57 57 #include <procfs.h>
58 58 #include <locale.h>
59 59 #include <wctype.h>
60 60 #include <wchar.h>
61 61 #include <libw.h>
62 62 #include <stdarg.h>
63 63 #include <sys/proc.h>
64 64 #include <sys/pset.h>
65 65 #include <project.h>
66 66 #include <zone.h>
67 67
68 68 #define min(a, b) ((a) > (b) ? (b) : (a))
69 69 #define max(a, b) ((a) < (b) ? (b) : (a))
70 70
71 71 #define NTTYS 20 /* initial size of table for -t option */
72 72 #define SIZ 30 /* initial size of tables for -p, -s, -g, -h and -z */
73 73
74 74 /*
75 75 * Size of buffer holding args for t, p, s, g, u, U, G, z options.
76 76 * Set to ZONENAME_MAX, the minimum value needed to allow any
77 77 * zone to be specified.
78 78 */
79 79 #define ARGSIZ ZONENAME_MAX
80 80
81 81 /* Max chars in a user/group name or printed u/g id */
82 82 #define MAXUGNAME (LOGNAME_MAX+2)
83 83
84 84 /* Structure for storing user or group info */
85 85 struct ugdata {
86 86 id_t id; /* numeric user-id or group-id */
87 87 char name[MAXUGNAME+1]; /* user/group name, null terminated */
88 88 };
89 89
90 90 struct ughead {
91 91 size_t size; /* number of ugdata structs allocated */
92 92 size_t nent; /* number of active entries */
93 93 struct ugdata *ent; /* pointer to array of actual entries */
94 94 };
95 95
96 96 enum fname { /* enumeration of field names */
97 97 F_USER, /* effective user of the process */
98 98 F_RUSER, /* real user of the process */
99 99 F_GROUP, /* effective group of the process */
100 100 F_RGROUP, /* real group of the process */
101 101 F_UID, /* numeric effective uid of the process */
102 102 F_RUID, /* numeric real uid of the process */
103 103 F_GID, /* numeric effective gid of the process */
104 104 F_RGID, /* numeric real gid of the process */
105 105 F_PID, /* process id */
106 106 F_PPID, /* parent process id */
107 107 F_PGID, /* process group id */
108 108 F_SID, /* session id */
109 109 F_PSR, /* bound processor */
110 110 F_LWP, /* lwp-id */
111 111 F_NLWP, /* number of lwps */
112 112 F_OPRI, /* old priority (obsolete) */
113 113 F_PRI, /* new priority */
114 114 F_F, /* process flags */
115 115 F_S, /* letter indicating the state */
116 116 F_C, /* processor utilization (obsolete) */
117 117 F_PCPU, /* percent of recently used cpu time */
118 118 F_PMEM, /* percent of physical memory used (rss) */
119 119 F_OSZ, /* virtual size of the process in pages */
120 120 F_VSZ, /* virtual size of the process in kilobytes */
121 121 F_RSS, /* resident set size of the process in kilobytes */
122 122 F_NICE, /* "nice" value of the process */
123 123 F_CLASS, /* scheduler class */
124 124 F_STIME, /* start time of the process, hh:mm:ss or Month Day */
125 125 F_ETIME, /* elapsed time of the process, [[dd-]hh:]mm:ss */
126 126 F_TIME, /* cpu time of the process, [[dd-]hh:]mm:ss */
127 127 F_TTY, /* name of the controlling terminal */
128 128 F_ADDR, /* address of the process (obsolete) */
129 129 F_WCHAN, /* wait channel (sleep condition variable) */
130 130 F_FNAME, /* file name of command */
131 131 F_COMM, /* name of command (argv[0] value) */
132 132 F_ARGS, /* name of command plus all its arguments */
133 133 F_TASKID, /* task id */
134 134 F_PROJID, /* project id */
135 135 F_PROJECT, /* project name of the process */
136 136 F_PSET, /* bound processor set */
137 137 F_ZONE, /* zone name */
138 138 F_ZONEID, /* zone id */
139 139 F_CTID, /* process contract id */
140 140 F_LGRP, /* process home lgroup */
141 141 F_DMODEL /* process data model */
142 142 };
143 143
144 144 struct field {
145 145 struct field *next; /* linked list */
146 146 int fname; /* field index */
147 147 const char *header; /* header to use */
148 148 int width; /* width of field */
149 149 };
150 150
151 151 static struct field *fields = NULL; /* fields selected via -o */
152 152 static struct field *last_field = NULL;
153 153 static int do_header = 0;
154 154 static struct timeval now;
155 155
156 156 /* array of defined fields, in fname order */
157 157 struct def_field {
158 158 const char *fname;
159 159 const char *header;
160 160 int width;
161 161 int minwidth;
162 162 };
163 163
164 164 static struct def_field fname[] = {
165 165 /* fname header width minwidth */
166 166 { "user", "USER", 8, 8 },
167 167 { "ruser", "RUSER", 8, 8 },
168 168 { "group", "GROUP", 8, 8 },
169 169 { "rgroup", "RGROUP", 8, 8 },
170 170 { "uid", "UID", 5, 5 },
171 171 { "ruid", "RUID", 5, 5 },
172 172 { "gid", "GID", 5, 5 },
173 173 { "rgid", "RGID", 5, 5 },
174 174 { "pid", "PID", 5, 5 },
175 175 { "ppid", "PPID", 5, 5 },
176 176 { "pgid", "PGID", 5, 5 },
177 177 { "sid", "SID", 5, 5 },
178 178 { "psr", "PSR", 3, 2 },
179 179 { "lwp", "LWP", 6, 2 },
180 180 { "nlwp", "NLWP", 4, 2 },
181 181 { "opri", "PRI", 3, 2 },
182 182 { "pri", "PRI", 3, 2 },
183 183 { "f", "F", 2, 2 },
184 184 { "s", "S", 1, 1 },
185 185 { "c", "C", 2, 2 },
186 186 { "pcpu", "%CPU", 4, 4 },
187 187 { "pmem", "%MEM", 4, 4 },
188 188 { "osz", "SZ", 4, 4 },
189 189 { "vsz", "VSZ", 4, 4 },
190 190 { "rss", "RSS", 4, 4 },
191 191 { "nice", "NI", 2, 2 },
192 192 { "class", "CLS", 4, 2 },
193 193 { "stime", "STIME", 8, 8 },
194 194 { "etime", "ELAPSED", 11, 7 },
195 195 { "time", "TIME", 11, 5 },
196 196 { "tty", "TT", 7, 7 },
197 197 #ifdef _LP64
198 198 { "addr", "ADDR", 16, 8 },
199 199 { "wchan", "WCHAN", 16, 8 },
200 200 #else
201 201 { "addr", "ADDR", 8, 8 },
202 202 { "wchan", "WCHAN", 8, 8 },
203 203 #endif
204 204 { "fname", "COMMAND", 8, 8 },
205 205 { "comm", "COMMAND", 80, 8 },
206 206 { "args", "COMMAND", 80, 80 },
207 207 { "taskid", "TASKID", 5, 5 },
208 208 { "projid", "PROJID", 5, 5 },
209 209 { "project", "PROJECT", 8, 8 },
210 210 { "pset", "PSET", 3, 3 },
211 211 { "zone", "ZONE", 8, 8 },
212 212 { "zoneid", "ZONEID", 5, 5 },
213 213 { "ctid", "CTID", 5, 5 },
214 214 { "lgrp", "LGRP", 4, 2 },
215 215 { "dmodel", "DMODEL", 6, 6 },
216 216 };
217 217
218 218 #define NFIELDS (sizeof (fname) / sizeof (fname[0]))
219 219
220 220 static int retcode = 1;
221 221 static int lflg;
222 222 static int Aflg;
223 223 static int uflg;
224 224 static int Uflg;
225 225 static int Gflg;
226 226 static int aflg;
227 227 static int dflg;
228 228 static int Lflg;
229 229 static int Pflg;
230 230 static int Wflg;
231 231 static int yflg;
232 232 static int pflg;
233 233 static int fflg;
234 234 static int cflg;
235 235 static int jflg;
236 236 static int gflg;
237 237 static int sflg;
238 238 static int tflg;
239 239 static int zflg;
240 240 static int Zflg;
241 241 static int hflg;
242 242 static int Hflg;
243 243 static uid_t tuid = (uid_t)-1;
244 244 static int errflg;
245 245
246 246 static int ndev; /* number of devices */
247 247 static int maxdev; /* number of devl structures allocated */
248 248
249 249 #define DNINCR 100
250 250 #define DNSIZE 14
251 251 static struct devl { /* device list */
252 252 char dname[DNSIZE]; /* device name */
253 253 dev_t ddev; /* device number */
254 254 } *devl;
255 255
256 256 static struct tty {
257 257 char *tname;
258 258 dev_t tdev;
259 259 } *tty = NULL; /* for t option */
260 260 static size_t ttysz = 0;
261 261 static int ntty = 0;
262 262
263 263 static pid_t *pid = NULL; /* for p option */
264 264 static size_t pidsz = 0;
265 265 static size_t npid = 0;
266 266
267 267 static int *lgrps = NULL; /* list of lgroup IDs for for h option */
268 268 static size_t lgrps_size = 0; /* size of the lgrps list */
269 269 static size_t nlgrps = 0; /* number elements in the list */
270 270
271 271 /* Maximum possible lgroup ID value */
272 272 #define MAX_LGRP_ID 256
273 273
274 274 static pid_t *grpid = NULL; /* for g option */
275 275 static size_t grpidsz = 0;
276 276 static int ngrpid = 0;
277 277
278 278 static pid_t *sessid = NULL; /* for s option */
|
↓ open down ↓ |
238 lines elided |
↑ open up ↑ |
279 279 static size_t sessidsz = 0;
280 280 static int nsessid = 0;
281 281
282 282 static zoneid_t *zoneid = NULL; /* for z option */
283 283 static size_t zoneidsz = 0;
284 284 static int nzoneid = 0;
285 285
286 286 static int kbytes_per_page;
287 287 static int pidwidth;
288 288
289 -static char *procdir = "/proc"; /* standard /proc directory */
289 +static char procdir[MAXPATHLEN]; /* standard /proc directory */
290 290
291 291 static struct ughead euid_tbl; /* table to store selected euid's */
292 292 static struct ughead ruid_tbl; /* table to store selected real uid's */
293 293 static struct ughead egid_tbl; /* table to store selected egid's */
294 294 static struct ughead rgid_tbl; /* table to store selected real gid's */
295 295 static prheader_t *lpsinfobuf; /* buffer to contain lpsinfo */
296 296 static size_t lpbufsize;
297 297
298 298 /*
299 299 * This constant defines the sentinal number of process IDs below which we
300 300 * only examine individual entries in /proc rather than scanning through
301 301 * /proc. This optimization is a huge win in the common case.
302 302 */
303 303 #define PTHRESHOLD 40
304 304
305 305 #define UCB_OPTS "-aceglnrtuvwxSU"
306 306
307 307 static void usage(void);
308 308 static char *getarg(char **);
309 309 static char *parse_format(char *);
310 310 static char *gettty(psinfo_t *);
311 311 static int prfind(int, psinfo_t *, char **);
312 312 static void prcom(psinfo_t *, char *);
313 313 static void prtpct(ushort_t, int);
314 314 static void print_time(time_t, int);
315 315 static void print_field(psinfo_t *, struct field *, const char *);
316 316 static void print_zombie_field(psinfo_t *, struct field *, const char *);
317 317 static void pr_fields(psinfo_t *, const char *,
318 318 void (*print_fld)(psinfo_t *, struct field *, const char *));
319 319 static int search(pid_t *, int, pid_t);
320 320 static void add_ugentry(struct ughead *, char *);
321 321 static int uconv(struct ughead *);
322 322 static int gconv(struct ughead *);
323 323 static int ugfind(id_t, struct ughead *);
324 324 static void prtime(timestruc_t, int, int);
325 325 static void przom(psinfo_t *);
326 326 static int namencnt(char *, int, int);
327 327 static char *err_string(int);
328 328 static int print_proc(char *pname);
329 329 static time_t delta_secs(const timestruc_t *);
330 330 static int str2id(const char *, pid_t *, long, long);
331 331 static int str2uid(const char *, uid_t *, unsigned long, unsigned long);
|
↓ open down ↓ |
32 lines elided |
↑ open up ↑ |
332 332 static void *Realloc(void *, size_t);
333 333 static int pidcmp(const void *p1, const void *p2);
334 334
335 335 extern int ucbmain(int, char **);
336 336 static int stdmain(int, char **);
337 337
338 338 int
339 339 main(int argc, char **argv)
340 340 {
341 341 const char *me;
342 + const char *zroot = zone_get_nroot();
342 343
343 344 /*
345 + * If this is a branded zone, the native procfs may mounted in a
346 + * non-standard location. Apply such a path prefix if it exists.
347 + */
348 + (void) snprintf(procdir, sizeof (procdir), "%s/proc", zroot != NULL ?
349 + zroot : "");
350 +
351 + /*
344 352 * The original two ps'es are linked in a single binary;
345 353 * their main()s are renamed to stdmain for /usr/bin/ps and
346 354 * ucbmain for /usr/ucb/ps.
347 355 * We try to figure out which instance of ps the user wants to run.
348 356 * Traditionally, the UCB variant doesn't require the flag argument
349 357 * start with a "-". If the first argument doesn't start with a
350 358 * "-", we call "ucbmain".
351 359 * If there's a first argument and it starts with a "-", we check
352 360 * whether any of the options isn't acceptable to "ucbmain"; in that
353 361 * case we run "stdmain".
354 362 * If we can't tell from the options which main to call, we check
355 363 * the binary we are running. We default to "stdmain" but
356 364 * any mention in the executable name of "ucb" causes us to call
357 365 * ucbmain.
358 366 */
359 367 if (argv[1] != NULL) {
360 368 if (argv[1][0] != '-')
361 369 return (ucbmain(argc, argv));
362 370 else if (argv[1][strspn(argv[1], UCB_OPTS)] != '\0')
363 371 return (stdmain(argc, argv));
364 372 }
365 373
366 374 me = getexecname();
367 375
368 376 if (me != NULL && strstr(me, "ucb") != NULL)
369 377 return (ucbmain(argc, argv));
370 378 else
371 379 return (stdmain(argc, argv));
372 380 }
373 381
374 382 static int
375 383 stdmain(int argc, char **argv)
376 384 {
377 385 char *p;
378 386 char *p1;
379 387 char *parg;
380 388 int c;
381 389 int i;
382 390 int pgerrflg = 0; /* err flg: non-numeric arg w/p & g options */
383 391 size_t size, len;
384 392 DIR *dirp;
385 393 struct dirent *dentp;
386 394 pid_t maxpid;
387 395 pid_t id;
388 396 int ret;
389 397 char loc_stime_str[32];
390 398
391 399 (void) setlocale(LC_ALL, "");
392 400 #if !defined(TEXT_DOMAIN) /* Should be defined by cc -D */
393 401 #define TEXT_DOMAIN "SYS_TEST" /* Use this only if it weren't */
394 402 #endif
395 403 (void) textdomain(TEXT_DOMAIN);
396 404
397 405 (void) memset(&euid_tbl, 0, sizeof (euid_tbl));
398 406 (void) memset(&ruid_tbl, 0, sizeof (ruid_tbl));
399 407 (void) memset(&egid_tbl, 0, sizeof (egid_tbl));
400 408 (void) memset(&rgid_tbl, 0, sizeof (rgid_tbl));
401 409
402 410 kbytes_per_page = sysconf(_SC_PAGESIZE) / 1024;
403 411
404 412 (void) gettimeofday(&now, NULL);
405 413
406 414 /*
407 415 * calculate width of pid fields based on configured MAXPID
408 416 * (must be at least 5 to retain output format compatibility)
409 417 */
410 418 id = maxpid = (pid_t)sysconf(_SC_MAXPID);
411 419 pidwidth = 1;
412 420 while ((id /= 10) > 0)
413 421 ++pidwidth;
414 422 pidwidth = pidwidth < 5 ? 5 : pidwidth;
415 423
416 424 fname[F_PID].width = fname[F_PPID].width = pidwidth;
417 425 fname[F_PGID].width = fname[F_SID].width = pidwidth;
418 426
419 427 /*
420 428 * TRANSLATION_NOTE
421 429 * Specify the printf format with width and precision for
422 430 * the STIME field.
423 431 */
424 432 len = snprintf(loc_stime_str, sizeof (loc_stime_str),
425 433 dcgettext(NULL, "%8.8s", LC_TIME), "STIME");
426 434 if (len >= sizeof (loc_stime_str))
427 435 len = sizeof (loc_stime_str) - 1;
428 436
429 437 fname[F_STIME].width = fname[F_STIME].minwidth = len;
430 438
431 439 while ((c = getopt(argc, argv, "jlfceAadLPWyZHh:t:p:g:u:U:G:n:s:o:z:"))
432 440 != EOF)
433 441 switch (c) {
434 442 case 'H': /* Show home lgroups */
435 443 Hflg++;
436 444 break;
437 445 case 'h':
438 446 /*
439 447 * Show processes/threads with given home lgroups
440 448 */
441 449 hflg++;
442 450 p1 = optarg;
443 451 do {
444 452 int id;
445 453
446 454 /*
447 455 * Get all IDs in the list, verify for
448 456 * correctness and place in lgrps array.
449 457 */
450 458 parg = getarg(&p1);
451 459 /* Convert string to integer */
452 460 ret = str2id(parg, (pid_t *)&id, 0,
453 461 MAX_LGRP_ID);
454 462 /* Complain if ID didn't parse correctly */
455 463 if (ret != 0) {
456 464 pgerrflg++;
457 465 (void) fprintf(stderr,
458 466 gettext("ps: %s "), parg);
459 467 if (ret == EINVAL)
460 468 (void) fprintf(stderr,
461 469 gettext("is an invalid "
462 470 "non-numeric argument"));
463 471 else
464 472 (void) fprintf(stderr,
465 473 gettext("exceeds valid "
466 474 "range"));
467 475 (void) fprintf(stderr,
468 476 gettext(" for -h option\n"));
469 477 continue;
470 478 }
471 479
472 480 /* Extend lgrps array if needed */
473 481 if (nlgrps == lgrps_size) {
474 482 /* Double the size of the lgrps array */
475 483 if (lgrps_size == 0)
476 484 lgrps_size = SIZ;
477 485 lgrps_size *= 2;
478 486 lgrps = Realloc(lgrps,
479 487 lgrps_size * sizeof (int));
480 488 }
481 489 /* place the id in the lgrps table */
482 490 lgrps[nlgrps++] = id;
483 491 } while (*p1);
484 492 break;
485 493 case 'l': /* long listing */
486 494 lflg++;
487 495 break;
488 496 case 'f': /* full listing */
489 497 fflg++;
490 498 break;
491 499 case 'j':
492 500 jflg++;
493 501 break;
494 502 case 'c':
495 503 /*
496 504 * Format output to reflect scheduler changes:
497 505 * high numbers for high priorities and don't
498 506 * print nice or p_cpu values. 'c' option only
499 507 * effective when used with 'l' or 'f' options.
500 508 */
501 509 cflg++;
502 510 break;
503 511 case 'A': /* list every process */
504 512 case 'e': /* (obsolete) list every process */
505 513 Aflg++;
506 514 tflg = Gflg = Uflg = uflg = pflg = gflg = sflg = 0;
507 515 zflg = hflg = 0;
508 516 break;
509 517 case 'a':
510 518 /*
511 519 * Same as 'e' except no session group leaders
512 520 * and no non-terminal processes.
513 521 */
514 522 aflg++;
515 523 break;
516 524 case 'd': /* same as e except no session leaders */
517 525 dflg++;
518 526 break;
519 527 case 'L': /* show lwps */
520 528 Lflg++;
521 529 break;
522 530 case 'P': /* show bound processor */
523 531 Pflg++;
524 532 break;
525 533 case 'W': /* truncate long names */
526 534 Wflg++;
527 535 break;
528 536 case 'y': /* omit F & ADDR, report RSS & SZ in Kby */
529 537 yflg++;
530 538 break;
531 539 case 'n': /* no longer needed; retain as no-op */
532 540 (void) fprintf(stderr,
533 541 gettext("ps: warning: -n option ignored\n"));
534 542 break;
535 543 case 't': /* terminals */
536 544 #define TSZ 30
537 545 tflg++;
538 546 p1 = optarg;
539 547 do {
540 548 char nambuf[TSZ+6]; /* for "/dev/" + '\0' */
541 549 struct stat64 s;
542 550 parg = getarg(&p1);
543 551 p = Realloc(NULL, TSZ+1); /* for '\0' */
544 552 /* zero the buffer before using it */
545 553 p[0] = '\0';
546 554 size = TSZ;
547 555 if (isdigit(*parg)) {
548 556 (void) strcpy(p, "tty");
549 557 size -= 3;
550 558 }
551 559 (void) strncat(p, parg, size);
552 560 if (ntty == ttysz) {
553 561 if ((ttysz *= 2) == 0)
554 562 ttysz = NTTYS;
555 563 tty = Realloc(tty,
556 564 (ttysz + 1) * sizeof (struct tty));
557 565 }
558 566 tty[ntty].tdev = PRNODEV;
559 567 (void) strcpy(nambuf, "/dev/");
560 568 (void) strcat(nambuf, p);
561 569 if (stat64(nambuf, &s) == 0)
562 570 tty[ntty].tdev = s.st_rdev;
563 571 tty[ntty++].tname = p;
564 572 } while (*p1);
565 573 break;
566 574 case 'p': /* proc ids */
567 575 pflg++;
568 576 p1 = optarg;
569 577 do {
570 578 pid_t id;
571 579
572 580 parg = getarg(&p1);
573 581 if ((ret = str2id(parg, &id, 0, maxpid)) != 0) {
574 582 pgerrflg++;
575 583 (void) fprintf(stderr,
576 584 gettext("ps: %s "), parg);
577 585 if (ret == EINVAL)
578 586 (void) fprintf(stderr,
579 587 gettext("is an invalid "
580 588 "non-numeric argument"));
581 589 else
582 590 (void) fprintf(stderr,
583 591 gettext("exceeds valid "
584 592 "range"));
585 593 (void) fprintf(stderr,
586 594 gettext(" for -p option\n"));
587 595 continue;
588 596 }
589 597
590 598 if (npid == pidsz) {
591 599 if ((pidsz *= 2) == 0)
592 600 pidsz = SIZ;
593 601 pid = Realloc(pid,
594 602 pidsz * sizeof (pid_t));
595 603 }
596 604 pid[npid++] = id;
597 605 } while (*p1);
598 606 break;
599 607 case 's': /* session */
600 608 sflg++;
601 609 p1 = optarg;
602 610 do {
603 611 pid_t id;
604 612
605 613 parg = getarg(&p1);
606 614 if ((ret = str2id(parg, &id, 0, maxpid)) != 0) {
607 615 pgerrflg++;
608 616 (void) fprintf(stderr,
609 617 gettext("ps: %s "), parg);
610 618 if (ret == EINVAL)
611 619 (void) fprintf(stderr,
612 620 gettext("is an invalid "
613 621 "non-numeric argument"));
614 622 else
615 623 (void) fprintf(stderr,
616 624 gettext("exceeds valid "
617 625 "range"));
618 626 (void) fprintf(stderr,
619 627 gettext(" for -s option\n"));
620 628 continue;
621 629 }
622 630
623 631 if (nsessid == sessidsz) {
624 632 if ((sessidsz *= 2) == 0)
625 633 sessidsz = SIZ;
626 634 sessid = Realloc(sessid,
627 635 sessidsz * sizeof (pid_t));
628 636 }
629 637 sessid[nsessid++] = id;
630 638 } while (*p1);
631 639 break;
632 640 case 'g': /* proc group */
633 641 gflg++;
634 642 p1 = optarg;
635 643 do {
636 644 pid_t id;
637 645
638 646 parg = getarg(&p1);
639 647 if ((ret = str2id(parg, &id, 0, maxpid)) != 0) {
640 648 pgerrflg++;
641 649 (void) fprintf(stderr,
642 650 gettext("ps: %s "), parg);
643 651 if (ret == EINVAL)
644 652 (void) fprintf(stderr,
645 653 gettext("is an invalid "
646 654 "non-numeric argument"));
647 655 else
648 656 (void) fprintf(stderr,
649 657 gettext("exceeds valid "
650 658 "range"));
651 659 (void) fprintf(stderr,
652 660 gettext(" for -g option\n"));
653 661 continue;
654 662 }
655 663
656 664 if (ngrpid == grpidsz) {
657 665 if ((grpidsz *= 2) == 0)
658 666 grpidsz = SIZ;
659 667 grpid = Realloc(grpid,
660 668 grpidsz * sizeof (pid_t));
661 669 }
662 670 grpid[ngrpid++] = id;
663 671 } while (*p1);
664 672 break;
665 673 case 'u': /* effective user name or number */
666 674 uflg++;
667 675 p1 = optarg;
668 676 do {
669 677 parg = getarg(&p1);
670 678 add_ugentry(&euid_tbl, parg);
671 679 } while (*p1);
672 680 break;
673 681 case 'U': /* real user name or number */
674 682 Uflg++;
675 683 p1 = optarg;
676 684 do {
677 685 parg = getarg(&p1);
678 686 add_ugentry(&ruid_tbl, parg);
679 687 } while (*p1);
680 688 break;
681 689 case 'G': /* real group name or number */
682 690 Gflg++;
683 691 p1 = optarg;
684 692 do {
685 693 parg = getarg(&p1);
686 694 add_ugentry(&rgid_tbl, parg);
687 695 } while (*p1);
688 696 break;
689 697 case 'o': /* output format */
690 698 p = optarg;
691 699 while ((p = parse_format(p)) != NULL)
692 700 ;
693 701 break;
694 702 case 'z': /* zone name or number */
695 703 zflg++;
696 704 p1 = optarg;
697 705 do {
698 706 zoneid_t id;
699 707
700 708 parg = getarg(&p1);
701 709 if (zone_get_id(parg, &id) != 0) {
702 710 pgerrflg++;
703 711 (void) fprintf(stderr,
704 712 gettext("ps: unknown zone %s\n"),
705 713 parg);
706 714 continue;
707 715 }
708 716
709 717 if (nzoneid == zoneidsz) {
710 718 if ((zoneidsz *= 2) == 0)
711 719 zoneidsz = SIZ;
712 720 zoneid = Realloc(zoneid,
713 721 zoneidsz * sizeof (zoneid_t));
714 722 }
715 723 zoneid[nzoneid++] = id;
716 724 } while (*p1);
717 725 break;
718 726 case 'Z': /* show zone name */
719 727 Zflg++;
720 728 break;
721 729 default: /* error on ? */
722 730 errflg++;
723 731 break;
724 732 }
725 733
726 734 if (errflg || optind < argc || pgerrflg)
727 735 usage();
728 736
729 737 if (tflg)
730 738 tty[ntty].tname = NULL;
731 739 /*
732 740 * If an appropriate option has not been specified, use the
733 741 * current terminal and effective uid as the default.
734 742 */
735 743 if (!(aflg|Aflg|dflg|Gflg|hflg|Uflg|uflg|tflg|pflg|gflg|sflg|zflg)) {
736 744 psinfo_t info;
737 745 int procfd;
738 746 char *name;
739 747 char pname[100];
740 748
741 749 /* get our own controlling tty name using /proc */
742 750 (void) snprintf(pname, sizeof (pname),
743 751 "%s/self/psinfo", procdir);
744 752 if ((procfd = open(pname, O_RDONLY)) < 0 ||
745 753 read(procfd, (char *)&info, sizeof (info)) < 0 ||
746 754 info.pr_ttydev == PRNODEV) {
747 755 (void) fprintf(stderr,
748 756 gettext("ps: no controlling terminal\n"));
749 757 exit(1);
750 758 }
751 759 (void) close(procfd);
752 760
753 761 i = 0;
754 762 name = gettty(&info);
755 763 if (*name == '?') {
756 764 (void) fprintf(stderr,
757 765 gettext("ps: can't find controlling terminal\n"));
758 766 exit(1);
759 767 }
760 768 if (ntty == ttysz) {
761 769 if ((ttysz *= 2) == 0)
762 770 ttysz = NTTYS;
763 771 tty = Realloc(tty, (ttysz + 1) * sizeof (struct tty));
764 772 }
765 773 tty[ntty].tdev = info.pr_ttydev;
766 774 tty[ntty++].tname = name;
767 775 tty[ntty].tname = NULL;
768 776 tflg++;
769 777 tuid = getuid();
770 778 }
771 779 if (Aflg) {
772 780 Gflg = Uflg = uflg = pflg = sflg = gflg = aflg = dflg = 0;
773 781 zflg = hflg = 0;
774 782 }
775 783 if (Aflg | aflg | dflg)
776 784 tflg = 0;
777 785
778 786 i = 0; /* prepare to exit on name lookup errors */
779 787 i += uconv(&euid_tbl);
780 788 i += uconv(&ruid_tbl);
781 789 i += gconv(&egid_tbl);
782 790 i += gconv(&rgid_tbl);
783 791 if (i)
784 792 exit(1);
785 793
786 794 /* allocate a buffer for lwpsinfo structures */
787 795 lpbufsize = 4096;
788 796 if (Lflg && (lpsinfobuf = malloc(lpbufsize)) == NULL) {
789 797 (void) fprintf(stderr,
790 798 gettext("ps: no memory\n"));
791 799 exit(1);
792 800 }
793 801
794 802 if (fields) { /* print user-specified header */
795 803 if (do_header) {
796 804 struct field *f;
797 805
798 806 for (f = fields; f != NULL; f = f->next) {
799 807 if (f != fields)
800 808 (void) printf(" ");
801 809 switch (f->fname) {
802 810 case F_TTY:
803 811 (void) printf("%-*s",
804 812 f->width, f->header);
805 813 break;
806 814 case F_FNAME:
807 815 case F_COMM:
808 816 case F_ARGS:
809 817 /*
810 818 * Print these headers full width
811 819 * unless they appear at the end.
812 820 */
813 821 if (f->next != NULL) {
814 822 (void) printf("%-*s",
815 823 f->width, f->header);
816 824 } else {
817 825 (void) printf("%s",
818 826 f->header);
819 827 }
820 828 break;
821 829 default:
822 830 (void) printf("%*s",
823 831 f->width, f->header);
824 832 break;
825 833 }
826 834 }
827 835 (void) printf("\n");
828 836 }
829 837 } else { /* print standard header */
830 838 /*
831 839 * All fields before 'PID' are printed with a trailing space
832 840 * as a separator and that is how we print the headers too.
833 841 */
834 842 if (lflg) {
835 843 if (yflg)
836 844 (void) printf("S ");
837 845 else
838 846 (void) printf(" F S ");
839 847 }
840 848 if (Zflg)
841 849 (void) printf(" ZONE ");
842 850 if (fflg) {
843 851 (void) printf(" UID ");
844 852 } else if (lflg)
845 853 (void) printf(" UID ");
846 854
847 855 (void) printf("%*s", pidwidth, "PID");
848 856 if (lflg || fflg)
849 857 (void) printf(" %*s", pidwidth, "PPID");
850 858 if (jflg)
851 859 (void) printf(" %*s %*s", pidwidth, "PGID",
852 860 pidwidth, "SID");
853 861 if (Lflg)
854 862 (void) printf(" LWP");
855 863 if (Pflg)
856 864 (void) printf(" PSR");
857 865 if (Lflg && fflg)
858 866 (void) printf(" NLWP");
859 867 if (cflg)
860 868 (void) printf(" CLS PRI");
861 869 else if (lflg || fflg) {
862 870 (void) printf(" C");
863 871 if (lflg)
864 872 (void) printf(" PRI NI");
865 873 }
866 874 if (lflg) {
867 875 if (yflg)
868 876 (void) printf(" RSS SZ WCHAN");
869 877 else
870 878 (void) printf(" ADDR SZ WCHAN");
871 879 }
872 880 if (fflg)
873 881 (void) printf(" %s", loc_stime_str);
874 882 if (Hflg)
875 883 (void) printf(" LGRP");
876 884 if (Lflg)
877 885 (void) printf(" TTY LTIME CMD\n");
878 886 else
879 887 (void) printf(" TTY TIME CMD\n");
880 888 }
881 889
882 890
883 891 if (pflg && !(aflg|Aflg|dflg|Gflg|Uflg|uflg|hflg|tflg|gflg|sflg|zflg) &&
884 892 npid <= PTHRESHOLD) {
885 893 /*
886 894 * If we are looking at specific processes go straight
887 895 * to their /proc entries and don't scan /proc.
888 896 */
889 897 int i;
890 898
891 899 (void) qsort(pid, npid, sizeof (pid_t), pidcmp);
892 900 for (i = 0; i < npid; i++) {
893 901 char pname[12];
894 902
895 903 if (i >= 1 && pid[i] == pid[i - 1])
896 904 continue;
897 905 (void) sprintf(pname, "%d", (int)pid[i]);
898 906 if (print_proc(pname) == 0)
899 907 retcode = 0;
900 908 }
901 909 } else {
902 910 /*
903 911 * Determine which processes to print info about by searching
904 912 * the /proc directory and looking at each process.
905 913 */
906 914 if ((dirp = opendir(procdir)) == NULL) {
907 915 (void) fprintf(stderr,
908 916 gettext("ps: cannot open PROC directory %s\n"),
909 917 procdir);
910 918 exit(1);
911 919 }
912 920
913 921 /* for each active process --- */
914 922 while ((dentp = readdir(dirp)) != NULL) {
915 923 if (dentp->d_name[0] == '.') /* skip . and .. */
916 924 continue;
917 925 if (print_proc(dentp->d_name) == 0)
918 926 retcode = 0;
919 927 }
920 928
921 929 (void) closedir(dirp);
922 930 }
923 931 return (retcode);
924 932 }
925 933
926 934
927 935 int
928 936 print_proc(char *pid_name)
929 937 {
930 938 char pname[PATH_MAX];
931 939 int pdlen;
932 940 int found;
933 941 int procfd; /* filedescriptor for /proc/nnnnn/psinfo */
934 942 char *tp; /* ptr to ttyname, if any */
935 943 psinfo_t info; /* process information from /proc */
936 944 lwpsinfo_t *lwpsinfo; /* array of lwpsinfo structs */
937 945
938 946 pdlen = snprintf(pname, sizeof (pname), "%s/%s/", procdir, pid_name);
939 947 if (pdlen >= sizeof (pname) - 10)
940 948 return (1);
941 949 retry:
942 950 (void) strcpy(&pname[pdlen], "psinfo");
943 951 if ((procfd = open(pname, O_RDONLY)) == -1) {
944 952 /* Process may have exited meanwhile. */
945 953 return (1);
946 954 }
947 955 /*
948 956 * Get the info structure for the process and close quickly.
949 957 */
950 958 if (read(procfd, (char *)&info, sizeof (info)) < 0) {
951 959 int saverr = errno;
952 960
953 961 (void) close(procfd);
954 962 if (saverr == EAGAIN)
955 963 goto retry;
956 964 if (saverr != ENOENT)
957 965 (void) fprintf(stderr,
958 966 gettext("ps: read() on %s: %s\n"),
959 967 pname, err_string(saverr));
960 968 return (1);
961 969 }
962 970 (void) close(procfd);
963 971
964 972 found = 0;
965 973 if (info.pr_lwp.pr_state == 0) /* can't happen? */
966 974 return (1);
967 975
968 976 /*
969 977 * Omit session group leaders for 'a' and 'd' options.
970 978 */
971 979 if ((info.pr_pid == info.pr_sid) && (dflg || aflg))
972 980 return (1);
973 981 if (Aflg || dflg)
974 982 found++;
975 983 else if (pflg && search(pid, npid, info.pr_pid))
976 984 found++; /* ppid in p option arg list */
977 985 else if (uflg && ugfind((id_t)info.pr_euid, &euid_tbl))
978 986 found++; /* puid in u option arg list */
979 987 else if (Uflg && ugfind((id_t)info.pr_uid, &ruid_tbl))
980 988 found++; /* puid in U option arg list */
981 989 #ifdef NOT_YET
982 990 else if (gflg && ugfind((id_t)info.pr_egid, &egid_tbl))
983 991 found++; /* pgid in g option arg list */
984 992 #endif /* NOT_YET */
985 993 else if (Gflg && ugfind((id_t)info.pr_gid, &rgid_tbl))
986 994 found++; /* pgid in G option arg list */
987 995 else if (gflg && search(grpid, ngrpid, info.pr_pgid))
988 996 found++; /* grpid in g option arg list */
989 997 else if (sflg && search(sessid, nsessid, info.pr_sid))
990 998 found++; /* sessid in s option arg list */
991 999 else if (zflg && search(zoneid, nzoneid, info.pr_zoneid))
992 1000 found++; /* zoneid in z option arg list */
993 1001 else if (hflg && search((pid_t *)lgrps, nlgrps, info.pr_lwp.pr_lgrp))
994 1002 found++; /* home lgroup in h option arg list */
995 1003 if (!found && !tflg && !aflg)
996 1004 return (1);
997 1005 if (!prfind(found, &info, &tp))
998 1006 return (1);
999 1007 if (Lflg && (info.pr_nlwp + info.pr_nzomb) > 1) {
1000 1008 ssize_t prsz;
1001 1009
1002 1010 (void) strcpy(&pname[pdlen], "lpsinfo");
1003 1011 if ((procfd = open(pname, O_RDONLY)) == -1)
1004 1012 return (1);
1005 1013 /*
1006 1014 * Get the info structures for the lwps.
1007 1015 */
1008 1016 prsz = read(procfd, lpsinfobuf, lpbufsize);
1009 1017 if (prsz == -1) {
1010 1018 int saverr = errno;
1011 1019
1012 1020 (void) close(procfd);
1013 1021 if (saverr == EAGAIN)
1014 1022 goto retry;
1015 1023 if (saverr != ENOENT)
1016 1024 (void) fprintf(stderr,
1017 1025 gettext("ps: read() on %s: %s\n"),
1018 1026 pname, err_string(saverr));
1019 1027 return (1);
1020 1028 }
1021 1029 (void) close(procfd);
1022 1030 if (prsz == lpbufsize) {
1023 1031 /*
1024 1032 * buffer overflow. Realloc new buffer.
1025 1033 * Error handling is done in Realloc().
1026 1034 */
1027 1035 lpbufsize *= 2;
1028 1036 lpsinfobuf = Realloc(lpsinfobuf, lpbufsize);
1029 1037 goto retry;
1030 1038 }
1031 1039 if (lpsinfobuf->pr_nent != (info.pr_nlwp + info.pr_nzomb))
1032 1040 goto retry;
1033 1041 lwpsinfo = (lwpsinfo_t *)(lpsinfobuf + 1);
1034 1042 }
1035 1043 if (!Lflg || (info.pr_nlwp + info.pr_nzomb) <= 1) {
1036 1044 prcom(&info, tp);
1037 1045 } else {
1038 1046 int nlwp = 0;
1039 1047
1040 1048 do {
1041 1049 info.pr_lwp = *lwpsinfo;
1042 1050 prcom(&info, tp);
1043 1051 /* LINTED improper alignment */
1044 1052 lwpsinfo = (lwpsinfo_t *)((char *)lwpsinfo +
1045 1053 lpsinfobuf->pr_entsize);
1046 1054 } while (++nlwp < lpsinfobuf->pr_nent);
1047 1055 }
1048 1056 return (0);
1049 1057 }
1050 1058
1051 1059 static int
1052 1060 field_cmp(const void *l, const void *r)
1053 1061 {
1054 1062 struct def_field *lhs = *((struct def_field **)l);
1055 1063 struct def_field *rhs = *((struct def_field **)r);
1056 1064
1057 1065 return (strcmp(lhs->fname, rhs->fname));
1058 1066 }
1059 1067
1060 1068 static void
1061 1069 usage(void) /* print usage message and quit */
1062 1070 {
1063 1071 struct def_field *df, *sorted[NFIELDS];
1064 1072 int pos = 80, i = 0;
1065 1073
1066 1074 static char usage1[] =
1067 1075 "ps [ -aAdefHlcjLPWyZ ] [ -o format ] [ -t termlist ]";
1068 1076 static char usage2[] =
1069 1077 "\t[ -u userlist ] [ -U userlist ] [ -G grouplist ]";
1070 1078 static char usage3[] =
1071 1079 "\t[ -p proclist ] [ -g pgrplist ] [ -s sidlist ]";
1072 1080 static char usage4[] =
1073 1081 "\t[ -z zonelist ] [-h lgrplist]";
1074 1082 static char usage5[] =
1075 1083 " 'format' is one or more of:";
1076 1084
1077 1085 (void) fprintf(stderr,
1078 1086 gettext("usage: %s\n%s\n%s\n%s\n%s"),
1079 1087 gettext(usage1), gettext(usage2), gettext(usage3),
1080 1088 gettext(usage4), gettext(usage5));
1081 1089
1082 1090 /*
1083 1091 * Now print out the possible output formats such that they neatly fit
1084 1092 * into eighty columns. Note that the fact that we are determining
1085 1093 * this output programmatically means that a gettext() is impossible --
1086 1094 * but it would be a mistake to localize the output formats anyway as
1087 1095 * they are tokens for input, not output themselves.
1088 1096 */
1089 1097 for (df = &fname[0]; df < &fname[NFIELDS]; df++)
1090 1098 sorted[i++] = df;
1091 1099
1092 1100 (void) qsort(sorted, NFIELDS, sizeof (void *), field_cmp);
1093 1101
1094 1102 for (i = 0; i < NFIELDS; i++) {
1095 1103 if (pos + strlen((df = sorted[i])->fname) + 1 >= 80) {
1096 1104 (void) fprintf(stderr, "\n\t");
1097 1105 pos = 8;
1098 1106 }
1099 1107
1100 1108 (void) fprintf(stderr, "%s%s", pos > 8 ? " " : "", df->fname);
1101 1109 pos += strlen(df->fname) + 1;
1102 1110 }
1103 1111
1104 1112 (void) fprintf(stderr, "\n");
1105 1113
1106 1114 exit(1);
1107 1115 }
1108 1116
1109 1117 /*
1110 1118 * getarg() finds the next argument in list and copies arg into argbuf.
1111 1119 * p1 first pts to arg passed back from getopt routine. p1 is then
1112 1120 * bumped to next character that is not a comma or blank -- p1 NULL
1113 1121 * indicates end of list.
1114 1122 */
1115 1123 static char *
1116 1124 getarg(char **pp1)
1117 1125 {
1118 1126 static char argbuf[ARGSIZ];
1119 1127 char *p1 = *pp1;
1120 1128 char *parga = argbuf;
1121 1129 int c;
1122 1130
1123 1131 while ((c = *p1) != '\0' && (c == ',' || isspace(c)))
1124 1132 p1++;
1125 1133
1126 1134 while ((c = *p1) != '\0' && c != ',' && !isspace(c)) {
1127 1135 if (parga < argbuf + ARGSIZ - 1)
1128 1136 *parga++ = c;
1129 1137 p1++;
1130 1138 }
1131 1139 *parga = '\0';
1132 1140
1133 1141 while ((c = *p1) != '\0' && (c == ',' || isspace(c)))
1134 1142 p1++;
1135 1143
1136 1144 *pp1 = p1;
1137 1145
1138 1146 return (argbuf);
1139 1147 }
1140 1148
1141 1149 /*
1142 1150 * parse_format() takes the argument to the -o option,
1143 1151 * sets up the next output field structure, and returns
1144 1152 * a pointer to any further output field specifier(s).
1145 1153 * As a side-effect, it increments errflg if encounters a format error.
1146 1154 */
1147 1155 static char *
1148 1156 parse_format(char *arg)
1149 1157 {
1150 1158 int c;
1151 1159 char *name;
1152 1160 char *header = NULL;
1153 1161 int width = 0;
1154 1162 struct def_field *df;
1155 1163 struct field *f;
1156 1164
1157 1165 while ((c = *arg) != '\0' && (c == ',' || isspace(c)))
1158 1166 arg++;
1159 1167 if (c == '\0')
1160 1168 return (NULL);
1161 1169 name = arg;
1162 1170 arg = strpbrk(arg, " \t\r\v\f\n,=");
1163 1171 if (arg != NULL) {
1164 1172 c = *arg;
1165 1173 *arg++ = '\0';
1166 1174 if (c == '=') {
1167 1175 char *s;
1168 1176
1169 1177 header = arg;
1170 1178 arg = NULL;
1171 1179 width = strlen(header);
1172 1180 s = header + width;
1173 1181 while (s > header && isspace(*--s))
1174 1182 *s = '\0';
1175 1183 while (isspace(*header))
1176 1184 header++;
1177 1185 }
1178 1186 }
1179 1187 for (df = &fname[0]; df < &fname[NFIELDS]; df++)
1180 1188 if (strcmp(name, df->fname) == 0) {
1181 1189 if (strcmp(name, "lwp") == 0)
1182 1190 Lflg++;
1183 1191 break;
1184 1192 }
1185 1193 if (df >= &fname[NFIELDS]) {
1186 1194 (void) fprintf(stderr,
1187 1195 gettext("ps: unknown output format: -o %s\n"),
1188 1196 name);
1189 1197 errflg++;
1190 1198 return (arg);
1191 1199 }
1192 1200 if ((f = malloc(sizeof (*f))) == NULL) {
1193 1201 (void) fprintf(stderr,
1194 1202 gettext("ps: malloc() for output format failed, %s\n"),
1195 1203 err_string(errno));
1196 1204 exit(1);
1197 1205 }
1198 1206 f->next = NULL;
1199 1207 f->fname = df - &fname[0];
1200 1208 f->header = header? header : df->header;
1201 1209 if (width == 0)
1202 1210 width = df->width;
1203 1211 if (*f->header != '\0')
1204 1212 do_header = 1;
1205 1213 f->width = max(width, df->minwidth);
1206 1214
1207 1215 if (fields == NULL)
1208 1216 fields = last_field = f;
1209 1217 else {
1210 1218 last_field->next = f;
1211 1219 last_field = f;
1212 1220 }
1213 1221
1214 1222 return (arg);
1215 1223 }
1216 1224
1217 1225 static char *
1218 1226 devlookup(dev_t ddev)
1219 1227 {
1220 1228 struct devl *dp;
1221 1229 int i;
1222 1230
1223 1231 for (dp = devl, i = 0; i < ndev; dp++, i++) {
1224 1232 if (dp->ddev == ddev)
1225 1233 return (dp->dname);
1226 1234 }
1227 1235 return (NULL);
1228 1236 }
1229 1237
1230 1238 static char *
1231 1239 devadd(char *name, dev_t ddev)
1232 1240 {
1233 1241 struct devl *dp;
1234 1242 int leng, start, i;
1235 1243
1236 1244 if (ndev == maxdev) {
1237 1245 maxdev += DNINCR;
1238 1246 devl = Realloc(devl, maxdev * sizeof (struct devl));
1239 1247 }
1240 1248 dp = &devl[ndev++];
1241 1249
1242 1250 dp->ddev = ddev;
1243 1251 if (name == NULL) {
1244 1252 (void) strcpy(dp->dname, "??");
1245 1253 return (dp->dname);
1246 1254 }
1247 1255
1248 1256 leng = strlen(name);
1249 1257 /* Strip off /dev/ */
1250 1258 if (leng < DNSIZE + 4)
1251 1259 (void) strcpy(dp->dname, &name[5]);
1252 1260 else {
1253 1261 start = leng - DNSIZE - 1;
1254 1262
1255 1263 for (i = start; i < leng && name[i] != '/'; i++)
1256 1264 ;
1257 1265 if (i == leng)
1258 1266 (void) strncpy(dp->dname, &name[start], DNSIZE);
1259 1267 else
1260 1268 (void) strncpy(dp->dname, &name[i+1], DNSIZE);
1261 1269 }
1262 1270 return (dp->dname);
1263 1271 }
1264 1272
1265 1273 /*
1266 1274 * gettty returns the user's tty number or ? if none.
1267 1275 */
1268 1276 static char *
1269 1277 gettty(psinfo_t *psinfo)
1270 1278 {
1271 1279 extern char *_ttyname_dev(dev_t, char *, size_t);
1272 1280 static zoneid_t zid = -1;
1273 1281 char devname[TTYNAME_MAX];
1274 1282 char *retval;
1275 1283
1276 1284 if (zid == -1)
1277 1285 zid = getzoneid();
1278 1286
1279 1287 if (psinfo->pr_ttydev == PRNODEV || psinfo->pr_zoneid != zid)
1280 1288 return ("?");
1281 1289
1282 1290 if ((retval = devlookup(psinfo->pr_ttydev)) != NULL)
1283 1291 return (retval);
1284 1292
1285 1293 retval = _ttyname_dev(psinfo->pr_ttydev, devname, sizeof (devname));
1286 1294
1287 1295 return (devadd(retval, psinfo->pr_ttydev));
1288 1296 }
1289 1297
1290 1298 /*
1291 1299 * Find the process's tty and return 1 if process is to be printed.
1292 1300 */
1293 1301 static int
1294 1302 prfind(int found, psinfo_t *psinfo, char **tpp)
1295 1303 {
1296 1304 char *tp;
1297 1305 struct tty *ttyp;
1298 1306
1299 1307 if (psinfo->pr_nlwp == 0) {
1300 1308 /* process is a zombie */
1301 1309 *tpp = "?";
1302 1310 if (tflg && !found)
1303 1311 return (0);
1304 1312 return (1);
1305 1313 }
1306 1314
1307 1315 /*
1308 1316 * Get current terminal. If none ("?") and 'a' is set, don't print
1309 1317 * info. If 't' is set, check if term is in list of desired terminals
1310 1318 * and print it if it is.
1311 1319 */
1312 1320 tp = gettty(psinfo);
1313 1321 if (aflg && *tp == '?') {
1314 1322 *tpp = tp;
1315 1323 return (0);
1316 1324 }
1317 1325 if (tflg && !found) {
1318 1326 int match = 0;
1319 1327 char *other = NULL;
1320 1328 for (ttyp = tty; ttyp->tname != NULL; ttyp++) {
1321 1329 /*
1322 1330 * Look for a name match
1323 1331 */
1324 1332 if (strcmp(tp, ttyp->tname) == 0) {
1325 1333 match = 1;
1326 1334 break;
1327 1335 }
1328 1336 /*
1329 1337 * Look for same device under different names.
1330 1338 */
1331 1339 if ((other == NULL) &&
1332 1340 (ttyp->tdev != PRNODEV) &&
1333 1341 (psinfo->pr_ttydev == ttyp->tdev))
1334 1342 other = ttyp->tname;
1335 1343 }
1336 1344 if (!match && (other != NULL)) {
1337 1345 /*
1338 1346 * found under a different name
1339 1347 */
1340 1348 match = 1;
1341 1349 tp = other;
1342 1350 }
1343 1351 if (!match || (tuid != (uid_t)-1 && tuid != psinfo->pr_euid)) {
1344 1352 /*
1345 1353 * not found OR not matching euid
1346 1354 */
1347 1355 *tpp = tp;
1348 1356 return (0);
1349 1357 }
1350 1358 }
1351 1359 *tpp = tp;
1352 1360 return (1);
1353 1361 }
1354 1362
1355 1363 /*
1356 1364 * Print info about the process.
1357 1365 */
1358 1366 static void
1359 1367 prcom(psinfo_t *psinfo, char *ttyp)
1360 1368 {
1361 1369 char *cp;
1362 1370 long tm;
1363 1371 int bytesleft;
1364 1372 int wcnt, length;
1365 1373 wchar_t wchar;
1366 1374 struct passwd *pwd;
1367 1375 int zombie_lwp;
1368 1376 char zonename[ZONENAME_MAX];
1369 1377
1370 1378 /*
1371 1379 * If process is zombie, call zombie print routine and return.
1372 1380 */
1373 1381 if (psinfo->pr_nlwp == 0) {
1374 1382 if (fields != NULL)
1375 1383 pr_fields(psinfo, ttyp, print_zombie_field);
1376 1384 else
1377 1385 przom(psinfo);
1378 1386 return;
1379 1387 }
1380 1388
1381 1389 zombie_lwp = (Lflg && psinfo->pr_lwp.pr_sname == 'Z');
1382 1390
1383 1391 /*
1384 1392 * If user specified '-o format', print requested fields and return.
1385 1393 */
1386 1394 if (fields != NULL) {
1387 1395 pr_fields(psinfo, ttyp, print_field);
1388 1396 return;
1389 1397 }
1390 1398
1391 1399 /*
1392 1400 * All fields before 'PID' are printed with a trailing space as a
1393 1401 * separator, rather than keeping track of which column is first. All
1394 1402 * other fields are printed with a leading space.
1395 1403 */
1396 1404 if (lflg) {
1397 1405 if (!yflg)
1398 1406 (void) printf("%2x ", psinfo->pr_flag & 0377); /* F */
1399 1407 (void) printf("%c ", psinfo->pr_lwp.pr_sname); /* S */
1400 1408 }
1401 1409
1402 1410 if (Zflg) { /* ZONE */
1403 1411 if (getzonenamebyid(psinfo->pr_zoneid, zonename,
1404 1412 sizeof (zonename)) < 0) {
1405 1413 if (snprintf(NULL, 0, "%d",
1406 1414 ((int)psinfo->pr_zoneid)) > 7)
1407 1415 (void) printf(" %6.6d%c ",
1408 1416 ((int)psinfo->pr_zoneid), '*');
1409 1417 else
1410 1418 (void) printf(" %7.7d ",
1411 1419 ((int)psinfo->pr_zoneid));
1412 1420 } else {
1413 1421 size_t nw;
1414 1422
1415 1423 nw = mbstowcs(NULL, zonename, 0);
1416 1424 if (nw == (size_t)-1)
1417 1425 (void) printf("%8.8s ", "ERROR");
1418 1426 else if (nw > 8)
1419 1427 (void) wprintf(L"%7.7s%c ", zonename, '*');
1420 1428 else
1421 1429 (void) wprintf(L"%8.8s ", zonename);
1422 1430 }
1423 1431 }
1424 1432
1425 1433 if (fflg) { /* UID */
1426 1434 if ((pwd = getpwuid(psinfo->pr_euid)) != NULL) {
1427 1435 size_t nw;
1428 1436
1429 1437 nw = mbstowcs(NULL, pwd->pw_name, 0);
1430 1438 if (nw == (size_t)-1)
1431 1439 (void) printf("%8.8s ", "ERROR");
1432 1440 else if (nw > 8)
1433 1441 (void) wprintf(L"%7.7s%c ", pwd->pw_name, '*');
1434 1442 else
1435 1443 (void) wprintf(L"%8.8s ", pwd->pw_name);
1436 1444 } else {
1437 1445 if (snprintf(NULL, 0, "%u",
1438 1446 (psinfo->pr_euid)) > 7)
1439 1447 (void) printf(" %6.6u%c ", psinfo->pr_euid,
1440 1448 '*');
1441 1449 else
1442 1450 (void) printf(" %7.7u ", psinfo->pr_euid);
1443 1451 }
1444 1452 } else if (lflg) {
1445 1453 if (snprintf(NULL, 0, "%u", (psinfo->pr_euid)) > 6)
1446 1454 (void) printf("%5.5u%c ", psinfo->pr_euid, '*');
1447 1455 else
1448 1456 (void) printf("%6u ", psinfo->pr_euid);
1449 1457 }
1450 1458 (void) printf("%*d", pidwidth, (int)psinfo->pr_pid); /* PID */
1451 1459 if (lflg || fflg)
1452 1460 (void) printf(" %*d", pidwidth,
1453 1461 (int)psinfo->pr_ppid); /* PPID */
1454 1462 if (jflg) {
1455 1463 (void) printf(" %*d", pidwidth,
1456 1464 (int)psinfo->pr_pgid); /* PGID */
1457 1465 (void) printf(" %*d", pidwidth,
1458 1466 (int)psinfo->pr_sid); /* SID */
1459 1467 }
1460 1468 if (Lflg)
1461 1469 (void) printf(" %5d", (int)psinfo->pr_lwp.pr_lwpid); /* LWP */
1462 1470 if (Pflg) {
1463 1471 if (psinfo->pr_lwp.pr_bindpro == PBIND_NONE) /* PSR */
1464 1472 (void) printf(" -");
1465 1473 else
1466 1474 (void) printf(" %3d", psinfo->pr_lwp.pr_bindpro);
1467 1475 }
1468 1476 if (Lflg && fflg) /* NLWP */
1469 1477 (void) printf(" %5d", psinfo->pr_nlwp + psinfo->pr_nzomb);
1470 1478 if (cflg) {
1471 1479 if (zombie_lwp) /* CLS */
1472 1480 (void) printf(" ");
1473 1481 else
1474 1482 (void) printf(" %4s", psinfo->pr_lwp.pr_clname);
1475 1483 (void) printf(" %3d", psinfo->pr_lwp.pr_pri); /* PRI */
1476 1484 } else if (lflg || fflg) {
1477 1485 (void) printf(" %3d", psinfo->pr_lwp.pr_cpu & 0377); /* C */
1478 1486 if (lflg) { /* PRI NI */
1479 1487 /*
1480 1488 * Print priorities the old way (lower numbers
1481 1489 * mean higher priority) and print nice value
1482 1490 * for time sharing procs.
1483 1491 */
1484 1492 (void) printf(" %3d", psinfo->pr_lwp.pr_oldpri);
1485 1493 if (psinfo->pr_lwp.pr_oldpri != 0)
1486 1494 (void) printf(" %2d", psinfo->pr_lwp.pr_nice);
1487 1495 else
1488 1496 (void) printf(" %2.2s",
1489 1497 psinfo->pr_lwp.pr_clname);
1490 1498 }
1491 1499 }
1492 1500 if (lflg) {
1493 1501 if (yflg) {
1494 1502 if (psinfo->pr_flag & SSYS) /* RSS */
1495 1503 (void) printf(" 0");
1496 1504 else if (psinfo->pr_rssize)
1497 1505 (void) printf(" %5lu",
1498 1506 (ulong_t)psinfo->pr_rssize);
1499 1507 else
1500 1508 (void) printf(" ?");
1501 1509 if (psinfo->pr_flag & SSYS) /* SZ */
1502 1510 (void) printf(" 0");
1503 1511 else if (psinfo->pr_size)
1504 1512 (void) printf(" %6lu",
1505 1513 (ulong_t)psinfo->pr_size);
1506 1514 else
1507 1515 (void) printf(" ?");
1508 1516 } else {
1509 1517 #ifndef _LP64
1510 1518 if (psinfo->pr_addr) /* ADDR */
1511 1519 (void) printf(" %8lx",
1512 1520 (ulong_t)psinfo->pr_addr);
1513 1521 else
1514 1522 #endif
1515 1523 (void) printf(" ?");
1516 1524 if (psinfo->pr_flag & SSYS) /* SZ */
1517 1525 (void) printf(" 0");
1518 1526 else if (psinfo->pr_size)
1519 1527 (void) printf(" %6lu",
1520 1528 (ulong_t)psinfo->pr_size / kbytes_per_page);
1521 1529 else
1522 1530 (void) printf(" ?");
1523 1531 }
1524 1532 if (psinfo->pr_lwp.pr_sname != 'S') /* WCHAN */
1525 1533 (void) printf(" ");
1526 1534 #ifndef _LP64
1527 1535 else if (psinfo->pr_lwp.pr_wchan)
1528 1536 (void) printf(" %8lx",
1529 1537 (ulong_t)psinfo->pr_lwp.pr_wchan);
1530 1538 #endif
1531 1539 else
1532 1540 (void) printf(" ?");
1533 1541 }
1534 1542 if (fflg) { /* STIME */
1535 1543 int width = fname[F_STIME].width;
1536 1544 if (Lflg)
1537 1545 prtime(psinfo->pr_lwp.pr_start, width + 1, 1);
1538 1546 else
1539 1547 prtime(psinfo->pr_start, width + 1, 1);
1540 1548 }
1541 1549
1542 1550 if (Hflg) {
1543 1551 /* Display home lgroup */
1544 1552 (void) printf(" %4d", (int)psinfo->pr_lwp.pr_lgrp);
1545 1553 }
1546 1554
1547 1555 (void) printf(" %-8.14s", ttyp); /* TTY */
1548 1556 if (Lflg) {
1549 1557 tm = psinfo->pr_lwp.pr_time.tv_sec;
1550 1558 if (psinfo->pr_lwp.pr_time.tv_nsec > 500000000)
1551 1559 tm++;
1552 1560 } else {
1553 1561 tm = psinfo->pr_time.tv_sec;
1554 1562 if (psinfo->pr_time.tv_nsec > 500000000)
1555 1563 tm++;
1556 1564 }
1557 1565 (void) printf(" %4ld:%.2ld", tm / 60, tm % 60); /* [L]TIME */
1558 1566
1559 1567 if (zombie_lwp) {
1560 1568 (void) printf(" <defunct>\n");
1561 1569 return;
1562 1570 }
1563 1571
1564 1572 if (!fflg) { /* CMD */
1565 1573 wcnt = namencnt(psinfo->pr_fname, 16, 8);
1566 1574 (void) printf(" %.*s\n", wcnt, psinfo->pr_fname);
1567 1575 return;
1568 1576 }
1569 1577
1570 1578
1571 1579 /*
1572 1580 * PRARGSZ == length of cmd arg string.
1573 1581 */
1574 1582 psinfo->pr_psargs[PRARGSZ-1] = '\0';
1575 1583 bytesleft = PRARGSZ;
1576 1584 for (cp = psinfo->pr_psargs; *cp != '\0'; cp += length) {
1577 1585 length = mbtowc(&wchar, cp, MB_LEN_MAX);
1578 1586 if (length == 0)
1579 1587 break;
1580 1588 if (length < 0 || !iswprint(wchar)) {
1581 1589 if (length < 0)
1582 1590 length = 1;
1583 1591 if (bytesleft <= length) {
1584 1592 *cp = '\0';
1585 1593 break;
1586 1594 }
1587 1595 /* omit the unprintable character */
1588 1596 (void) memmove(cp, cp+length, bytesleft-length);
1589 1597 length = 0;
1590 1598 }
1591 1599 bytesleft -= length;
1592 1600 }
1593 1601 wcnt = namencnt(psinfo->pr_psargs, PRARGSZ, lflg ? 35 : PRARGSZ);
1594 1602 (void) printf(" %.*s\n", wcnt, psinfo->pr_psargs);
1595 1603 }
1596 1604
1597 1605 /*
1598 1606 * Print percent from 16-bit binary fraction [0 .. 1]
1599 1607 * Round up .01 to .1 to indicate some small percentage (the 0x7000 below).
1600 1608 */
1601 1609 static void
1602 1610 prtpct(ushort_t pct, int width)
1603 1611 {
1604 1612 uint_t value = pct; /* need 32 bits to compute with */
1605 1613
1606 1614 value = ((value * 1000) + 0x7000) >> 15; /* [0 .. 1000] */
1607 1615 if (value >= 1000)
1608 1616 value = 999;
1609 1617 if ((width -= 2) < 2)
1610 1618 width = 2;
1611 1619 (void) printf("%*u.%u", width, value / 10, value % 10);
1612 1620 }
1613 1621
1614 1622 static void
1615 1623 print_time(time_t tim, int width)
1616 1624 {
1617 1625 char buf[30];
1618 1626 time_t seconds;
1619 1627 time_t minutes;
1620 1628 time_t hours;
1621 1629 time_t days;
1622 1630
1623 1631 if (tim < 0) {
1624 1632 (void) printf("%*s", width, "-");
1625 1633 return;
1626 1634 }
1627 1635
1628 1636 seconds = tim % 60;
1629 1637 tim /= 60;
1630 1638 minutes = tim % 60;
1631 1639 tim /= 60;
1632 1640 hours = tim % 24;
1633 1641 days = tim / 24;
1634 1642
1635 1643 if (days > 0) {
1636 1644 (void) snprintf(buf, sizeof (buf), "%ld-%2.2ld:%2.2ld:%2.2ld",
1637 1645 days, hours, minutes, seconds);
1638 1646 } else if (hours > 0) {
1639 1647 (void) snprintf(buf, sizeof (buf), "%2.2ld:%2.2ld:%2.2ld",
1640 1648 hours, minutes, seconds);
1641 1649 } else {
1642 1650 (void) snprintf(buf, sizeof (buf), "%2.2ld:%2.2ld",
1643 1651 minutes, seconds);
1644 1652 }
1645 1653
1646 1654 (void) printf("%*s", width, buf);
1647 1655 }
1648 1656
1649 1657 static void
1650 1658 print_field(psinfo_t *psinfo, struct field *f, const char *ttyp)
1651 1659 {
1652 1660 int width = f->width;
1653 1661 struct passwd *pwd;
1654 1662 struct group *grp;
1655 1663 time_t cputime;
1656 1664 int bytesleft;
1657 1665 int wcnt;
1658 1666 wchar_t wchar;
1659 1667 char *cp;
1660 1668 int length;
1661 1669 ulong_t mask;
1662 1670 char c = '\0', *csave = NULL;
1663 1671 int zombie_lwp;
1664 1672
1665 1673 zombie_lwp = (Lflg && psinfo->pr_lwp.pr_sname == 'Z');
1666 1674
1667 1675 switch (f->fname) {
1668 1676 case F_RUSER:
1669 1677 if ((pwd = getpwuid(psinfo->pr_uid)) != NULL) {
1670 1678 size_t nw;
1671 1679
1672 1680 nw = mbstowcs(NULL, pwd->pw_name, 0);
1673 1681 if (nw == (size_t)-1)
1674 1682 (void) printf("%*s ", width, "ERROR");
1675 1683 else if (Wflg && nw > width)
1676 1684 (void) wprintf(L"%.*s%c", width - 1,
1677 1685 pwd->pw_name, '*');
1678 1686 else
1679 1687 (void) wprintf(L"%*s", width, pwd->pw_name);
1680 1688 } else {
1681 1689 if (Wflg && snprintf(NULL, 0, "%u",
1682 1690 (psinfo->pr_uid)) > width)
1683 1691
1684 1692 (void) printf("%*u%c", width - 1,
1685 1693 psinfo->pr_uid, '*');
1686 1694 else
1687 1695 (void) printf("%*u", width, psinfo->pr_uid);
1688 1696 }
1689 1697 break;
1690 1698 case F_USER:
1691 1699 if ((pwd = getpwuid(psinfo->pr_euid)) != NULL) {
1692 1700 size_t nw;
1693 1701
1694 1702 nw = mbstowcs(NULL, pwd->pw_name, 0);
1695 1703 if (nw == (size_t)-1)
1696 1704 (void) printf("%*s ", width, "ERROR");
1697 1705 else if (Wflg && nw > width)
1698 1706 (void) wprintf(L"%.*s%c", width - 1,
1699 1707 pwd->pw_name, '*');
1700 1708 else
1701 1709 (void) wprintf(L"%*s", width, pwd->pw_name);
1702 1710 } else {
1703 1711 if (Wflg && snprintf(NULL, 0, "%u",
1704 1712 (psinfo->pr_euid)) > width)
1705 1713
1706 1714 (void) printf("%*u%c", width - 1,
1707 1715 psinfo->pr_euid, '*');
1708 1716 else
1709 1717 (void) printf("%*u", width, psinfo->pr_euid);
1710 1718 }
1711 1719 break;
1712 1720 case F_RGROUP:
1713 1721 if ((grp = getgrgid(psinfo->pr_gid)) != NULL)
1714 1722 (void) printf("%*s", width, grp->gr_name);
1715 1723 else
1716 1724 (void) printf("%*u", width, psinfo->pr_gid);
1717 1725 break;
1718 1726 case F_GROUP:
1719 1727 if ((grp = getgrgid(psinfo->pr_egid)) != NULL)
1720 1728 (void) printf("%*s", width, grp->gr_name);
1721 1729 else
1722 1730 (void) printf("%*u", width, psinfo->pr_egid);
1723 1731 break;
1724 1732 case F_RUID:
1725 1733 (void) printf("%*u", width, psinfo->pr_uid);
1726 1734 break;
1727 1735 case F_UID:
1728 1736 (void) printf("%*u", width, psinfo->pr_euid);
1729 1737 break;
1730 1738 case F_RGID:
1731 1739 (void) printf("%*u", width, psinfo->pr_gid);
1732 1740 break;
1733 1741 case F_GID:
1734 1742 (void) printf("%*u", width, psinfo->pr_egid);
1735 1743 break;
1736 1744 case F_PID:
1737 1745 (void) printf("%*d", width, (int)psinfo->pr_pid);
1738 1746 break;
1739 1747 case F_PPID:
1740 1748 (void) printf("%*d", width, (int)psinfo->pr_ppid);
1741 1749 break;
1742 1750 case F_PGID:
1743 1751 (void) printf("%*d", width, (int)psinfo->pr_pgid);
1744 1752 break;
1745 1753 case F_SID:
1746 1754 (void) printf("%*d", width, (int)psinfo->pr_sid);
1747 1755 break;
1748 1756 case F_PSR:
1749 1757 if (zombie_lwp || psinfo->pr_lwp.pr_bindpro == PBIND_NONE)
1750 1758 (void) printf("%*s", width, "-");
1751 1759 else
1752 1760 (void) printf("%*d", width, psinfo->pr_lwp.pr_bindpro);
1753 1761 break;
1754 1762 case F_LWP:
1755 1763 (void) printf("%*d", width, (int)psinfo->pr_lwp.pr_lwpid);
1756 1764 break;
1757 1765 case F_NLWP:
1758 1766 (void) printf("%*d", width, psinfo->pr_nlwp + psinfo->pr_nzomb);
1759 1767 break;
1760 1768 case F_OPRI:
1761 1769 if (zombie_lwp)
1762 1770 (void) printf("%*s", width, "-");
1763 1771 else
1764 1772 (void) printf("%*d", width, psinfo->pr_lwp.pr_oldpri);
1765 1773 break;
1766 1774 case F_PRI:
1767 1775 if (zombie_lwp)
1768 1776 (void) printf("%*s", width, "-");
1769 1777 else
1770 1778 (void) printf("%*d", width, psinfo->pr_lwp.pr_pri);
1771 1779 break;
1772 1780 case F_F:
1773 1781 mask = 0xffffffffUL;
1774 1782 if (width < 8)
1775 1783 mask >>= (8 - width) * 4;
1776 1784 (void) printf("%*lx", width, psinfo->pr_flag & mask);
1777 1785 break;
1778 1786 case F_S:
1779 1787 (void) printf("%*c", width, psinfo->pr_lwp.pr_sname);
1780 1788 break;
1781 1789 case F_C:
1782 1790 if (zombie_lwp)
1783 1791 (void) printf("%*s", width, "-");
1784 1792 else
1785 1793 (void) printf("%*d", width, psinfo->pr_lwp.pr_cpu);
1786 1794 break;
1787 1795 case F_PCPU:
1788 1796 if (zombie_lwp)
1789 1797 (void) printf("%*s", width, "-");
1790 1798 else if (Lflg)
1791 1799 prtpct(psinfo->pr_lwp.pr_pctcpu, width);
1792 1800 else
1793 1801 prtpct(psinfo->pr_pctcpu, width);
1794 1802 break;
1795 1803 case F_PMEM:
1796 1804 prtpct(psinfo->pr_pctmem, width);
1797 1805 break;
1798 1806 case F_OSZ:
1799 1807 (void) printf("%*lu", width,
1800 1808 (ulong_t)psinfo->pr_size / kbytes_per_page);
1801 1809 break;
1802 1810 case F_VSZ:
1803 1811 (void) printf("%*lu", width, (ulong_t)psinfo->pr_size);
1804 1812 break;
1805 1813 case F_RSS:
1806 1814 (void) printf("%*lu", width, (ulong_t)psinfo->pr_rssize);
1807 1815 break;
1808 1816 case F_NICE:
1809 1817 /* if pr_oldpri is zero, then this class has no nice */
1810 1818 if (zombie_lwp)
1811 1819 (void) printf("%*s", width, "-");
1812 1820 else if (psinfo->pr_lwp.pr_oldpri != 0)
1813 1821 (void) printf("%*d", width, psinfo->pr_lwp.pr_nice);
1814 1822 else
1815 1823 (void) printf("%*.*s", width, width,
1816 1824 psinfo->pr_lwp.pr_clname);
1817 1825 break;
1818 1826 case F_CLASS:
1819 1827 if (zombie_lwp)
1820 1828 (void) printf("%*s", width, "-");
1821 1829 else
1822 1830 (void) printf("%*.*s", width, width,
1823 1831 psinfo->pr_lwp.pr_clname);
1824 1832 break;
1825 1833 case F_STIME:
1826 1834 if (Lflg)
1827 1835 prtime(psinfo->pr_lwp.pr_start, width, 0);
1828 1836 else
1829 1837 prtime(psinfo->pr_start, width, 0);
1830 1838 break;
1831 1839 case F_ETIME:
1832 1840 if (Lflg)
1833 1841 print_time(delta_secs(&psinfo->pr_lwp.pr_start),
1834 1842 width);
1835 1843 else
1836 1844 print_time(delta_secs(&psinfo->pr_start), width);
1837 1845 break;
1838 1846 case F_TIME:
1839 1847 if (Lflg) {
1840 1848 cputime = psinfo->pr_lwp.pr_time.tv_sec;
1841 1849 if (psinfo->pr_lwp.pr_time.tv_nsec > 500000000)
1842 1850 cputime++;
1843 1851 } else {
1844 1852 cputime = psinfo->pr_time.tv_sec;
1845 1853 if (psinfo->pr_time.tv_nsec > 500000000)
1846 1854 cputime++;
1847 1855 }
1848 1856 print_time(cputime, width);
1849 1857 break;
1850 1858 case F_TTY:
1851 1859 (void) printf("%-*s", width, ttyp);
1852 1860 break;
1853 1861 case F_ADDR:
1854 1862 if (zombie_lwp)
1855 1863 (void) printf("%*s", width, "-");
1856 1864 else if (Lflg)
1857 1865 (void) printf("%*lx", width,
1858 1866 (long)psinfo->pr_lwp.pr_addr);
1859 1867 else
1860 1868 (void) printf("%*lx", width, (long)psinfo->pr_addr);
1861 1869 break;
1862 1870 case F_WCHAN:
1863 1871 if (!zombie_lwp && psinfo->pr_lwp.pr_wchan)
1864 1872 (void) printf("%*lx", width,
1865 1873 (long)psinfo->pr_lwp.pr_wchan);
1866 1874 else
1867 1875 (void) printf("%*.*s", width, width, "-");
1868 1876 break;
1869 1877 case F_FNAME:
1870 1878 /*
1871 1879 * Print full width unless this is the last output format.
1872 1880 */
1873 1881 if (zombie_lwp) {
1874 1882 if (f->next != NULL)
1875 1883 (void) printf("%-*s", width, "<defunct>");
1876 1884 else
1877 1885 (void) printf("%s", "<defunct>");
1878 1886 break;
1879 1887 }
1880 1888 wcnt = namencnt(psinfo->pr_fname, 16, width);
1881 1889 if (f->next != NULL)
1882 1890 (void) printf("%-*.*s", width, wcnt, psinfo->pr_fname);
1883 1891 else
1884 1892 (void) printf("%-.*s", wcnt, psinfo->pr_fname);
1885 1893 break;
1886 1894 case F_COMM:
1887 1895 if (zombie_lwp) {
1888 1896 if (f->next != NULL)
1889 1897 (void) printf("%-*s", width, "<defunct>");
1890 1898 else
1891 1899 (void) printf("%s", "<defunct>");
1892 1900 break;
1893 1901 }
1894 1902 csave = strpbrk(psinfo->pr_psargs, " \t\r\v\f\n");
1895 1903 if (csave) {
1896 1904 c = *csave;
1897 1905 *csave = '\0';
1898 1906 }
1899 1907 /* FALLTHROUGH */
1900 1908 case F_ARGS:
1901 1909 /*
1902 1910 * PRARGSZ == length of cmd arg string.
1903 1911 */
1904 1912 if (zombie_lwp) {
1905 1913 (void) printf("%-*s", width, "<defunct>");
1906 1914 break;
1907 1915 }
1908 1916 psinfo->pr_psargs[PRARGSZ-1] = '\0';
1909 1917 bytesleft = PRARGSZ;
1910 1918 for (cp = psinfo->pr_psargs; *cp != '\0'; cp += length) {
1911 1919 length = mbtowc(&wchar, cp, MB_LEN_MAX);
1912 1920 if (length == 0)
1913 1921 break;
1914 1922 if (length < 0 || !iswprint(wchar)) {
1915 1923 if (length < 0)
1916 1924 length = 1;
1917 1925 if (bytesleft <= length) {
1918 1926 *cp = '\0';
1919 1927 break;
1920 1928 }
1921 1929 /* omit the unprintable character */
1922 1930 (void) memmove(cp, cp+length, bytesleft-length);
1923 1931 length = 0;
1924 1932 }
1925 1933 bytesleft -= length;
1926 1934 }
1927 1935 wcnt = namencnt(psinfo->pr_psargs, PRARGSZ, width);
1928 1936 /*
1929 1937 * Print full width unless this is the last format.
1930 1938 */
1931 1939 if (f->next != NULL)
1932 1940 (void) printf("%-*.*s", width, wcnt,
1933 1941 psinfo->pr_psargs);
1934 1942 else
1935 1943 (void) printf("%-.*s", wcnt,
1936 1944 psinfo->pr_psargs);
1937 1945 if (f->fname == F_COMM && csave)
1938 1946 *csave = c;
1939 1947 break;
1940 1948 case F_TASKID:
1941 1949 (void) printf("%*d", width, (int)psinfo->pr_taskid);
1942 1950 break;
1943 1951 case F_PROJID:
1944 1952 (void) printf("%*d", width, (int)psinfo->pr_projid);
1945 1953 break;
1946 1954 case F_PROJECT:
1947 1955 {
1948 1956 struct project cproj;
1949 1957 char proj_buf[PROJECT_BUFSZ];
1950 1958
1951 1959 if ((getprojbyid(psinfo->pr_projid, &cproj,
1952 1960 (void *)&proj_buf, PROJECT_BUFSZ)) == NULL) {
1953 1961 if (Wflg && snprintf(NULL, 0, "%d",
1954 1962 ((int)psinfo->pr_projid)) > width)
1955 1963 (void) printf("%.*d%c", width - 1,
1956 1964 ((int)psinfo->pr_projid), '*');
1957 1965 else
1958 1966 (void) printf("%*d", width,
1959 1967 (int)psinfo->pr_projid);
1960 1968 } else {
1961 1969 size_t nw;
1962 1970
1963 1971 if (cproj.pj_name != NULL)
1964 1972 nw = mbstowcs(NULL, cproj.pj_name, 0);
1965 1973 if (cproj.pj_name == NULL)
1966 1974 (void) printf("%*s ", width, "---");
1967 1975 else if (nw == (size_t)-1)
1968 1976 (void) printf("%*s ", width, "ERROR");
1969 1977 else if (Wflg && nw > width)
1970 1978 (void) wprintf(L"%.*s%c", width - 1,
1971 1979 cproj.pj_name, '*');
1972 1980 else
1973 1981 (void) wprintf(L"%*s", width,
1974 1982 cproj.pj_name);
1975 1983 }
1976 1984 }
1977 1985 break;
1978 1986 case F_PSET:
1979 1987 if (zombie_lwp || psinfo->pr_lwp.pr_bindpset == PS_NONE)
1980 1988 (void) printf("%*s", width, "-");
1981 1989 else
1982 1990 (void) printf("%*d", width, psinfo->pr_lwp.pr_bindpset);
1983 1991 break;
1984 1992 case F_ZONEID:
1985 1993 (void) printf("%*d", width, (int)psinfo->pr_zoneid);
1986 1994 break;
1987 1995 case F_ZONE:
1988 1996 {
1989 1997 char zonename[ZONENAME_MAX];
1990 1998
1991 1999 if (getzonenamebyid(psinfo->pr_zoneid, zonename,
1992 2000 sizeof (zonename)) < 0) {
1993 2001 if (Wflg && snprintf(NULL, 0, "%d",
1994 2002 ((int)psinfo->pr_zoneid)) > width)
1995 2003 (void) printf("%.*d%c", width - 1,
1996 2004 ((int)psinfo->pr_zoneid), '*');
1997 2005 else
1998 2006 (void) printf("%*d", width,
1999 2007 (int)psinfo->pr_zoneid);
2000 2008 } else {
2001 2009 size_t nw;
2002 2010
2003 2011 nw = mbstowcs(NULL, zonename, 0);
2004 2012 if (nw == (size_t)-1)
2005 2013 (void) printf("%*s ", width, "ERROR");
2006 2014 else if (Wflg && nw > width)
2007 2015 (void) wprintf(L"%.*s%c", width - 1,
2008 2016 zonename, '*');
2009 2017 else
2010 2018 (void) wprintf(L"%*s", width, zonename);
2011 2019 }
2012 2020 }
2013 2021 break;
2014 2022 case F_CTID:
2015 2023 if (psinfo->pr_contract == -1)
2016 2024 (void) printf("%*s", width, "-");
2017 2025 else
2018 2026 (void) printf("%*ld", width, (long)psinfo->pr_contract);
2019 2027 break;
2020 2028 case F_LGRP:
2021 2029 /* Display home lgroup */
2022 2030 (void) printf("%*d", width, (int)psinfo->pr_lwp.pr_lgrp);
2023 2031 break;
2024 2032
2025 2033 case F_DMODEL:
2026 2034 (void) printf("%*s", width,
2027 2035 psinfo->pr_dmodel == PR_MODEL_LP64 ? "_LP64" : "_ILP32");
2028 2036 break;
2029 2037 }
2030 2038 }
2031 2039
2032 2040 static void
2033 2041 print_zombie_field(psinfo_t *psinfo, struct field *f, const char *ttyp)
2034 2042 {
2035 2043 int wcnt;
2036 2044 int width = f->width;
2037 2045
2038 2046 switch (f->fname) {
2039 2047 case F_FNAME:
2040 2048 case F_COMM:
2041 2049 case F_ARGS:
2042 2050 /*
2043 2051 * Print full width unless this is the last output format.
2044 2052 */
2045 2053 wcnt = min(width, sizeof ("<defunct>"));
2046 2054 if (f->next != NULL)
2047 2055 (void) printf("%-*.*s", width, wcnt, "<defunct>");
2048 2056 else
2049 2057 (void) printf("%-.*s", wcnt, "<defunct>");
2050 2058 break;
2051 2059
2052 2060 case F_PSR:
2053 2061 case F_PCPU:
2054 2062 case F_PMEM:
2055 2063 case F_NICE:
2056 2064 case F_CLASS:
2057 2065 case F_STIME:
2058 2066 case F_ETIME:
2059 2067 case F_WCHAN:
2060 2068 case F_PSET:
2061 2069 (void) printf("%*s", width, "-");
2062 2070 break;
2063 2071
2064 2072 case F_OPRI:
2065 2073 case F_PRI:
2066 2074 case F_OSZ:
2067 2075 case F_VSZ:
2068 2076 case F_RSS:
2069 2077 (void) printf("%*d", width, 0);
|
↓ open down ↓ |
1716 lines elided |
↑ open up ↑ |
2070 2078 break;
2071 2079
2072 2080 default:
2073 2081 print_field(psinfo, f, ttyp);
2074 2082 break;
2075 2083 }
2076 2084 }
2077 2085
2078 2086 static void
2079 2087 pr_fields(psinfo_t *psinfo, const char *ttyp,
2080 - void (*print_fld)(psinfo_t *, struct field *, const char *))
2088 + void (*print_fld)(psinfo_t *, struct field *, const char *))
2081 2089 {
2082 2090 struct field *f;
2083 2091
2084 2092 for (f = fields; f != NULL; f = f->next) {
2085 2093 print_fld(psinfo, f, ttyp);
2086 2094 if (f->next != NULL)
2087 2095 (void) printf(" ");
2088 2096 }
2089 2097 (void) printf("\n");
2090 2098 }
2091 2099
2092 2100 /*
2093 2101 * Returns 1 if arg is found in array arr, of length num; 0 otherwise.
2094 2102 */
2095 2103 static int
2096 2104 search(pid_t *arr, int number, pid_t arg)
2097 2105 {
2098 2106 int i;
2099 2107
2100 2108 for (i = 0; i < number; i++)
2101 2109 if (arg == arr[i])
2102 2110 return (1);
2103 2111 return (0);
2104 2112 }
2105 2113
2106 2114 /*
2107 2115 * Add an entry (user, group) to the specified table.
2108 2116 */
2109 2117 static void
2110 2118 add_ugentry(struct ughead *tbl, char *name)
2111 2119 {
2112 2120 struct ugdata *entp;
2113 2121
2114 2122 if (tbl->size == tbl->nent) { /* reallocate the table entries */
2115 2123 if ((tbl->size *= 2) == 0)
2116 2124 tbl->size = 32; /* first time */
2117 2125 tbl->ent = Realloc(tbl->ent, tbl->size*sizeof (struct ugdata));
2118 2126 }
2119 2127 entp = &tbl->ent[tbl->nent++];
2120 2128 entp->id = 0;
2121 2129 (void) strncpy(entp->name, name, MAXUGNAME);
2122 2130 entp->name[MAXUGNAME] = '\0';
2123 2131 }
2124 2132
2125 2133 static int
2126 2134 uconv(struct ughead *uhead)
2127 2135 {
2128 2136 struct ugdata *utbl = uhead->ent;
2129 2137 int n = uhead->nent;
2130 2138 struct passwd *pwd;
2131 2139 int i;
2132 2140 int fnd = 0;
2133 2141 uid_t uid;
2134 2142
2135 2143 /*
2136 2144 * Ask the name service for names.
2137 2145 */
2138 2146 for (i = 0; i < n; i++) {
2139 2147 /*
2140 2148 * If name is numeric, ask for numeric id
2141 2149 */
2142 2150 if (str2uid(utbl[i].name, &uid, 0, MAXEPHUID) == 0)
2143 2151 pwd = getpwuid(uid);
2144 2152 else
2145 2153 pwd = getpwnam(utbl[i].name);
2146 2154
2147 2155 /*
2148 2156 * If found, enter found index into tbl array.
2149 2157 */
2150 2158 if (pwd == NULL) {
2151 2159 (void) fprintf(stderr,
2152 2160 gettext("ps: unknown user %s\n"), utbl[i].name);
2153 2161 continue;
2154 2162 }
2155 2163
2156 2164 utbl[fnd].id = pwd->pw_uid;
2157 2165 (void) strncpy(utbl[fnd].name, pwd->pw_name, MAXUGNAME);
2158 2166 fnd++;
2159 2167 }
2160 2168
2161 2169 uhead->nent = fnd; /* in case it changed */
2162 2170 return (n - fnd);
2163 2171 }
2164 2172
2165 2173 static int
2166 2174 gconv(struct ughead *ghead)
2167 2175 {
2168 2176 struct ugdata *gtbl = ghead->ent;
2169 2177 int n = ghead->nent;
2170 2178 struct group *grp;
2171 2179 gid_t gid;
2172 2180 int i;
2173 2181 int fnd = 0;
2174 2182
2175 2183 /*
2176 2184 * Ask the name service for names.
2177 2185 */
2178 2186 for (i = 0; i < n; i++) {
2179 2187 /*
2180 2188 * If name is numeric, ask for numeric id
2181 2189 */
2182 2190 if (str2uid(gtbl[i].name, (uid_t *)&gid, 0, MAXEPHUID) == 0)
2183 2191 grp = getgrgid(gid);
2184 2192 else
2185 2193 grp = getgrnam(gtbl[i].name);
2186 2194 /*
2187 2195 * If found, enter found index into tbl array.
2188 2196 */
2189 2197 if (grp == NULL) {
2190 2198 (void) fprintf(stderr,
2191 2199 gettext("ps: unknown group %s\n"), gtbl[i].name);
2192 2200 continue;
2193 2201 }
2194 2202
2195 2203 gtbl[fnd].id = grp->gr_gid;
2196 2204 (void) strncpy(gtbl[fnd].name, grp->gr_name, MAXUGNAME);
2197 2205 fnd++;
2198 2206 }
2199 2207
2200 2208 ghead->nent = fnd; /* in case it changed */
2201 2209 return (n - fnd);
2202 2210 }
2203 2211
2204 2212 /*
2205 2213 * Return 1 if puid is in table, otherwise 0.
2206 2214 */
2207 2215 static int
2208 2216 ugfind(id_t id, struct ughead *ughead)
2209 2217 {
2210 2218 struct ugdata *utbl = ughead->ent;
2211 2219 int n = ughead->nent;
2212 2220 int i;
2213 2221
2214 2222 for (i = 0; i < n; i++)
2215 2223 if (utbl[i].id == id)
2216 2224 return (1);
2217 2225 return (0);
2218 2226 }
2219 2227
2220 2228 /*
2221 2229 * Print starting time of process unless process started more than 24 hours
2222 2230 * ago, in which case the date is printed. The date is printed in the form
2223 2231 * "MMM dd" if old format, else the blank is replaced with an '_' so
2224 2232 * it appears as a single word (for parseability).
2225 2233 */
2226 2234 static void
2227 2235 prtime(timestruc_t st, int width, int old)
2228 2236 {
2229 2237 char sttim[26];
2230 2238 time_t starttime;
2231 2239
2232 2240 starttime = st.tv_sec;
2233 2241 if (st.tv_nsec > 500000000)
2234 2242 starttime++;
2235 2243 if ((now.tv_sec - starttime) >= 24*60*60) {
2236 2244 (void) strftime(sttim, sizeof (sttim), old?
2237 2245 /*
2238 2246 * TRANSLATION_NOTE
2239 2247 * This time format is used by STIME field when -f option
2240 2248 * is specified. Used for processes that begun more than
2241 2249 * 24 hours.
2242 2250 */
2243 2251 dcgettext(NULL, "%b %d", LC_TIME) :
2244 2252 /*
2245 2253 * TRANSLATION_NOTE
2246 2254 * This time format is used by STIME field when -o option
2247 2255 * is specified. Used for processes that begun more than
2248 2256 * 24 hours.
2249 2257 */
2250 2258 dcgettext(NULL, "%b_%d", LC_TIME), localtime(&starttime));
2251 2259 } else {
2252 2260 /*
2253 2261 * TRANSLATION_NOTE
2254 2262 * This time format is used by STIME field when -f or -o option
2255 2263 * is specified. Used for processes that begun less than
2256 2264 * 24 hours.
2257 2265 */
2258 2266 (void) strftime(sttim, sizeof (sttim),
2259 2267 dcgettext(NULL, "%H:%M:%S", LC_TIME),
2260 2268 localtime(&starttime));
2261 2269 }
2262 2270 (void) printf("%*.*s", width, width, sttim);
2263 2271 }
2264 2272
2265 2273 static void
2266 2274 przom(psinfo_t *psinfo)
2267 2275 {
2268 2276 long tm;
2269 2277 struct passwd *pwd;
2270 2278 char zonename[ZONENAME_MAX];
2271 2279
2272 2280 /*
2273 2281 * All fields before 'PID' are printed with a trailing space as a
2274 2282 * spearator, rather than keeping track of which column is first. All
2275 2283 * other fields are printed with a leading space.
2276 2284 */
2277 2285 if (lflg) { /* F S */
2278 2286 if (!yflg)
2279 2287 (void) printf("%2x ", psinfo->pr_flag & 0377); /* F */
2280 2288 (void) printf("%c ", psinfo->pr_lwp.pr_sname); /* S */
2281 2289 }
2282 2290 if (Zflg) {
2283 2291 if (getzonenamebyid(psinfo->pr_zoneid, zonename,
2284 2292 sizeof (zonename)) < 0) {
2285 2293 if (snprintf(NULL, 0, "%d",
2286 2294 ((int)psinfo->pr_zoneid)) > 7)
2287 2295 (void) printf(" %6.6d%c ",
2288 2296 ((int)psinfo->pr_zoneid), '*');
2289 2297 else
2290 2298 (void) printf(" %7.7d ",
2291 2299 ((int)psinfo->pr_zoneid));
2292 2300 } else {
2293 2301 size_t nw;
2294 2302
2295 2303 nw = mbstowcs(NULL, zonename, 0);
2296 2304 if (nw == (size_t)-1)
2297 2305 (void) printf("%8.8s ", "ERROR");
2298 2306 else if (nw > 8)
2299 2307 (void) wprintf(L"%7.7s%c ", zonename, '*');
2300 2308 else
2301 2309 (void) wprintf(L"%8.8s ", zonename);
2302 2310 }
2303 2311 }
2304 2312 if (Hflg) {
2305 2313 /* Display home lgroup */
2306 2314 (void) printf(" %6d", (int)psinfo->pr_lwp.pr_lgrp); /* LGRP */
2307 2315 }
2308 2316 if (fflg) {
2309 2317 if ((pwd = getpwuid(psinfo->pr_euid)) != NULL) {
2310 2318 size_t nw;
2311 2319
2312 2320 nw = mbstowcs(NULL, pwd->pw_name, 0);
2313 2321 if (nw == (size_t)-1)
2314 2322 (void) printf("%8.8s ", "ERROR");
2315 2323 else if (nw > 8)
2316 2324 (void) wprintf(L"%7.7s%c ", pwd->pw_name, '*');
2317 2325 else
2318 2326 (void) wprintf(L"%8.8s ", pwd->pw_name);
2319 2327 } else {
2320 2328 if (snprintf(NULL, 0, "%u",
2321 2329 (psinfo->pr_euid)) > 7)
2322 2330 (void) printf(" %6.6u%c ", psinfo->pr_euid,
2323 2331 '*');
2324 2332 else
2325 2333 (void) printf(" %7.7u ", psinfo->pr_euid);
2326 2334 }
2327 2335 } else if (lflg) {
2328 2336 if (snprintf(NULL, 0, "%u", (psinfo->pr_euid)) > 6)
2329 2337 (void) printf("%5.5u%c ", psinfo->pr_euid, '*');
2330 2338 else
2331 2339 (void) printf("%6u ", psinfo->pr_euid);
2332 2340 }
2333 2341
2334 2342 (void) printf("%*d", pidwidth, (int)psinfo->pr_pid); /* PID */
2335 2343 if (lflg || fflg)
2336 2344 (void) printf(" %*d", pidwidth,
2337 2345 (int)psinfo->pr_ppid); /* PPID */
2338 2346
2339 2347 if (jflg) {
2340 2348 (void) printf(" %*d", pidwidth,
2341 2349 (int)psinfo->pr_pgid); /* PGID */
2342 2350 (void) printf(" %*d", pidwidth,
2343 2351 (int)psinfo->pr_sid); /* SID */
2344 2352 }
2345 2353
2346 2354 if (Lflg)
2347 2355 (void) printf(" %5d", 0); /* LWP */
2348 2356 if (Pflg)
2349 2357 (void) printf(" -"); /* PSR */
2350 2358 if (Lflg && fflg)
2351 2359 (void) printf(" %5d", 0); /* NLWP */
2352 2360
2353 2361 if (cflg) {
2354 2362 (void) printf(" %4s", "-"); /* zombies have no class */
2355 2363 (void) printf(" %3d", psinfo->pr_lwp.pr_pri); /* PRI */
2356 2364 } else if (lflg || fflg) {
2357 2365 (void) printf(" %3d", psinfo->pr_lwp.pr_cpu & 0377); /* C */
2358 2366 if (lflg)
2359 2367 (void) printf(" %3d %2s",
2360 2368 psinfo->pr_lwp.pr_oldpri, "-"); /* PRI NI */
2361 2369 }
2362 2370 if (lflg) {
2363 2371 if (yflg) /* RSS SZ WCHAN */
2364 2372 (void) printf(" %5d %6d %8s", 0, 0, "-");
2365 2373 else /* ADDR SZ WCHAN */
2366 2374 (void) printf(" %8s %6d %8s", "-", 0, "-");
2367 2375 }
2368 2376 if (fflg) {
2369 2377 int width = fname[F_STIME].width;
2370 2378 (void) printf(" %*.*s", width, width, "-"); /* STIME */
2371 2379 }
2372 2380 (void) printf(" %-8.14s", "?"); /* TTY */
2373 2381
2374 2382 tm = psinfo->pr_time.tv_sec;
2375 2383 if (psinfo->pr_time.tv_nsec > 500000000)
2376 2384 tm++;
2377 2385 (void) printf(" %4ld:%.2ld", tm / 60, tm % 60); /* TIME */
2378 2386 (void) printf(" <defunct>\n");
2379 2387 }
2380 2388
2381 2389 /*
2382 2390 * Function to compute the number of printable bytes in a multibyte
2383 2391 * command string ("internationalization").
2384 2392 */
2385 2393 static int
2386 2394 namencnt(char *cmd, int csisize, int scrsize)
2387 2395 {
2388 2396 int csiwcnt = 0, scrwcnt = 0;
2389 2397 int ncsisz, nscrsz;
2390 2398 wchar_t wchar;
2391 2399 int len;
2392 2400
2393 2401 while (*cmd != '\0') {
2394 2402 if ((len = csisize - csiwcnt) > (int)MB_CUR_MAX)
2395 2403 len = MB_CUR_MAX;
2396 2404 if ((ncsisz = mbtowc(&wchar, cmd, len)) < 0)
2397 2405 return (8); /* default to use for illegal chars */
2398 2406 if ((nscrsz = wcwidth(wchar)) <= 0)
2399 2407 return (8);
2400 2408 if (csiwcnt + ncsisz > csisize || scrwcnt + nscrsz > scrsize)
2401 2409 break;
2402 2410 csiwcnt += ncsisz;
2403 2411 scrwcnt += nscrsz;
2404 2412 cmd += ncsisz;
2405 2413 }
2406 2414 return (csiwcnt);
2407 2415 }
2408 2416
2409 2417 static char *
2410 2418 err_string(int err)
2411 2419 {
2412 2420 static char buf[32];
2413 2421 char *str = strerror(err);
2414 2422
2415 2423 if (str == NULL)
2416 2424 (void) snprintf(str = buf, sizeof (buf), "Errno #%d", err);
2417 2425
2418 2426 return (str);
2419 2427 }
2420 2428
2421 2429 /* If allocation fails, die */
2422 2430 static void *
2423 2431 Realloc(void *ptr, size_t size)
2424 2432 {
2425 2433 ptr = realloc(ptr, size);
2426 2434 if (ptr == NULL) {
2427 2435 (void) fprintf(stderr, gettext("ps: no memory\n"));
2428 2436 exit(1);
2429 2437 }
2430 2438 return (ptr);
2431 2439 }
2432 2440
2433 2441 static time_t
2434 2442 delta_secs(const timestruc_t *start)
2435 2443 {
2436 2444 time_t seconds = now.tv_sec - start->tv_sec;
2437 2445 long nanosecs = now.tv_usec * 1000 - start->tv_nsec;
2438 2446
2439 2447 if (nanosecs >= (NANOSEC / 2))
2440 2448 seconds++;
2441 2449 else if (nanosecs < -(NANOSEC / 2))
2442 2450 seconds--;
2443 2451
2444 2452 return (seconds);
2445 2453 }
2446 2454
2447 2455 /*
2448 2456 * Returns the following:
2449 2457 *
2450 2458 * 0 No error
2451 2459 * EINVAL Invalid number
2452 2460 * ERANGE Value exceeds (min, max) range
2453 2461 */
2454 2462 static int
2455 2463 str2id(const char *p, pid_t *val, long min, long max)
2456 2464 {
2457 2465 char *q;
2458 2466 long number;
2459 2467 int error;
2460 2468
2461 2469 errno = 0;
2462 2470 number = strtol(p, &q, 10);
2463 2471
2464 2472 if (errno != 0 || q == p || *q != '\0') {
2465 2473 if ((error = errno) == 0) {
2466 2474 /*
2467 2475 * strtol() can fail without setting errno, or it can
2468 2476 * set it to EINVAL or ERANGE. In the case errno is
2469 2477 * still zero, return EINVAL.
2470 2478 */
2471 2479 error = EINVAL;
2472 2480 }
2473 2481 } else if (number < min || number > max) {
2474 2482 error = ERANGE;
2475 2483 } else {
2476 2484 error = 0;
2477 2485 }
2478 2486
2479 2487 *val = number;
2480 2488
2481 2489 return (error);
2482 2490 }
2483 2491
2484 2492 /*
2485 2493 * Returns the following:
2486 2494 *
2487 2495 * 0 No error
2488 2496 * EINVAL Invalid number
2489 2497 * ERANGE Value exceeds (min, max) range
2490 2498 */
2491 2499 static int
2492 2500 str2uid(const char *p, uid_t *val, unsigned long min, unsigned long max)
2493 2501 {
2494 2502 char *q;
2495 2503 unsigned long number;
2496 2504 int error;
2497 2505
2498 2506 errno = 0;
2499 2507 number = strtoul(p, &q, 10);
2500 2508
2501 2509 if (errno != 0 || q == p || *q != '\0') {
2502 2510 if ((error = errno) == 0) {
2503 2511 /*
2504 2512 * strtoul() can fail without setting errno, or it can
2505 2513 * set it to EINVAL or ERANGE. In the case errno is
2506 2514 * still zero, return EINVAL.
2507 2515 */
2508 2516 error = EINVAL;
2509 2517 }
2510 2518 } else if (number < min || number > max) {
2511 2519 error = ERANGE;
2512 2520 } else {
2513 2521 error = 0;
2514 2522 }
2515 2523
2516 2524 *val = number;
2517 2525
2518 2526 return (error);
2519 2527 }
2520 2528
2521 2529 static int
2522 2530 pidcmp(const void *p1, const void *p2)
2523 2531 {
2524 2532 pid_t i = *((pid_t *)p1);
2525 2533 pid_t j = *((pid_t *)p2);
2526 2534
2527 2535 return (i - j);
2528 2536 }
|
↓ open down ↓ |
438 lines elided |
↑ open up ↑ |
XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX