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