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