1 0 stevel /* 2 0 stevel * CDDL HEADER START 3 0 stevel * 4 0 stevel * The contents of this file are subject to the terms of the 5 8822 Casper * Common Development and Distribution License (the "License"). 6 8822 Casper * You may not use this file except in compliance with the License. 7 0 stevel * 8 0 stevel * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE 9 0 stevel * or http://www.opensolaris.org/os/licensing. 10 0 stevel * See the License for the specific language governing permissions 11 0 stevel * and limitations under the License. 12 0 stevel * 13 0 stevel * When distributing Covered Code, include this CDDL HEADER in each 14 0 stevel * file and include the License file at usr/src/OPENSOLARIS.LICENSE. 15 0 stevel * If applicable, add the following below this CDDL HEADER, with the 16 0 stevel * fields enclosed by brackets "[]" replaced with your own identifying 17 0 stevel * information: Portions Copyright [yyyy] [name of copyright owner] 18 0 stevel * 19 0 stevel * CDDL HEADER END 20 0 stevel */ 21 0 stevel /* 22 8822 Casper * Copyright 2009 Sun Microsystems, Inc. All rights reserved. 23 0 stevel * Use is subject to license terms. 24 0 stevel */ 25 0 stevel 26 0 stevel /* Copyright (c) 1984, 1986, 1987, 1988, 1989 AT&T */ 27 0 stevel /* All Rights Reserved */ 28 0 stevel 29 0 stevel /* 30 0 stevel * University Copyright- Copyright (c) 1982, 1986, 1988 31 0 stevel * The Regents of the University of California 32 0 stevel * All Rights Reserved 33 0 stevel * 34 0 stevel * University Acknowledgment- Portions of this document are derived from 35 0 stevel * software developed by the University of California, Berkeley, and its 36 0 stevel * contributors. 37 0 stevel */ 38 0 stevel 39 0 stevel /* 40 0 stevel * ps -- print things about processes. 41 0 stevel */ 42 0 stevel 43 0 stevel #define _SYSCALL32 44 0 stevel 45 0 stevel #include <stdio.h> 46 0 stevel #include <ctype.h> 47 0 stevel #include <string.h> 48 0 stevel #include <errno.h> 49 0 stevel #include <fcntl.h> 50 0 stevel #include <pwd.h> 51 0 stevel #include <sys/types.h> 52 0 stevel #include <sys/stat.h> 53 0 stevel #include <sys/mkdev.h> 54 0 stevel #include <unistd.h> 55 0 stevel #include <stdlib.h> 56 0 stevel #include <limits.h> 57 0 stevel #include <dirent.h> 58 0 stevel #include <procfs.h> 59 0 stevel #include <sys/param.h> 60 0 stevel #include <sys/ttold.h> 61 0 stevel #include <libelf.h> 62 0 stevel #include <gelf.h> 63 0 stevel #include <locale.h> 64 0 stevel #include <wctype.h> 65 0 stevel #include <stdarg.h> 66 0 stevel #include <sys/proc.h> 67 0 stevel #include <priv_utils.h> 68 0 stevel 69 0 stevel #define NTTYS 2 /* max ttys that can be specified with the -t option */ 70 0 stevel /* only one tty can be specified with SunOS ps */ 71 0 stevel #define SIZ 30 /* max processes that can be specified with -p and -g */ 72 0 stevel #define ARGSIZ 30 /* size of buffer holding args for -t, -p, -u options */ 73 0 stevel 74 0 stevel #define FSTYPE_MAX 8 75 0 stevel 76 0 stevel struct psent { 77 0 stevel psinfo_t *psinfo; 78 0 stevel char *psargs; 79 0 stevel int found; 80 0 stevel }; 81 0 stevel 82 0 stevel static int tplen, maxlen, twidth; 83 0 stevel static char hdr[81]; 84 0 stevel static struct winsize win; 85 0 stevel 86 0 stevel static int retcode = 1; 87 0 stevel static int lflg; /* long format */ 88 0 stevel static int uflg; /* user-oriented output */ 89 0 stevel static int aflg; /* Display all processes */ 90 0 stevel static int eflg; /* Display environment as well as arguments */ 91 0 stevel static int gflg; /* Display process group leaders */ 92 0 stevel static int tflg; /* Processes running on specific terminals */ 93 0 stevel static int rflg; /* Running processes only flag */ 94 0 stevel static int Sflg; /* Accumulated time plus all reaped children */ 95 0 stevel static int xflg; /* Include processes with no controlling tty */ 96 0 stevel static int cflg; /* Display command name */ 97 0 stevel static int vflg; /* Virtual memory-oriented output */ 98 0 stevel static int nflg; /* Numerical output */ 99 0 stevel static int pflg; /* Specific process id passed as argument */ 100 0 stevel static int Uflg; /* Update private database, ups_data */ 101 0 stevel static int errflg; 102 0 stevel 103 0 stevel static char *gettty(); 104 0 stevel static char argbuf[ARGSIZ]; 105 0 stevel static char *parg; 106 0 stevel static char *p1; /* points to successive option arguments */ 107 0 stevel static uid_t my_uid; 108 0 stevel static char stdbuf[BUFSIZ]; 109 0 stevel 110 0 stevel static int ndev; /* number of devices */ 111 0 stevel static int maxdev; /* number of devl structures allocated */ 112 0 stevel 113 0 stevel #define DNINCR 100 114 0 stevel #define DNSIZE 14 115 0 stevel static struct devl { /* device list */ 116 0 stevel char dname[DNSIZE]; /* device name */ 117 0 stevel dev_t ddev; /* device number */ 118 0 stevel } *devl; 119 0 stevel 120 0 stevel static struct tty { 121 0 stevel char *tname; 122 0 stevel dev_t tdev; 123 0 stevel } tty[NTTYS]; /* for t option */ 124 0 stevel static int ntty = 0; 125 0 stevel static pid_t pidsave; 126 0 stevel static int pidwidth; 127 0 stevel 128 0 stevel static char *procdir = "/proc"; /* standard /proc directory */ 129 0 stevel static void usage(); /* print usage message and quit */ 130 0 stevel static void getarg(void); 131 0 stevel static void prtime(timestruc_t st); 132 0 stevel static void przom(psinfo_t *psinfo); 133 0 stevel static int num(char *); 134 0 stevel static int preadargs(int, psinfo_t *, char *); 135 0 stevel static int preadenvs(int, psinfo_t *, char *); 136 0 stevel static int prcom(int, psinfo_t *, char *); 137 0 stevel static int namencnt(char *, int, int); 138 0 stevel static int pscompare(const void *, const void *); 139 0 stevel static char *err_string(int); 140 0 stevel 141 0 stevel extern int scrwidth(wchar_t); /* header file? */ 142 0 stevel 143 0 stevel int 144 8822 Casper ucbmain(int argc, char **argv) 145 0 stevel { 146 0 stevel psinfo_t info; /* process information structure from /proc */ 147 0 stevel char *psargs = NULL; /* pointer to buffer for -w and -ww options */ 148 0 stevel char *svpsargs = NULL; 149 0 stevel struct psent *psent; 150 0 stevel int entsize; 151 0 stevel int nent; 152 0 stevel pid_t maxpid; 153 0 stevel 154 0 stevel struct tty *ttyp = tty; 155 0 stevel char *tmp; 156 0 stevel char *p; 157 0 stevel int c; 158 0 stevel pid_t pid; /* pid: process id */ 159 0 stevel pid_t ppid; /* ppid: parent process id */ 160 0 stevel int i, found; 161 0 stevel 162 0 stevel size_t size; 163 0 stevel 164 0 stevel DIR *dirp; 165 0 stevel struct dirent *dentp; 166 0 stevel char psname[100]; 167 0 stevel char asname[100]; 168 0 stevel int pdlen; 169 0 stevel size_t len; 170 0 stevel 171 0 stevel (void) setlocale(LC_ALL, ""); 172 0 stevel 173 0 stevel my_uid = getuid(); 174 0 stevel 175 0 stevel /* 176 0 stevel * This program needs the proc_owner privilege 177 0 stevel */ 178 0 stevel (void) __init_suid_priv(PU_CLEARLIMITSET, PRIV_PROC_OWNER, 179 0 stevel (char *)NULL); 180 0 stevel 181 0 stevel /* 182 0 stevel * calculate width of pid fields based on configured MAXPID 183 0 stevel * (must be at least 5 to retain output format compatibility) 184 0 stevel */ 185 0 stevel maxpid = (pid_t)sysconf(_SC_MAXPID); 186 0 stevel pidwidth = 1; 187 0 stevel while ((maxpid /= 10) > 0) 188 0 stevel ++pidwidth; 189 0 stevel pidwidth = pidwidth < 5 ? 5 : pidwidth; 190 0 stevel 191 0 stevel if (ioctl(1, TIOCGWINSZ, &win) == -1) 192 0 stevel twidth = 80; 193 0 stevel else 194 0 stevel twidth = (win.ws_col == 0 ? 80 : win.ws_col); 195 0 stevel 196 0 stevel /* add the '-' for BSD compatibility */ 197 0 stevel if (argc > 1) { 198 0 stevel if (argv[1][0] != '-' && !isdigit(argv[1][0])) { 199 0 stevel len = strlen(argv[1]) + 2; 200 0 stevel tmp = malloc(len); 201 0 stevel if (tmp != NULL) { 202 0 stevel (void) snprintf(tmp, len, "%s%s", "-", argv[1]); 203 0 stevel argv[1] = tmp; 204 0 stevel } 205 0 stevel } 206 0 stevel } 207 0 stevel 208 0 stevel setbuf(stdout, stdbuf); 209 0 stevel while ((c = getopt(argc, argv, "lcaengrSt:xuvwU")) != EOF) 210 0 stevel switch (c) { 211 0 stevel case 'g': 212 0 stevel gflg++; /* include process group leaders */ 213 0 stevel break; 214 0 stevel case 'c': /* display internal command name */ 215 0 stevel cflg++; 216 0 stevel break; 217 0 stevel case 'r': /* restrict output to running processes */ 218 0 stevel rflg++; 219 0 stevel break; 220 0 stevel case 'S': /* display time by process and all reaped children */ 221 0 stevel Sflg++; 222 0 stevel break; 223 0 stevel case 'x': /* process w/o controlling tty */ 224 0 stevel xflg++; 225 0 stevel break; 226 0 stevel case 'l': /* long listing */ 227 0 stevel lflg++; 228 0 stevel uflg = vflg = 0; 229 0 stevel break; 230 0 stevel case 'u': /* user-oriented output */ 231 0 stevel uflg++; 232 0 stevel lflg = vflg = 0; 233 0 stevel break; 234 0 stevel case 'U': /* update private database ups_data */ 235 0 stevel Uflg++; 236 0 stevel break; 237 0 stevel case 'w': /* increase display width */ 238 0 stevel if (twidth < 132) 239 0 stevel twidth = 132; 240 0 stevel else /* second w option */ 241 0 stevel twidth = NCARGS; 242 0 stevel break; 243 0 stevel case 'v': /* display virtual memory format */ 244 0 stevel vflg++; 245 0 stevel lflg = uflg = 0; 246 0 stevel break; 247 0 stevel case 'a': 248 0 stevel /* 249 0 stevel * display all processes except process group 250 0 stevel * leaders and processes w/o controlling tty 251 0 stevel */ 252 0 stevel aflg++; 253 0 stevel gflg++; 254 0 stevel break; 255 0 stevel case 'e': 256 0 stevel /* Display environment along with aguments. */ 257 0 stevel eflg++; 258 0 stevel break; 259 0 stevel case 'n': /* Display numerical output */ 260 0 stevel nflg++; 261 0 stevel break; 262 0 stevel case 't': /* restrict output to named terminal */ 263 0 stevel #define TSZ 30 264 0 stevel tflg++; 265 0 stevel gflg++; 266 0 stevel xflg = 0; 267 0 stevel 268 0 stevel p1 = optarg; 269 0 stevel do { /* only loop through once (NTTYS = 2) */ 270 0 stevel parg = argbuf; 271 0 stevel if (ntty >= NTTYS-1) 272 0 stevel break; 273 0 stevel getarg(); 274 0 stevel if ((p = malloc(TSZ+1)) == NULL) { 275 0 stevel (void) fprintf(stderr, 276 0 stevel "ps: no memory\n"); 277 0 stevel exit(1); 278 0 stevel } 279 0 stevel p[0] = '\0'; 280 0 stevel size = TSZ; 281 0 stevel if (isdigit(*parg)) { 282 0 stevel (void) strcpy(p, "tty"); 283 0 stevel size -= 3; 284 0 stevel } 285 0 stevel 286 0 stevel (void) strncat(p, parg, size); 287 0 stevel ttyp->tdev = PRNODEV; 288 0 stevel if (parg && *parg == '?') 289 0 stevel xflg++; 290 0 stevel else { 291 0 stevel char nambuf[TSZ+6]; /* for /dev/+\0 */ 292 0 stevel struct stat64 s; 293 0 stevel (void) strcpy(nambuf, "/dev/"); 294 0 stevel (void) strcat(nambuf, p); 295 0 stevel if (stat64(nambuf, &s) == 0) 296 0 stevel ttyp->tdev = s.st_rdev; 297 0 stevel } 298 0 stevel ttyp++->tname = p; 299 0 stevel ntty++; 300 0 stevel } while (*p1); 301 0 stevel break; 302 0 stevel default: /* error on ? */ 303 0 stevel errflg++; 304 0 stevel break; 305 0 stevel } 306 0 stevel 307 0 stevel if (errflg) 308 0 stevel usage(); 309 0 stevel 310 0 stevel if (optind + 1 < argc) { /* more than one additional argument */ 311 0 stevel (void) fprintf(stderr, "ps: too many arguments\n"); 312 0 stevel usage(); 313 0 stevel } 314 0 stevel 315 0 stevel /* 316 0 stevel * The -U option is obsolete. Attempts to use it cause ps to exit 317 0 stevel * without printing anything. 318 0 stevel */ 319 0 stevel if (Uflg) 320 0 stevel exit(0); 321 0 stevel 322 0 stevel if (optind < argc) { /* user specified a specific proc id */ 323 0 stevel pflg++; 324 0 stevel p1 = argv[optind]; 325 0 stevel parg = argbuf; 326 0 stevel getarg(); 327 0 stevel if (!num(parg)) { 328 0 stevel (void) fprintf(stderr, 329 0 stevel "ps: %s is an invalid non-numeric argument for a process id\n", parg); 330 0 stevel usage(); 331 0 stevel } 332 0 stevel pidsave = (pid_t)atol(parg); 333 0 stevel aflg = rflg = xflg = 0; 334 0 stevel gflg++; 335 0 stevel } 336 0 stevel 337 0 stevel if (tflg) 338 0 stevel ttyp->tname = NULL; 339 0 stevel 340 0 stevel /* allocate an initial guess for the number of processes */ 341 0 stevel entsize = 1024; 342 0 stevel psent = malloc(entsize * sizeof (struct psent)); 343 0 stevel if (psent == NULL) { 344 0 stevel (void) fprintf(stderr, "ps: no memory\n"); 345 0 stevel exit(1); 346 0 stevel } 347 0 stevel nent = 0; /* no active entries yet */ 348 0 stevel 349 0 stevel if (lflg) { 350 0 stevel (void) sprintf(hdr, 351 0 stevel " F UID%*s%*s %%C PRI NI SZ RSS " 352 0 stevel "WCHAN S TT TIME COMMAND", pidwidth + 1, "PID", 353 0 stevel pidwidth + 1, "PPID"); 354 0 stevel } else if (uflg) { 355 0 stevel if (nflg) 356 0 stevel (void) sprintf(hdr, 357 0 stevel " UID%*s %%CPU %%MEM SZ RSS " 358 0 stevel "TT S START TIME COMMAND", 359 0 stevel pidwidth + 1, "PID"); 360 0 stevel else 361 0 stevel (void) sprintf(hdr, 362 0 stevel "USER %*s %%CPU %%MEM SZ RSS " 363 0 stevel "TT S START TIME COMMAND", 364 0 stevel pidwidth + 1, "PID"); 365 0 stevel } else if (vflg) { 366 0 stevel (void) sprintf(hdr, 367 0 stevel "%*s TT S TIME SIZE RSS %%CPU %%MEM " 368 0 stevel "COMMAND", pidwidth + 1, "PID"); 369 0 stevel } else 370 0 stevel (void) sprintf(hdr, "%*s TT S TIME COMMAND", 371 0 stevel pidwidth + 1, "PID"); 372 0 stevel 373 0 stevel twidth = twidth - strlen(hdr) + 6; 374 0 stevel (void) printf("%s\n", hdr); 375 0 stevel 376 0 stevel if (twidth > PRARGSZ && (psargs = malloc(twidth)) == NULL) { 377 0 stevel (void) fprintf(stderr, "ps: no memory\n"); 378 0 stevel exit(1); 379 0 stevel } 380 0 stevel svpsargs = psargs; 381 0 stevel 382 0 stevel /* 383 0 stevel * Determine which processes to print info about by searching 384 0 stevel * the /proc directory and looking at each process. 385 0 stevel */ 386 0 stevel if ((dirp = opendir(procdir)) == NULL) { 387 0 stevel (void) fprintf(stderr, "ps: cannot open PROC directory %s\n", 388 0 stevel procdir); 389 0 stevel exit(1); 390 0 stevel } 391 0 stevel 392 0 stevel (void) strcpy(psname, procdir); 393 0 stevel pdlen = strlen(psname); 394 0 stevel psname[pdlen++] = '/'; 395 0 stevel 396 0 stevel /* for each active process --- */ 397 0 stevel while (dentp = readdir(dirp)) { 398 0 stevel int psfd; /* file descriptor for /proc/nnnnn/psinfo */ 399 0 stevel int asfd; /* file descriptor for /proc/nnnnn/as */ 400 0 stevel 401 0 stevel if (dentp->d_name[0] == '.') /* skip . and .. */ 402 0 stevel continue; 403 0 stevel (void) strcpy(psname + pdlen, dentp->d_name); 404 0 stevel (void) strcpy(asname, psname); 405 0 stevel (void) strcat(psname, "/psinfo"); 406 0 stevel (void) strcat(asname, "/as"); 407 0 stevel retry: 408 0 stevel if ((psfd = open(psname, O_RDONLY)) == -1) 409 0 stevel continue; 410 0 stevel asfd = -1; 411 0 stevel if (psargs != NULL || eflg) { 412 0 stevel 413 0 stevel /* now we need the proc_owner privilege */ 414 0 stevel (void) __priv_bracket(PRIV_ON); 415 0 stevel 416 0 stevel asfd = open(asname, O_RDONLY); 417 0 stevel 418 0 stevel /* drop proc_owner privilege after open */ 419 0 stevel (void) __priv_bracket(PRIV_OFF); 420 0 stevel } 421 0 stevel 422 0 stevel /* 423 0 stevel * Get the info structure for the process 424 0 stevel */ 425 0 stevel if (read(psfd, &info, sizeof (info)) != sizeof (info)) { 426 0 stevel int saverr = errno; 427 0 stevel 428 0 stevel (void) close(psfd); 429 0 stevel if (asfd > 0) 430 0 stevel (void) close(asfd); 431 0 stevel if (saverr == EAGAIN) 432 0 stevel goto retry; 433 0 stevel if (saverr != ENOENT) 434 0 stevel (void) fprintf(stderr, "ps: read() on %s: %s\n", 435 0 stevel psname, err_string(saverr)); 436 0 stevel continue; 437 0 stevel } 438 0 stevel (void) close(psfd); 439 0 stevel 440 0 stevel found = 0; 441 0 stevel if (info.pr_lwp.pr_state == 0) /* can't happen? */ 442 0 stevel goto closeit; 443 0 stevel pid = info.pr_pid; 444 0 stevel ppid = info.pr_ppid; 445 0 stevel 446 0 stevel /* Display only process from command line */ 447 0 stevel if (pflg) { /* pid in arg list */ 448 0 stevel if (pidsave == pid) 449 0 stevel found++; 450 0 stevel else 451 0 stevel goto closeit; 452 0 stevel } 453 0 stevel 454 0 stevel /* 455 0 stevel * Omit "uninteresting" processes unless 'g' option. 456 0 stevel */ 457 0 stevel if ((ppid == 1) && !(gflg)) 458 0 stevel goto closeit; 459 0 stevel 460 0 stevel /* 461 0 stevel * Omit non-running processes for 'r' option 462 0 stevel */ 463 0 stevel if (rflg && 464 0 stevel !(info.pr_lwp.pr_sname == 'O' || 465 0 stevel info.pr_lwp.pr_sname == 'R')) 466 0 stevel goto closeit; 467 0 stevel 468 0 stevel if (!found && !tflg && !aflg && info.pr_euid != my_uid) 469 0 stevel goto closeit; 470 0 stevel 471 0 stevel /* 472 0 stevel * Read the args for the -w and -ww cases 473 0 stevel */ 474 0 stevel if (asfd > 0) { 475 0 stevel if ((psargs != NULL && 476 0 stevel preadargs(asfd, &info, psargs) == -1) || 477 0 stevel (eflg && preadenvs(asfd, &info, psargs) == -1)) { 478 0 stevel int saverr = errno; 479 0 stevel 480 0 stevel (void) close(asfd); 481 0 stevel if (saverr == EAGAIN) 482 0 stevel goto retry; 483 0 stevel if (saverr != ENOENT) 484 0 stevel (void) fprintf(stderr, 485 0 stevel "ps: read() on %s: %s\n", 486 0 stevel asname, err_string(saverr)); 487 0 stevel continue; 488 0 stevel } 489 0 stevel } else { 490 0 stevel psargs = info.pr_psargs; 491 0 stevel } 492 0 stevel 493 0 stevel if (nent >= entsize) { 494 0 stevel entsize *= 2; 495 0 stevel psent = (struct psent *)realloc((char *)psent, 496 8822 Casper entsize * sizeof (struct psent)); 497 0 stevel if (psent == NULL) { 498 0 stevel (void) fprintf(stderr, "ps: no memory\n"); 499 0 stevel exit(1); 500 0 stevel } 501 0 stevel } 502 0 stevel if ((psent[nent].psinfo = malloc(sizeof (psinfo_t))) 503 0 stevel == NULL) { 504 0 stevel (void) fprintf(stderr, "ps: no memory\n"); 505 0 stevel exit(1); 506 0 stevel } 507 0 stevel *psent[nent].psinfo = info; 508 0 stevel if (psargs == NULL) 509 0 stevel psent[nent].psargs = NULL; 510 0 stevel else { 511 0 stevel if ((psent[nent].psargs = malloc(strlen(psargs)+1)) 512 0 stevel == NULL) { 513 0 stevel (void) fprintf(stderr, "ps: no memory\n"); 514 0 stevel exit(1); 515 0 stevel } 516 0 stevel (void) strcpy(psent[nent].psargs, psargs); 517 0 stevel } 518 0 stevel psent[nent].found = found; 519 0 stevel nent++; 520 0 stevel closeit: 521 0 stevel if (asfd > 0) 522 0 stevel (void) close(asfd); 523 0 stevel psargs = svpsargs; 524 0 stevel } 525 0 stevel 526 0 stevel /* revert to non-privileged user */ 527 0 stevel (void) __priv_relinquish(); 528 0 stevel 529 0 stevel (void) closedir(dirp); 530 0 stevel 531 0 stevel qsort((char *)psent, nent, sizeof (psent[0]), pscompare); 532 0 stevel 533 0 stevel for (i = 0; i < nent; i++) { 534 0 stevel struct psent *pp = &psent[i]; 535 0 stevel if (prcom(pp->found, pp->psinfo, pp->psargs)) { 536 0 stevel (void) printf("\n"); 537 0 stevel retcode = 0; 538 0 stevel } 539 0 stevel } 540 0 stevel 541 0 stevel return (retcode); 542 0 stevel } 543 0 stevel 544 0 stevel static void 545 0 stevel usage() /* print usage message and quit */ 546 0 stevel { 547 0 stevel static char usage1[] = "ps [ -aceglnrSuUvwx ] [ -t term ] [ num ]"; 548 0 stevel 549 0 stevel (void) fprintf(stderr, "usage: %s\n", usage1); 550 0 stevel exit(1); 551 0 stevel } 552 0 stevel 553 0 stevel /* 554 0 stevel * Read the process arguments from the process. 555 0 stevel * This allows >PRARGSZ characters of arguments to be displayed but, 556 0 stevel * unlike pr_psargs[], the process may have changed them. 557 0 stevel */ 558 0 stevel #define NARG 100 559 0 stevel static int 560 0 stevel preadargs(int pfd, psinfo_t *psinfo, char *psargs) 561 0 stevel { 562 0 stevel off_t argvoff = (off_t)psinfo->pr_argv; 563 0 stevel size_t len; 564 0 stevel char *psa = psargs; 565 0 stevel int bsize = twidth; 566 0 stevel int narg = NARG; 567 0 stevel off_t argv[NARG]; 568 0 stevel off_t argoff; 569 0 stevel off_t nextargoff; 570 0 stevel int i; 571 0 stevel #ifdef _LP64 572 0 stevel caddr32_t argv32[NARG]; 573 0 stevel int is32 = (psinfo->pr_dmodel != PR_MODEL_LP64); 574 0 stevel #endif 575 0 stevel 576 0 stevel if (psinfo->pr_nlwp == 0 || 577 0 stevel strcmp(psinfo->pr_lwp.pr_clname, "SYS") == 0) 578 0 stevel goto out; 579 0 stevel 580 0 stevel (void) memset(psa, 0, bsize--); 581 0 stevel nextargoff = 0; 582 0 stevel errno = EIO; 583 0 stevel while (bsize > 0) { 584 0 stevel if (narg == NARG) { 585 0 stevel (void) memset(argv, 0, sizeof (argv)); 586 0 stevel #ifdef _LP64 587 0 stevel if (is32) { 588 0 stevel if ((i = pread(pfd, argv32, sizeof (argv32), 589 0 stevel argvoff)) <= 0) { 590 0 stevel if (i == 0 || errno == EIO) 591 0 stevel break; 592 0 stevel return (-1); 593 0 stevel } 594 0 stevel for (i = 0; i < NARG; i++) 595 0 stevel argv[i] = argv32[i]; 596 0 stevel } else 597 0 stevel #endif 598 0 stevel if ((i = pread(pfd, argv, sizeof (argv), 599 0 stevel argvoff)) <= 0) { 600 0 stevel if (i == 0 || errno == EIO) 601 0 stevel break; 602 0 stevel return (-1); 603 0 stevel } 604 0 stevel narg = 0; 605 0 stevel } 606 0 stevel if ((argoff = argv[narg++]) == 0) 607 0 stevel break; 608 0 stevel if (argoff != nextargoff && 609 0 stevel (i = pread(pfd, psa, bsize, argoff)) <= 0) { 610 0 stevel if (i == 0 || errno == EIO) 611 0 stevel break; 612 0 stevel return (-1); 613 0 stevel } 614 0 stevel len = strlen(psa); 615 0 stevel psa += len; 616 0 stevel *psa++ = ' '; 617 0 stevel bsize -= len + 1; 618 0 stevel nextargoff = argoff + len + 1; 619 0 stevel #ifdef _LP64 620 0 stevel argvoff += is32? sizeof (caddr32_t) : sizeof (caddr_t); 621 0 stevel #else 622 0 stevel argvoff += sizeof (caddr_t); 623 0 stevel #endif 624 0 stevel } 625 0 stevel while (psa > psargs && isspace(*(psa-1))) 626 0 stevel psa--; 627 0 stevel 628 0 stevel out: 629 0 stevel *psa = '\0'; 630 0 stevel if (strlen(psinfo->pr_psargs) > strlen(psargs)) 631 0 stevel (void) strcpy(psargs, psinfo->pr_psargs); 632 0 stevel 633 0 stevel return (0); 634 0 stevel } 635 0 stevel 636 0 stevel /* 637 0 stevel * Read environment variables from the process. 638 0 stevel * Append them to psargs if there is room. 639 0 stevel */ 640 0 stevel static int 641 0 stevel preadenvs(int pfd, psinfo_t *psinfo, char *psargs) 642 0 stevel { 643 0 stevel off_t envpoff = (off_t)psinfo->pr_envp; 644 0 stevel int len; 645 0 stevel char *psa; 646 0 stevel char *psainit; 647 0 stevel int bsize; 648 0 stevel int nenv = NARG; 649 0 stevel off_t envp[NARG]; 650 0 stevel off_t envoff; 651 0 stevel off_t nextenvoff; 652 0 stevel int i; 653 0 stevel #ifdef _LP64 654 0 stevel caddr32_t envp32[NARG]; 655 0 stevel int is32 = (psinfo->pr_dmodel != PR_MODEL_LP64); 656 0 stevel #endif 657 0 stevel 658 0 stevel psainit = psa = (psargs != NULL)? psargs : psinfo->pr_psargs; 659 0 stevel len = strlen(psa); 660 0 stevel psa += len; 661 0 stevel bsize = twidth - len - 1; 662 0 stevel 663 0 stevel if (bsize <= 0 || psinfo->pr_nlwp == 0 || 664 0 stevel strcmp(psinfo->pr_lwp.pr_clname, "SYS") == 0) 665 0 stevel return (0); 666 0 stevel 667 0 stevel nextenvoff = 0; 668 0 stevel errno = EIO; 669 0 stevel while (bsize > 0) { 670 0 stevel if (nenv == NARG) { 671 0 stevel (void) memset(envp, 0, sizeof (envp)); 672 0 stevel #ifdef _LP64 673 0 stevel if (is32) { 674 0 stevel if ((i = pread(pfd, envp32, sizeof (envp32), 675 0 stevel envpoff)) <= 0) { 676 0 stevel if (i == 0 || errno == EIO) 677 0 stevel break; 678 0 stevel return (-1); 679 0 stevel } 680 0 stevel for (i = 0; i < NARG; i++) 681 0 stevel envp[i] = envp32[i]; 682 0 stevel } else 683 0 stevel #endif 684 0 stevel if ((i = pread(pfd, envp, sizeof (envp), 685 0 stevel envpoff)) <= 0) { 686 0 stevel if (i == 0 || errno == EIO) 687 0 stevel break; 688 0 stevel return (-1); 689 0 stevel } 690 0 stevel nenv = 0; 691 0 stevel } 692 0 stevel if ((envoff = envp[nenv++]) == 0) 693 0 stevel break; 694 0 stevel if (envoff != nextenvoff && 695 0 stevel (i = pread(pfd, psa+1, bsize, envoff)) <= 0) { 696 0 stevel if (i == 0 || errno == EIO) 697 0 stevel break; 698 0 stevel return (-1); 699 0 stevel } 700 0 stevel *psa++ = ' '; 701 0 stevel len = strlen(psa); 702 0 stevel psa += len; 703 0 stevel bsize -= len + 1; 704 0 stevel nextenvoff = envoff + len + 1; 705 0 stevel #ifdef _LP64 706 0 stevel envpoff += is32? sizeof (caddr32_t) : sizeof (caddr_t); 707 0 stevel #else 708 0 stevel envpoff += sizeof (caddr_t); 709 0 stevel #endif 710 0 stevel } 711 0 stevel while (psa > psainit && isspace(*(psa-1))) 712 0 stevel psa--; 713 0 stevel *psa = '\0'; 714 0 stevel 715 0 stevel return (0); 716 0 stevel } 717 0 stevel 718 0 stevel /* 719 0 stevel * getarg() finds the next argument in list and copies arg into argbuf. 720 0 stevel * p1 first pts to arg passed back from getopt routine. p1 is then 721 0 stevel * bumped to next character that is not a comma or blank -- p1 NULL 722 0 stevel * indicates end of list. 723 0 stevel */ 724 0 stevel 725 0 stevel static void 726 0 stevel getarg() 727 0 stevel { 728 0 stevel char *parga; 729 0 stevel int c; 730 0 stevel 731 0 stevel while ((c = *p1) != '\0' && (c == ',' || isspace(c))) 732 0 stevel p1++; 733 0 stevel 734 0 stevel parga = argbuf; 735 0 stevel while ((c = *p1) != '\0' && c != ',' && !isspace(c)) { 736 0 stevel if (parga < argbuf + ARGSIZ - 1) 737 0 stevel *parga++ = c; 738 0 stevel p1++; 739 0 stevel } 740 0 stevel *parga = '\0'; 741 0 stevel 742 0 stevel while ((c = *p1) != '\0' && (c == ',' || isspace(c))) 743 0 stevel p1++; 744 0 stevel } 745 0 stevel 746 0 stevel static char * 747 0 stevel devlookup(dev_t ddev) 748 0 stevel { 749 0 stevel struct devl *dp; 750 0 stevel int i; 751 0 stevel 752 0 stevel for (dp = devl, i = 0; i < ndev; dp++, i++) { 753 0 stevel if (dp->ddev == ddev) 754 0 stevel return (dp->dname); 755 0 stevel } 756 0 stevel return (NULL); 757 0 stevel } 758 0 stevel 759 0 stevel static char * 760 0 stevel devadd(char *name, dev_t ddev) 761 0 stevel { 762 0 stevel struct devl *dp; 763 0 stevel int leng, start, i; 764 0 stevel 765 0 stevel if (ndev == maxdev) { 766 0 stevel maxdev += DNINCR; 767 0 stevel devl = realloc(devl, maxdev * sizeof (struct devl)); 768 0 stevel if (devl == NULL) { 769 0 stevel (void) fprintf(stderr, 770 0 stevel "ps: not enough memory for %d devices\n", maxdev); 771 0 stevel exit(1); 772 0 stevel } 773 0 stevel } 774 0 stevel dp = &devl[ndev++]; 775 0 stevel 776 0 stevel dp->ddev = ddev; 777 0 stevel if (name == NULL) { 778 0 stevel (void) strcpy(dp->dname, "??"); 779 0 stevel return (dp->dname); 780 0 stevel } 781 0 stevel 782 0 stevel leng = strlen(name); 783 0 stevel /* Strip off /dev/ */ 784 0 stevel if (leng < DNSIZE + 4) 785 0 stevel (void) strcpy(dp->dname, &name[5]); 786 0 stevel else { 787 0 stevel start = leng - (DNSIZE - 1); 788 0 stevel 789 0 stevel for (i = start; i < leng && name[i] != '/'; i++) 790 0 stevel ; 791 0 stevel if (i == leng) 792 0 stevel (void) strlcpy(dp->dname, &name[start], DNSIZE); 793 0 stevel else 794 0 stevel (void) strlcpy(dp->dname, &name[i+1], DNSIZE); 795 0 stevel } 796 0 stevel return (dp->dname); 797 0 stevel } 798 0 stevel 799 0 stevel /* 800 0 stevel * gettty returns the user's tty number or ? if none. 801 0 stevel */ 802 0 stevel static char * 803 0 stevel gettty(psinfo_t *psinfo) 804 0 stevel { 805 0 stevel extern char *_ttyname_dev(dev_t, char *, size_t); 806 0 stevel char devname[TTYNAME_MAX]; 807 0 stevel char *retval; 808 0 stevel 809 0 stevel if (psinfo->pr_ttydev == PRNODEV) 810 0 stevel return ("?"); 811 0 stevel 812 0 stevel if ((retval = devlookup(psinfo->pr_ttydev)) != NULL) 813 0 stevel return (retval); 814 0 stevel 815 0 stevel retval = _ttyname_dev(psinfo->pr_ttydev, devname, sizeof (devname)); 816 0 stevel 817 0 stevel return (devadd(retval, psinfo->pr_ttydev)); 818 0 stevel } 819 0 stevel 820 0 stevel /* 821 0 stevel * Print percent from 16-bit binary fraction [0 .. 1] 822 0 stevel * Round up .01 to .1 to indicate some small percentage (the 0x7000 below). 823 0 stevel */ 824 0 stevel static void 825 0 stevel prtpct(ushort_t pct) 826 0 stevel { 827 0 stevel uint_t value = pct; /* need 32 bits to compute with */ 828 0 stevel 829 0 stevel value = ((value * 1000) + 0x7000) >> 15; /* [0 .. 1000] */ 830 0 stevel (void) printf("%3u.%u", value / 10, value % 10); 831 0 stevel } 832 0 stevel 833 0 stevel /* 834 0 stevel * Print info about the process. 835 0 stevel */ 836 0 stevel static int 837 0 stevel prcom(int found, psinfo_t *psinfo, char *psargs) 838 0 stevel { 839 0 stevel char *cp; 840 0 stevel char *tp; 841 0 stevel char *psa; 842 0 stevel long tm; 843 0 stevel int i, wcnt, length; 844 0 stevel wchar_t wchar; 845 0 stevel struct tty *ttyp; 846 0 stevel 847 0 stevel /* 848 0 stevel * If process is zombie, call print routine and return. 849 0 stevel */ 850 0 stevel if (psinfo->pr_nlwp == 0) { 851 0 stevel if (tflg && !found) 852 0 stevel return (0); 853 0 stevel else { 854 0 stevel przom(psinfo); 855 0 stevel return (1); 856 0 stevel } 857 0 stevel } 858 0 stevel 859 0 stevel /* 860 0 stevel * Get current terminal. If none ("?") and 'a' is set, don't print 861 0 stevel * info. If 't' is set, check if term is in list of desired terminals 862 0 stevel * and print it if it is. 863 0 stevel */ 864 0 stevel i = 0; 865 0 stevel tp = gettty(psinfo); 866 0 stevel 867 0 stevel if (*tp == '?' && !found && !xflg) 868 0 stevel return (0); 869 0 stevel 870 0 stevel if (!(*tp == '?' && aflg) && tflg && !found) { 871 0 stevel int match = 0; 872 0 stevel char *other = NULL; 873 0 stevel for (ttyp = tty; ttyp->tname != NULL; ttyp++) { 874 0 stevel /* 875 0 stevel * Look for a name match 876 0 stevel */ 877 0 stevel if (strcmp(tp, ttyp->tname) == 0) { 878 0 stevel match = 1; 879 0 stevel break; 880 0 stevel } 881 0 stevel /* 882 0 stevel * Look for same device under different names. 883 0 stevel */ 884 0 stevel if ((other == NULL) && 885 0 stevel (psinfo->pr_ttydev == ttyp->tdev)) 886 0 stevel other = ttyp->tname; 887 0 stevel } 888 0 stevel if (!match) { 889 0 stevel if (other == NULL) 890 0 stevel return (0); 891 0 stevel tp = other; 892 0 stevel } 893 0 stevel } 894 0 stevel 895 0 stevel if (lflg) 896 0 stevel (void) printf("%2x", psinfo->pr_flag & 0377); 897 0 stevel if (uflg) { 898 0 stevel if (!nflg) { 899 0 stevel struct passwd *pwd; 900 0 stevel 901 0 stevel if ((pwd = getpwuid(psinfo->pr_euid)) != NULL) 902 0 stevel /* USER */ 903 0 stevel (void) printf("%-8.8s", pwd->pw_name); 904 0 stevel else 905 0 stevel /* UID */ 906 0 stevel (void) printf(" %7.7d", (int)psinfo->pr_euid); 907 0 stevel } else { 908 0 stevel (void) printf(" %5d", (int)psinfo->pr_euid); /* UID */ 909 0 stevel } 910 0 stevel } else if (lflg) 911 0 stevel (void) printf(" %5d", (int)psinfo->pr_euid); /* UID */ 912 0 stevel 913 0 stevel (void) printf("%*d", pidwidth + 1, (int)psinfo->pr_pid); /* PID */ 914 0 stevel if (lflg) 915 0 stevel (void) printf("%*d", pidwidth + 1, 916 0 stevel (int)psinfo->pr_ppid); /* PPID */ 917 0 stevel if (lflg) 918 0 stevel (void) printf("%3d", psinfo->pr_lwp.pr_cpu & 0377); /* CP */ 919 0 stevel if (uflg) { 920 0 stevel prtpct(psinfo->pr_pctcpu); /* %CPU */ 921 0 stevel prtpct(psinfo->pr_pctmem); /* %MEM */ 922 0 stevel } 923 0 stevel if (lflg) { 924 0 stevel (void) printf("%4d", psinfo->pr_lwp.pr_pri); /* PRI */ 925 0 stevel (void) printf("%3d", psinfo->pr_lwp.pr_nice); /* NICE */ 926 0 stevel } 927 0 stevel if (lflg || uflg) { 928 0 stevel if (psinfo->pr_flag & SSYS) /* SZ */ 929 0 stevel (void) printf(" 0"); 930 0 stevel else if (psinfo->pr_size) 931 0 stevel (void) printf("%5lu", (ulong_t)psinfo->pr_size); 932 0 stevel else 933 0 stevel (void) printf(" ?"); 934 0 stevel if (psinfo->pr_flag & SSYS) /* RSS */ 935 0 stevel (void) printf(" 0"); 936 0 stevel else if (psinfo->pr_rssize) 937 0 stevel (void) printf("%5lu", (ulong_t)psinfo->pr_rssize); 938 0 stevel else 939 0 stevel (void) printf(" ?"); 940 0 stevel } 941 0 stevel if (lflg) { /* WCHAN */ 942 0 stevel if (psinfo->pr_lwp.pr_sname != 'S') { 943 0 stevel (void) printf(" "); 944 0 stevel } else if (psinfo->pr_lwp.pr_wchan) { 945 0 stevel (void) printf(" %+8.8lx", 946 8822 Casper (ulong_t)psinfo->pr_lwp.pr_wchan); 947 0 stevel } else { 948 0 stevel (void) printf(" ?"); 949 0 stevel } 950 0 stevel } 951 0 stevel if ((tplen = strlen(tp)) > 9) 952 0 stevel maxlen = twidth - tplen + 9; 953 0 stevel else 954 0 stevel maxlen = twidth; 955 0 stevel 956 0 stevel if (!lflg) 957 0 stevel (void) printf(" %-8.14s", tp); /* TTY */ 958 0 stevel (void) printf(" %c", psinfo->pr_lwp.pr_sname); /* STATE */ 959 0 stevel if (lflg) 960 0 stevel (void) printf(" %-8.14s", tp); /* TTY */ 961 0 stevel if (uflg) 962 0 stevel prtime(psinfo->pr_start); /* START */ 963 0 stevel 964 0 stevel /* time just for process */ 965 0 stevel tm = psinfo->pr_time.tv_sec; 966 0 stevel if (Sflg) { /* calculate time for process and all reaped children */ 967 0 stevel tm += psinfo->pr_ctime.tv_sec; 968 0 stevel if (psinfo->pr_time.tv_nsec + psinfo->pr_ctime.tv_nsec 969 0 stevel >= 1000000000) 970 0 stevel tm += 1; 971 0 stevel } 972 0 stevel 973 0 stevel (void) printf(" %2ld:%.2ld", tm / 60, tm % 60); /* TIME */ 974 0 stevel 975 0 stevel if (vflg) { 976 0 stevel if (psinfo->pr_flag & SSYS) /* SZ */ 977 0 stevel (void) printf(" 0"); 978 0 stevel else if (psinfo->pr_size) 979 0 stevel (void) printf("%5lu", (ulong_t)psinfo->pr_size); 980 0 stevel else 981 0 stevel (void) printf(" ?"); 982 0 stevel if (psinfo->pr_flag & SSYS) /* SZ */ 983 0 stevel (void) printf(" 0"); 984 0 stevel else if (psinfo->pr_rssize) 985 0 stevel (void) printf("%5lu", (ulong_t)psinfo->pr_rssize); 986 0 stevel else 987 0 stevel (void) printf(" ?"); 988 0 stevel prtpct(psinfo->pr_pctcpu); /* %CPU */ 989 0 stevel prtpct(psinfo->pr_pctmem); /* %MEM */ 990 0 stevel } 991 0 stevel if (cflg) { /* CMD */ 992 0 stevel wcnt = namencnt(psinfo->pr_fname, 16, maxlen); 993 0 stevel (void) printf(" %.*s", wcnt, psinfo->pr_fname); 994 0 stevel return (1); 995 0 stevel } 996 0 stevel /* 997 0 stevel * PRARGSZ == length of cmd arg string. 998 0 stevel */ 999 0 stevel if (psargs == NULL) { 1000 0 stevel psa = &psinfo->pr_psargs[0]; 1001 0 stevel i = PRARGSZ; 1002 0 stevel tp = &psinfo->pr_psargs[PRARGSZ]; 1003 0 stevel } else { 1004 0 stevel psa = psargs; 1005 0 stevel i = strlen(psargs); 1006 0 stevel tp = psa + i; 1007 0 stevel } 1008 0 stevel 1009 0 stevel for (cp = psa; cp < tp; /* empty */) { 1010 0 stevel if (*cp == 0) 1011 0 stevel break; 1012 0 stevel length = mbtowc(&wchar, cp, MB_LEN_MAX); 1013 0 stevel if (length < 0 || !iswprint(wchar)) { 1014 0 stevel (void) printf(" [ %.16s ]", psinfo->pr_fname); 1015 0 stevel return (1); 1016 0 stevel } 1017 0 stevel cp += length; 1018 0 stevel } 1019 0 stevel wcnt = namencnt(psa, i, maxlen); 1020 0 stevel #if 0 1021 0 stevel /* dumps core on really long strings */ 1022 0 stevel (void) printf(" %.*s", wcnt, psa); 1023 0 stevel #else 1024 0 stevel (void) putchar(' '); 1025 0 stevel (void) fwrite(psa, 1, wcnt, stdout); 1026 0 stevel #endif 1027 0 stevel return (1); 1028 0 stevel } 1029 0 stevel 1030 0 stevel /* 1031 0 stevel * Print starting time of process unless process started more than 24 hours 1032 0 stevel * ago, in which case the date is printed. 1033 0 stevel */ 1034 0 stevel static void 1035 0 stevel prtime(timestruc_t st) 1036 0 stevel { 1037 0 stevel char sttim[26]; 1038 0 stevel static time_t tim = 0L; 1039 0 stevel time_t starttime; 1040 0 stevel 1041 0 stevel if (tim == 0L) 1042 0 stevel tim = time((time_t *)0); 1043 0 stevel starttime = st.tv_sec; 1044 0 stevel if (tim - starttime > 24*60*60) { 1045 0 stevel (void) strftime(sttim, sizeof (sttim), "%b %d", 1046 8822 Casper localtime(&starttime)); 1047 0 stevel } else { 1048 0 stevel (void) strftime(sttim, sizeof (sttim), "%H:%M:%S", 1049 8822 Casper localtime(&starttime)); 1050 0 stevel } 1051 0 stevel (void) printf("%9.9s", sttim); 1052 0 stevel } 1053 0 stevel 1054 0 stevel static void 1055 0 stevel przom(psinfo_t *psinfo) 1056 0 stevel { 1057 0 stevel long tm; 1058 0 stevel 1059 0 stevel if (lflg) 1060 0 stevel (void) printf("%2x", psinfo->pr_flag & 0377); 1061 0 stevel if (uflg) { 1062 0 stevel struct passwd *pwd; 1063 0 stevel 1064 0 stevel if ((pwd = getpwuid(psinfo->pr_euid)) != NULL) 1065 0 stevel (void) printf("%-8.8s", pwd->pw_name); /* USER */ 1066 0 stevel else 1067 0 stevel (void) printf(" %7.7d", (int)psinfo->pr_euid); /* UID */ 1068 0 stevel } else if (lflg) 1069 0 stevel (void) printf(" %5d", (int)psinfo->pr_euid); /* UID */ 1070 0 stevel 1071 0 stevel (void) printf("%*d", pidwidth + 1, (int)psinfo->pr_pid); /* PID */ 1072 0 stevel if (lflg) 1073 0 stevel (void) printf("%*d", pidwidth + 1, 1074 0 stevel (int)psinfo->pr_ppid); /* PPID */ 1075 0 stevel if (lflg) 1076 0 stevel (void) printf(" 0"); /* CP */ 1077 0 stevel if (uflg) { 1078 0 stevel prtpct(0); /* %CPU */ 1079 0 stevel prtpct(0); /* %MEM */ 1080 0 stevel } 1081 0 stevel if (lflg) { 1082 0 stevel (void) printf("%4d", psinfo->pr_lwp.pr_pri); /* PRI */ 1083 0 stevel (void) printf(" "); /* NICE */ 1084 0 stevel } 1085 0 stevel if (lflg || uflg) { 1086 0 stevel (void) printf(" 0"); /* SZ */ 1087 0 stevel (void) printf(" 0"); /* RSS */ 1088 0 stevel } 1089 0 stevel if (lflg) 1090 0 stevel (void) printf(" "); /* WCHAN */ 1091 0 stevel (void) printf(" "); /* TTY */ 1092 0 stevel (void) printf("%c", psinfo->pr_lwp.pr_sname); /* STATE */ 1093 0 stevel if (uflg) 1094 0 stevel (void) printf(" "); /* START */ 1095 0 stevel 1096 0 stevel /* time just for process */ 1097 0 stevel tm = psinfo->pr_time.tv_sec; 1098 0 stevel if (Sflg) { /* calculate time for process and all reaped children */ 1099 0 stevel tm += psinfo->pr_ctime.tv_sec; 1100 0 stevel if (psinfo->pr_time.tv_nsec + psinfo->pr_ctime.tv_nsec 1101 0 stevel >= 1000000000) 1102 0 stevel tm += 1; 1103 0 stevel } 1104 0 stevel (void) printf(" %2ld:%.2ld", tm / 60, tm % 60); /* TIME */ 1105 0 stevel 1106 0 stevel if (vflg) { 1107 0 stevel (void) printf(" 0"); /* SZ */ 1108 0 stevel (void) printf(" 0"); /* RSS */ 1109 0 stevel prtpct(0); /* %CPU */ 1110 0 stevel prtpct(0); /* %MEM */ 1111 0 stevel } 1112 0 stevel (void) printf(" %.*s", maxlen, " <defunct>"); 1113 0 stevel } 1114 0 stevel 1115 0 stevel /* 1116 0 stevel * Returns true iff string is all numeric. 1117 0 stevel */ 1118 0 stevel static int 1119 0 stevel num(char *s) 1120 0 stevel { 1121 0 stevel int c; 1122 0 stevel 1123 0 stevel if (s == NULL) 1124 0 stevel return (0); 1125 0 stevel c = *s; 1126 0 stevel do { 1127 0 stevel if (!isdigit(c)) 1128 0 stevel return (0); 1129 0 stevel } while ((c = *++s) != '\0'); 1130 0 stevel return (1); 1131 0 stevel } 1132 0 stevel 1133 0 stevel /* 1134 0 stevel * Function to compute the number of printable bytes in a multibyte 1135 0 stevel * command string ("internationalization"). 1136 0 stevel */ 1137 0 stevel static int 1138 0 stevel namencnt(char *cmd, int eucsize, int scrsize) 1139 0 stevel { 1140 0 stevel int eucwcnt = 0, scrwcnt = 0; 1141 0 stevel int neucsz, nscrsz; 1142 0 stevel wchar_t wchar; 1143 0 stevel 1144 0 stevel while (*cmd != '\0') { 1145 0 stevel if ((neucsz = mbtowc(&wchar, cmd, MB_LEN_MAX)) < 0) 1146 0 stevel return (8); /* default to use for illegal chars */ 1147 0 stevel if ((nscrsz = scrwidth(wchar)) == 0) 1148 0 stevel return (8); 1149 0 stevel if (eucwcnt + neucsz > eucsize || scrwcnt + nscrsz > scrsize) 1150 0 stevel break; 1151 0 stevel eucwcnt += neucsz; 1152 0 stevel scrwcnt += nscrsz; 1153 0 stevel cmd += neucsz; 1154 0 stevel } 1155 0 stevel return (eucwcnt); 1156 0 stevel } 1157 0 stevel 1158 0 stevel static int 1159 0 stevel pscompare(const void *v1, const void *v2) 1160 0 stevel { 1161 0 stevel const struct psent *p1 = v1; 1162 0 stevel const struct psent *p2 = v2; 1163 0 stevel int i; 1164 0 stevel 1165 0 stevel if (uflg) 1166 0 stevel i = p2->psinfo->pr_pctcpu - p1->psinfo->pr_pctcpu; 1167 0 stevel else if (vflg) 1168 0 stevel i = p2->psinfo->pr_rssize - p1->psinfo->pr_rssize; 1169 0 stevel else 1170 0 stevel i = p1->psinfo->pr_ttydev - p2->psinfo->pr_ttydev; 1171 0 stevel if (i == 0) 1172 0 stevel i = p1->psinfo->pr_pid - p2->psinfo->pr_pid; 1173 0 stevel return (i); 1174 0 stevel } 1175 0 stevel 1176 0 stevel static char * 1177 0 stevel err_string(int err) 1178 0 stevel { 1179 0 stevel static char buf[32]; 1180 0 stevel char *str = strerror(err); 1181 0 stevel 1182 0 stevel if (str == NULL) 1183 0 stevel (void) sprintf(str = buf, "Errno #%d", err); 1184 0 stevel 1185 0 stevel return (str); 1186 0 stevel } 1187