ps.c (114086B)
1 /* 2 * ps - process status 3 * 4 * Gunnar Ritter, Freiburg i. Br., Germany, August 2002. 5 */ 6 /* 7 * Copyright (c) 2003 Gunnar Ritter 8 * 9 * This software is provided 'as-is', without any express or implied 10 * warranty. In no event will the authors be held liable for any damages 11 * arising from the use of this software. 12 * 13 * Permission is granted to anyone to use this software for any purpose, 14 * including commercial applications, and to alter it and redistribute 15 * it freely, subject to the following restrictions: 16 * 17 * 1. The origin of this software must not be misrepresented; you must not 18 * claim that you wrote the original software. If you use this software 19 * in a product, an acknowledgment in the product documentation would be 20 * appreciated but is not required. 21 * 22 * 2. Altered source versions must be plainly marked as such, and must not be 23 * misrepresented as being the original software. 24 * 25 * 3. This notice may not be removed or altered from any source distribution. 26 */ 27 28 #if __GNUC__ >= 3 && __GNUC_MINOR__ >= 4 || __GNUC__ >= 4 29 #define USED __attribute__ ((used)) 30 #elif defined __GNUC__ 31 #define USED __attribute__ ((unused)) 32 #else 33 #define USED 34 #endif 35 #if defined (S42) 36 static const char sccsid[] USED = "@(#)ps_s42.sl 2.115 (gritter) 12/16/07"; 37 #elif defined (SUS) 38 static const char sccsid[] USED = "@(#)ps_sus.sl 2.115 (gritter) 12/16/07"; 39 #elif defined (UCB) 40 static const char sccsid[] USED = "@(#)/usr/ucb/ps.sl 2.115 (gritter) 12/16/07"; 41 #else 42 static const char sccsid[] USED = "@(#)ps.sl 2.115 (gritter) 12/16/07"; 43 #endif 44 45 static const char cacheid[] = "@(#)/tmp/ps_cache 2.115 (gritter) 12/16/07"; 46 47 #if !defined (__linux__) && !defined (__sun) && !defined (__FreeBSD__) \ 48 && !defined (__DragonFly__) 49 #define _KMEMUSER 50 #endif /* !__linux__, !__sun, !__FreeBSD__, !__DragonFly__ */ 51 #include <sys/types.h> 52 #include <sys/stat.h> 53 #include <sys/utsname.h> 54 #ifdef __GLIBC__ 55 #include <sys/sysmacros.h> 56 #endif 57 #include <fcntl.h> 58 #include <time.h> 59 #include <unistd.h> 60 #include <stdio.h> 61 #include <string.h> 62 #include <stdlib.h> 63 #include <errno.h> 64 #include <libgen.h> 65 #include <alloca.h> 66 #include <dirent.h> 67 #include <limits.h> 68 #include <sched.h> 69 #include <pwd.h> 70 #include <grp.h> 71 #include <langinfo.h> 72 #include <locale.h> 73 #include <ctype.h> 74 #include <blank.h> 75 #include <inttypes.h> 76 #include <termios.h> 77 #if defined (__linux__) 78 #include <mntent.h> 79 #elif defined (__FreeBSD__) || defined (__DragonFly__) 80 #include <kvm.h> 81 #include <sys/param.h> 82 #include <sys/ucred.h> 83 #include <sys/mount.h> 84 #include <sys/time.h> 85 #include <sys/resource.h> 86 #include <sys/sysctl.h> 87 #include <sys/user.h> 88 #define proc process 89 #undef p_pgid 90 #undef p_pctcpu 91 #if defined (__DragonFly__) 92 #endif /* __DragonFly__ */ 93 #elif defined (__hpux) 94 #include <mntent.h> 95 #include <sys/param.h> 96 #include <sys/pstat.h> 97 #elif defined (_AIX) 98 #include <mntent.h> 99 #include <procinfo.h> 100 #define proc process 101 #ifndef MNTTYPE_IGNORE 102 #define MNTTYPE_IGNORE "" 103 #endif 104 #elif defined (__NetBSD__) || defined (__OpenBSD__) 105 #include <kvm.h> 106 #include <sys/param.h> 107 #include <sys/sysctl.h> 108 #include <sys/mount.h> 109 #define proc process 110 #undef p_pgid 111 #if !defined (SRUN) && defined (LSRUN) 112 #define SRUN LSRUN 113 #endif 114 #if !defined (SSLEEP) && defined (LSSLEEP) 115 #define SSLEEP LSSLEEP 116 #endif 117 #if !defined (SDEAD) && defined (LSDEAD) 118 #define SDEAD LSDEAD 119 #endif 120 #if !defined (SONPROC) && defined (LSONPROC) 121 #define SONPROC LSONPROC 122 #endif 123 #if !defined (P_INMEM) && defined (L_INMEM) 124 #define P_INMEM L_INMEM 125 #endif 126 #if !defined (P_SINTR) && defined (L_SINTR) 127 #define P_SINTR L_SINTR 128 #endif 129 #ifndef SCHED_OTHER 130 #define SCHED_OTHER 1 131 #endif 132 #elif defined (__APPLE__) 133 #include <sys/time.h> 134 #include <sys/proc.h> 135 #include <sys/sysctl.h> 136 #include <sys/mount.h> 137 #include <sys/resource.h> 138 #include <mach/mach_types.h> 139 #include <mach/task_info.h> 140 #include <mach/shared_memory_server.h> 141 #define proc process 142 #undef p_pgid 143 #else /* SVR4 */ 144 #include <sys/mnttab.h> 145 #ifdef __sun 146 #define _STRUCTURED_PROC 1 147 #endif /* __sun */ 148 #include <sys/procfs.h> 149 #include <sys/proc.h> 150 #undef p_pid 151 #undef p_wchan 152 #define proc process 153 #endif /* SVR4 */ 154 #include <wchar.h> 155 #include <wctype.h> 156 #ifndef TIOCGWINSZ 157 #include <sys/ioctl.h> 158 #endif 159 160 #if __NetBSD_Version__ >= 300000000 161 #include <sys/statvfs.h> 162 #define statfs statvfs 163 #endif 164 165 #include <mbtowi.h> 166 167 #ifdef __linux__ 168 #ifndef SCHED_BATCH 169 #define SCHED_BATCH 3 170 #endif 171 #ifndef SCHED_ISO 172 #define SCHED_ISO 4 173 #endif 174 #endif /* __linux__ */ 175 176 #define PROCDIR "/proc" 177 #ifndef UCB 178 #define DEFUNCT "<defunct>" 179 #else /* UCB */ 180 #define DEFUNCT " <defunct>" 181 #endif /* UCB */ 182 #ifndef PRNODEV 183 #define PRNODEV 0 184 #endif /* !PRNODEV */ 185 #define eq(a, b) (strcmp(a, b) == 0) 186 187 #ifdef __GLIBC__ 188 #ifdef _IO_getc_unlocked 189 #undef getc 190 #define getc(f) _IO_getc_unlocked(f) 191 #endif /* _IO_getc_unlocked */ 192 #ifdef _IO_putc_unlocked 193 #undef putchar 194 #define putchar(c) _IO_putc_unlocked(c, stdout) 195 #endif /* _IO_putc_unlocked */ 196 #endif /* __GLIBC__ */ 197 198 #define next(wc, s, n) (mb_cur_max > 1 && *(s) & 0200 ? \ 199 ((n) = mbtowi(&(wc), (s), mb_cur_max), \ 200 (n) = ((n) > 0 ? (n) : (n) < 0 ? (wc=WEOF, 1) : 1)) :\ 201 ((wc) = *(s) & 0377, (n) = 1)) 202 203 #ifndef _AIX 204 typedef uint32_t dev_type; 205 #else 206 typedef uint64_t dev_type; 207 #endif 208 209 enum okay { 210 OKAY, 211 STOP 212 }; 213 214 enum crtype { 215 CR_ALL, /* -e, -A */ 216 CR_ALL_WITH_TTY, /* -a */ 217 CR_ALL_BUT_SESSION_LEADERS, /* -d */ 218 CR_WITHOUT_TTY, /* UCB -gx */ 219 CR_NO_TTY_NO_SESSION_LEADER, /* UCB -x */ 220 CR_PROCESS_GROUP, /* traditional -g ... */ 221 CR_REAL_GID, /* -G ... */ 222 CR_PROCESS_ID, /* -p ... */ 223 CR_TTY_DEVICE, /* -t ... */ 224 CR_SESSION_LEADER, /* -s ..., SUS -g ... */ 225 CR_EFF_UID, /* SUS -u ... */ 226 CR_REAL_UID, /* -U ..., traditional -u ... */ 227 CR_ADD_UNINTERESTING, /* UCB -g */ 228 CR_INVALID_EFF_UID, /* invalid eff. uid but look for more */ 229 CR_INVALID_REAL_UID, /* invalid real uid but look for more */ 230 CR_INVALID_REAL_GID, /* invalid group but look for more */ 231 CR_INVALID_TTY_DEVICE, /* invalid tty, ignore */ 232 CR_INVALID_STOP, /* invalid criterion but stop later */ 233 CR_DEFAULT 234 }; 235 236 enum outype { 237 OU_USER, 238 OU_RUSER, 239 OU_GROUP, 240 OU_RGROUP, 241 OU_PID, 242 OU_PPID, 243 OU_PGID, 244 OU_PCPU, 245 OU_VSZ, 246 OU_NICE, 247 OU_ETIME, 248 OU_OTIME, 249 OU_TIME, 250 OU_ACCUTIME, 251 OU_TTY, 252 OU_COMM, 253 OU_ARGS, 254 OU_F, 255 OU_S, 256 OU_C, 257 OU_UID, 258 OU_RUID, 259 OU_GID, 260 OU_RGID, 261 OU_SID, 262 OU_CLASS, 263 OU_PRI, 264 OU_OPRI, 265 OU_PSR, 266 OU_ADDR, 267 OU_OSZ, 268 OU_WCHAN, 269 OU_STIME, 270 OU_RSS, 271 OU_ORSS, 272 OU_PMEM, 273 OU_FNAME, 274 OU_LWP, 275 OU_NLWP, 276 OU_LTIME, 277 OU_STID, 278 OU_TID, 279 OU_NTP, 280 OU_MRSZ, 281 OU_PFLTS, 282 OU_BUFR, 283 OU_BUFW, 284 OU_MRCV, 285 OU_MSND, 286 OU_UTIME, 287 OU_KTIME, 288 OU_SPACE 289 }; 290 291 enum { 292 FL_LOAD = 001, 293 FL_SYS = 002, 294 FL_LOCK = 004, 295 FL_SWAP = 010, 296 FL_TRC = 020, 297 FL_WTED = 040 298 }; 299 300 enum valtype { 301 VT_CHAR, 302 VT_INT, 303 VT_UINT, 304 VT_LONG, 305 VT_ULONG 306 }; 307 308 union value { 309 char v_char; 310 int v_int; 311 unsigned int v_uint; 312 long v_long; 313 unsigned long v_ulong; 314 }; 315 316 struct trenod { 317 struct trenod *t_lln; 318 struct trenod *t_rln; 319 char *t_str; 320 unsigned long t_num; 321 }; 322 323 struct ditem { 324 struct ditem *d_lnk; 325 char *d_str; 326 dev_type d_rdev; 327 }; 328 329 struct criterion { 330 struct criterion *c_nxt; 331 enum crtype c_typ; 332 unsigned long c_val; 333 }; 334 335 struct output { 336 struct output *o_nxt; 337 enum outype o_typ; 338 char *o_nam; 339 int o_len; 340 }; 341 342 static const struct { 343 enum outype os_typ; 344 char *os_fmt; 345 char *os_def; 346 enum { 347 OS_Lflag = 01 348 } os_flags; 349 } outspec[] = { 350 { OU_USER, "user", " USER", 0 }, 351 { OU_RUSER, "ruser", " RUSER", 0 }, 352 { OU_GROUP, "group", " GROUP", 0 }, 353 { OU_RGROUP, "rgroup", " RGROUP", 0 }, 354 { OU_PID, "pid", " PID", 0 }, 355 { OU_PPID, "ppid", " PPID", 0 }, 356 { OU_PGID, "pgid", " PGID", 0 }, 357 { OU_PCPU, "pcpu", "%CPU", 0 }, 358 { OU_VSZ, "vsz", " VSZ", 0 }, 359 { OU_NICE, "nice", "NI", 0 }, 360 { OU_ETIME, "etime", " ELAPSED", 0 }, 361 { OU_TIME, "time", " TIME", 0 }, 362 { OU_ACCUTIME, "accutime", " TIME", 0 }, 363 { OU_OTIME, "otime", " TIME", 0 }, 364 { OU_TTY, "tty", "TT ", 0 }, 365 { OU_COMM, "comm", "COMMAND", 0 }, 366 { OU_ARGS, "args", "COMMAND", 0 }, 367 { OU_F, "f", " F", 0 }, 368 { OU_S, "s", "S", 0 }, 369 { OU_C, "c", " C", 0 }, 370 { OU_UID, "uid", " UID", 0 }, 371 { OU_RUID, "ruid", " RUID", 0 }, 372 { OU_GID, "gid", " GID", 0 }, 373 { OU_RGID, "rgid", " RGID", 0 }, 374 { OU_SID, "sid", " SID", 0 }, 375 { OU_CLASS, "class", " CLS", 0 }, 376 { OU_PRI, "pri", "PRI", 0 }, 377 { OU_OPRI, "opri", "PRI", 0 }, 378 { OU_PSR, "psr", "PSR", 0 }, 379 { OU_ADDR, "addr", " ADDR", 0 }, 380 { OU_OSZ, "osz", " SZ", 0 }, 381 { OU_WCHAN, "wchan", " WCHAN", 0 }, 382 { OU_STIME, "stime", " STIME", 0 }, 383 { OU_RSS, "rss", " RSS", 0 }, 384 { OU_ORSS, "orss", " RSS", 0 }, 385 { OU_PMEM, "pmem", "%MEM", 0 }, 386 { OU_FNAME, "fname", "COMMAND", 0 }, 387 { OU_LWP, "lwp", " LWP", OS_Lflag }, 388 { OU_NLWP, "nlwp", " NLWP", 0 }, 389 { OU_LTIME, "ltime", "LTIME", OS_Lflag }, 390 { OU_STID, "stid", " STID", OS_Lflag }, 391 { OU_TID, "tid", "TID", OS_Lflag }, 392 { OU_NTP, "ntp", "NTP", 0 }, 393 { OU_MRSZ, "mrsz", " MRSZ", 0 }, 394 { OU_PFLTS, "pflts", "PFLTS", 0 }, 395 { OU_BUFR, "bufr", " BUFR", 0 }, 396 { OU_BUFW, "bufw", " BUFW", 0 }, 397 { OU_MRCV, "mrcv", " MRCV", 0 }, 398 { OU_MSND, "msnd", " MSND", 0 }, 399 { OU_UTIME, "utime", " UTIME", 0 }, 400 { OU_KTIME, "ktime", " KTIME", 0 }, 401 { OU_SPACE, NULL, " ", 0 } 402 }; 403 404 struct proc { 405 pid_t p_pid; /* process id */ 406 char p_fname[19]; /* executable name */ 407 char p_state[2]; /* process state */ 408 char p_lstate[2]; /* linux state */ 409 pid_t p_ppid; /* parent process id */ 410 pid_t p_pgid; /* process group */ 411 pid_t p_sid; /* session */ 412 pid_t p_lwp; /* LWP id */ 413 dev_type p_ttydev; /* tty device */ 414 unsigned long p_flag; /* process flags */ 415 unsigned long p_lflag; /* linux flags */ 416 time_t p_time; /* cpu time */ 417 time_t p_accutime; /* accumulated cpu time */ 418 time_t p_utime; /* user time */ 419 time_t p_ktime; /* kernel time */ 420 long p_intpri; /* priority value from /proc */ 421 long p_rtpri; /* rt_priority value from /proc */ 422 long p_policy; /* scheduling policy */ 423 int p_c; /* cpu usage for scheduling */ 424 int p_oldpri; /* old priority */ 425 int p_pri; /* new priority */ 426 int p_nice; /* nice value */ 427 int p_nlwp; /* number of LWPs */ 428 time_t p_start; /* start time */ 429 unsigned long p_size; /* size in kilobytes */ 430 unsigned long p_osz; /* size in pages */ 431 unsigned long p_rssize; /* rss size in kbytes */ 432 unsigned long p_orss; /* rss size in pages */ 433 unsigned long p_pflts; /* page faults */ 434 unsigned long p_bufr; /* buffer reads */ 435 unsigned long p_bufw; /* buffer writes */ 436 unsigned long p_mrcv; /* messages received */ 437 unsigned long p_msnd; /* messages sent */ 438 unsigned long p_addr; /* address */ 439 unsigned long p_wchan; /* wait channel */ 440 int p_psr; /* processor */ 441 double p_pctcpu; /* cpu percent */ 442 double p_pctmem; /* mem percent */ 443 char *p_clname; /* scheduling class */ 444 char p_comm[80]; /* first argument */ 445 char p_psargs[80]; /* process arguments */ 446 uid_t p_uid; /* real uid */ 447 uid_t p_euid; /* effective uid */ 448 gid_t p_gid; /* real gid */ 449 gid_t p_egid; /* effective gid */ 450 }; 451 452 static unsigned errcnt; /* count of errors */ 453 static int Lflag; /* show LWPs */ 454 static int oflag; /* had -o switch */ 455 static const char *rflag; /* change root directory */ 456 static int ucb_rflag; /* running processes only */ 457 static int dohdr; /* output header */ 458 #undef hz 459 static long hz; /* clock ticks per second */ 460 static time_t now; /* current time */ 461 #ifdef __linux__ 462 static time_t uptime; 463 #endif /* __linux__ */ 464 #ifndef __sun 465 static unsigned long totalmem; 466 #endif /* !__sun */ 467 static unsigned long kbytes_per_page; 468 static unsigned long pagesize; 469 static uid_t myuid; /* real uid of ps */ 470 static uid_t myeuid; /* effective uid of ps */ 471 static int sched_selection; 472 static int maxcolumn; /* maximum terminal size */ 473 static int mb_cur_max; /* MB_CUR_MAX acceleration */ 474 static int ontty; /* running on a tty */ 475 static char *progname; /* argv[0] to main() */ 476 static struct proc myproc; /* struct proc for this ps instance */ 477 478 static struct ditem **d0; /* dev_t to device name mapping */ 479 static struct criterion *c0; /* criteria list */ 480 static struct output *o0; /* output field list */ 481 482 #ifdef __linux__ 483 static int linux_version[3] = { 2, 4, 0 }; 484 #endif /* !__linux__ */ 485 486 #ifdef USE_PS_CACHE 487 static FILE *devfp; 488 static char *ps_cache_file = "/tmp/ps_cache"; 489 static mode_t ps_cache_mode = 0664; 490 static gid_t ps_cache_gid = 3; 491 #endif /* USE_PS_CACHE */ 492 static int dropprivs; 493 494 static void postproc(struct proc *); 495 static enum okay selectproc(struct proc *); 496 497 /************************************************************************ 498 * Utility functions * 499 ************************************************************************/ 500 501 static void * 502 srealloc(void *vp, size_t nbytes) 503 { 504 void *p; 505 506 if ((p = realloc(vp, nbytes)) == NULL) { 507 write(2, "no memory\n", 10); 508 exit(077); 509 } 510 return p; 511 } 512 513 static void * 514 smalloc(size_t nbytes) 515 { 516 return srealloc(NULL, nbytes); 517 } 518 519 static char * 520 sstrdup(const char *op) 521 { 522 char *np; 523 524 np = smalloc(strlen(op) + 1); 525 strcpy(np, op); 526 return np; 527 } 528 529 static void * 530 scalloc(size_t nmemb, size_t size) 531 { 532 void *p; 533 534 if ((p = (void *)calloc(nmemb, size)) == NULL) { 535 write(2, "no memory\n", 10); 536 exit(077); 537 } 538 return p; 539 } 540 541 static FILE * 542 wopen(const char *fn) 543 { 544 int fd; 545 char *tl, *dn, *fc; 546 547 dn = dirname(fc = sstrdup(fn)); 548 tl = smalloc(strlen(dn) + 10); 549 strcpy(tl, dn); 550 strcat(tl, "/psXXXXXX"); 551 free(fc); 552 if ((fd = mkstemp(tl)) < 0) 553 return NULL; 554 if (rename(tl, fn) < 0) { 555 unlink(tl); 556 free(tl); 557 close(fd); 558 return NULL; 559 } 560 free(tl); 561 return fdopen(fd, "w"); 562 } 563 564 static struct trenod * 565 treget(unsigned long num, struct trenod **troot) 566 { 567 long long c; 568 struct trenod *tp = *troot; 569 570 while (tp != NULL) { 571 if ((c = num - tp->t_num) == 0) 572 break; 573 else if (c < 0) 574 tp = tp->t_lln; 575 else 576 tp = tp->t_rln; 577 } 578 return tp; 579 } 580 581 static void 582 treput(struct trenod *tk, struct trenod **troot) 583 { 584 if (*troot) { 585 long long c; 586 struct trenod *tp = *troot, *tq = NULL; 587 588 while (tp != NULL) { 589 tq = tp; 590 if ((c = tk->t_num - tp->t_num) == 0) 591 return; 592 else if (c < 0) 593 tp = tp->t_lln; 594 else 595 tp = tp->t_rln; 596 } 597 if (tq != NULL) { 598 if ((c = tk->t_num - tq->t_num) < 0) 599 tq->t_lln = tk; 600 else 601 tq->t_rln = tk; 602 } 603 } else 604 *troot = tk; 605 } 606 607 #define dhash(c) ((uint32_t)(2654435769U * (uint32_t)(c) >> 24)) 608 609 static struct ditem * 610 dlook(dev_type rdev, struct ditem **dt, char *str) 611 { 612 struct ditem *dp; 613 int h; 614 615 dp = dt[h = dhash(rdev)]; 616 while (dp != NULL) { 617 if (dp->d_rdev == rdev) 618 break; 619 dp = dp->d_lnk; 620 } 621 if (str != NULL && dp == NULL) { 622 dp = scalloc(1, sizeof *dp); 623 dp->d_rdev = rdev; 624 dp->d_str = str; 625 dp->d_lnk = dt[h]; 626 dt[h] = dp; 627 } 628 return dp; 629 } 630 631 #if !defined (__hpux) && !defined (_AIX) && !defined (__NetBSD__) && \ 632 !defined (__OpenBSD__) && !defined (__APPLE__) 633 static void 634 chdir_to_proc(void) 635 { 636 static int fd = -1; 637 638 if (fd == -1 && (fd = open(PROCDIR, O_RDONLY)) < 0) { 639 fprintf(stderr, "%s: cannot open %s\n", progname, PROCDIR); 640 exit(075); 641 } 642 if (fchdir(fd) < 0) { 643 fprintf(stderr, "%s: cannot chdir to %s\n", progname, PROCDIR); 644 exit(074); 645 } 646 } 647 #endif /* !__hpux, !_AIX, !__NetBSD__, !__OpenBSD__, !__APPLE__ */ 648 649 static union value * 650 getval(char **listp, enum valtype type, int separator, int sep2) 651 { 652 char *buf; 653 static union value v; 654 const char *cp, *op; 655 char *cq, *x; 656 657 if (**listp == '\0') 658 return NULL; 659 op = *listp; 660 while (**listp != '\0') { 661 if ((separator == ' ' ? isspace(**listp) : **listp == separator) 662 || **listp == sep2) 663 break; 664 (*listp)++; 665 } 666 buf = alloca(*listp - op + 1); 667 for (cp = op, cq = buf; cp < *listp; cp++, cq++) 668 *cq = *cp; 669 *cq = '\0'; 670 if (**listp) { 671 while ((separator == ' ' ? 672 isspace(**listp) : **listp == separator) || 673 **listp == sep2) 674 (*listp)++; 675 } 676 switch (type) { 677 case VT_CHAR: 678 if (buf[1] != '\0') 679 return NULL; 680 v.v_char = buf[0]; 681 break; 682 case VT_INT: 683 v.v_int = strtol(buf, &x, 10); 684 if (*x != '\0') 685 return NULL; 686 break; 687 case VT_UINT: 688 v.v_uint = strtoul(buf, &x, 10); 689 if (*x != '\0') 690 return NULL; 691 break; 692 case VT_LONG: 693 v.v_long = strtol(buf, &x, 10); 694 if (*x != '\0') 695 return NULL; 696 break; 697 case VT_ULONG: 698 v.v_ulong = strtoul(buf, &x, 10); 699 if (*x != '\0') 700 return NULL; 701 break; 702 } 703 return &v; 704 } 705 706 #ifdef __linux__ 707 static int 708 linux_version_lt(int version, int patchlevel, int sublevel) 709 { 710 if (linux_version[0] < version) 711 return 1; 712 if (linux_version[0] == version) { 713 if (linux_version[1] < patchlevel) 714 return 1; 715 if (patchlevel == linux_version[1] && 716 linux_version[2] < sublevel) 717 return 1; 718 } 719 return 0; 720 } 721 722 static int 723 has_o1_sched(void) 724 { 725 struct stat st; 726 727 if (sched_selection) 728 return sched_selection > 0; 729 return stat("/proc/sys/sched", &st) == 0; 730 } 731 #endif /* __linux__ */ 732 733 static int 734 hasnonprint(const char *s) 735 { 736 wint_t wc; 737 int n; 738 739 while (*s) { 740 next(wc, s, n); 741 if (mb_cur_max > 1 ? !iswprint(wc) : !isprint(wc)) 742 return 1; 743 s += n; 744 } 745 return 0; 746 } 747 748 static int 749 colwidth(const char *s) 750 { 751 wint_t wc; 752 int i, n, w = 0; 753 754 while (*s) { 755 next(wc, s, n); 756 s += n; 757 if (mb_cur_max > 1) 758 i = iswprint(wc) ? wcwidth(wc) : 0; 759 else 760 i = isprint(wc) != 0; 761 w += i; 762 } 763 return w; 764 } 765 766 static void 767 cleanline(struct proc *p) 768 { 769 /* 770 * If the argument list contains a nonprintable character, 771 * replace it with the file name even if output is not a 772 * terminal. 773 */ 774 if (*p->p_psargs == '\0' || hasnonprint(p->p_psargs)) { 775 if (p->p_size == 0 && *p->p_psargs == '\0') 776 strcpy(p->p_psargs, p->p_fname); 777 else 778 snprintf(p->p_psargs, sizeof p->p_psargs, "[ %.8s ]", 779 p->p_fname); 780 strcpy(p->p_comm, p->p_psargs); 781 } 782 } 783 784 /************************************************************************ 785 * Execution * 786 ************************************************************************/ 787 788 static void 789 putheader(void) 790 { 791 struct output *o; 792 unsigned i; 793 794 for (o = o0; o; o = o->o_nxt) { 795 if (*o->o_nam == '\0') { 796 for (i = 0; i < o->o_len; i++) 797 putchar(' '); 798 } else 799 fputs(o->o_nam, stdout); 800 if (o->o_nxt && o->o_typ != OU_SPACE) 801 putchar(' '); 802 } 803 putchar('\n'); 804 } 805 806 /* 807 * Print a string, not exceeding the maximum output width, but with at least 808 * minimum columns. Drop nonprintable characters if printing to a terminal. 809 */ 810 static int 811 putstr(int width, int minimum, int maximum, const char *s) 812 { 813 wint_t wc; 814 int written = 0, n, cw; 815 816 while (next(wc, s, n), cw = wcwidth(wc), cw = cw >= 0 ? cw : 1, 817 wc != '\0' && 818 (maxcolumn == 0 || width + cw <= maxcolumn) && 819 (maximum == 0 || written + cw <= maximum)) { 820 if (!ontty || (mb_cur_max > 1 ? iswprint(wc) : isprint(wc))) { 821 while (n--) { 822 putchar(*s); 823 s++; 824 } 825 written += cw; 826 width += cw; 827 } else 828 s += n; 829 } 830 while ((maxcolumn == 0 || width < maxcolumn) && written < minimum && 831 (maximum == 0 || written < maximum)) { 832 putchar(' '); 833 written++; 834 } 835 return written; 836 } 837 838 /* 839 * Print a hexadecimal value with a maximum width, preceded by spaces 840 * if it is short. 841 * 842 * This is used for ADDR and WCHAN. Truncating the addresses to keep 843 * the display columns in order makes sense here since ADDR serves no 844 * known purpose anymore, and for WCHAN only the lower part of the 845 * address is relevant. 846 */ 847 static int 848 putxd(int width, unsigned long val) 849 { 850 const char digits[] = "0123456789abcdef"; 851 char *buf = alloca(width); 852 int m, n = width; 853 854 do { 855 buf[--n] = digits[val & 0xf]; 856 val >>= 4; 857 } while (val != 0 && n > 0); 858 for (m = 0; m < n; m++) 859 putchar(' '); 860 do 861 putchar(buf[n]); 862 while (++n < width); 863 return width; 864 } 865 866 static int 867 putid(unsigned long val, unsigned len, struct trenod **troot, 868 char *(*func)(unsigned long)) 869 { 870 struct trenod *tp; 871 char *str; 872 873 if ((tp = treget(val, troot)) == NULL) { 874 if ((str = func(val)) != NULL) { 875 tp = scalloc(1, sizeof *tp); 876 tp->t_str = smalloc(strlen(str) + 1); 877 strcpy(tp->t_str, str); 878 tp->t_num = val; 879 treput(tp, troot); 880 } else 881 numeric: 882 #ifdef UCB 883 return printf("%-*lu", len, val); 884 #else 885 return printf("%*lu", len, val); 886 #endif 887 } 888 if (oflag && colwidth(tp->t_str) > len) 889 goto numeric; 890 #ifdef UCB 891 return printf("%-*s", len, tp->t_str); 892 #else 893 return printf("%*s", len, tp->t_str); 894 #endif 895 } 896 897 static char * 898 get_username_from_pwd(unsigned long uid) 899 { 900 struct passwd *pwd; 901 902 if ((pwd = getpwuid(uid)) != NULL) 903 return pwd->pw_name; 904 return NULL; 905 } 906 907 static char * 908 get_groupname_from_grp(unsigned long gid) 909 { 910 struct group *grp; 911 912 if ((grp = getgrgid(gid)) != NULL) 913 return grp->gr_name; 914 return NULL; 915 } 916 917 static int 918 putuser(uid_t uid, unsigned len) 919 { 920 static struct trenod *u0; 921 922 return putid(uid, len, &u0, get_username_from_pwd); 923 } 924 925 static int 926 putgroup(gid_t gid, unsigned len) 927 { 928 static struct trenod *g0; 929 930 return putid(gid, len, &g0, get_groupname_from_grp); 931 } 932 933 static int 934 putdev(dev_type dev, unsigned len) 935 { 936 struct ditem *d; 937 char *nam; 938 939 if (dev != (dev_type)PRNODEV) { 940 if ((d = dlook(dev, d0, NULL)) != NULL) 941 nam = d->d_str; 942 else 943 nam = "??"; 944 } else 945 nam = "?"; 946 return printf("%-*s", len, nam); 947 } 948 949 static int 950 time2(long t, unsigned len, int format) 951 { 952 char buf[40]; 953 int days, hours, minutes, seconds; 954 955 if (t < 0) 956 t = 0; 957 if (format == 2) 958 snprintf(buf, sizeof buf, "%2lu:%02lu.%ld", t / 600, 959 (t/10) % 60, 960 t % 10); 961 else if (format == 1) 962 snprintf(buf, sizeof buf, "%2lu:%02lu", t / 60, t % 60); 963 else { 964 days = t / 86400; 965 t %= 86400; 966 hours = t / 3600; 967 t %= 3600; 968 minutes = t / 60; 969 t %= 60; 970 seconds = t; 971 if (days) 972 snprintf(buf, sizeof buf, "%02u-:%02u:%02u:%02u", 973 days, hours, minutes, seconds); 974 else 975 snprintf(buf, sizeof buf, "%02u:%02u:%02u", 976 hours, minutes, seconds); 977 } 978 return printf("%*s", len, buf); 979 } 980 981 static int 982 time3(time_t t, unsigned len) 983 { 984 struct tm *tp; 985 int sz = 8, width = 0; 986 987 while (sz++ < len) { 988 putchar(' '); 989 width++; 990 } 991 tp = localtime(&t); 992 if (now > t && now - t > 86400) { 993 nl_item val; 994 995 switch (tp->tm_mon) { 996 case 0: val = ABMON_1; break; 997 case 1: val = ABMON_2; break; 998 case 2: val = ABMON_3; break; 999 case 3: val = ABMON_4; break; 1000 case 4: val = ABMON_5; break; 1001 case 5: val = ABMON_6; break; 1002 case 6: val = ABMON_7; break; 1003 case 7: val = ABMON_8; break; 1004 case 8: val = ABMON_9; break; 1005 case 9: val = ABMON_10; break; 1006 case 10: val = ABMON_11; break; 1007 case 11: val = ABMON_12; break; 1008 default: val = ABMON_12; /* won't happen anyway */ 1009 } 1010 width += printf(" %s %02u", nl_langinfo(val), tp->tm_mday); 1011 } else 1012 width += printf("%02u:%02u:%02u", 1013 tp->tm_hour, tp->tm_min, tp->tm_sec); 1014 return width; 1015 } 1016 1017 #define ZOMBIE(a) (p->p_lstate[0] != 'Z' ? (a) : \ 1018 printf("%-*s", o->o_len, oflag ? "-" : " ")) 1019 1020 static void 1021 outproc(struct proc *p) 1022 { 1023 struct output *o; 1024 int width = 0; 1025 1026 for (o = o0; o; o = o->o_nxt) { 1027 switch (o->o_typ) { 1028 case OU_USER: 1029 width += putuser(p->p_euid, o->o_len); 1030 break; 1031 case OU_RUSER: 1032 width += putuser(p->p_uid, o->o_len); 1033 break; 1034 case OU_RGROUP: 1035 width += putgroup(p->p_gid, o->o_len); 1036 break; 1037 case OU_GROUP: 1038 width += putgroup(p->p_egid, o->o_len); 1039 break; 1040 case OU_PID: 1041 width += printf("%*u", o->o_len, (int)p->p_pid); 1042 break; 1043 case OU_PPID: 1044 width += printf("%*u", o->o_len, (int)p->p_ppid); 1045 break; 1046 case OU_PGID: 1047 width += printf("%*u", o->o_len, (int)p->p_pgid); 1048 break; 1049 case OU_LWP: 1050 case OU_STID: 1051 width += ZOMBIE(printf("%*u", o->o_len, (int)p->p_lwp)); 1052 break; 1053 case OU_PCPU: 1054 width += printf("%*.1f", o->o_len, p->p_pctcpu); 1055 break; 1056 case OU_VSZ: 1057 width += ZOMBIE(printf("%*lu", o->o_len, 1058 (long)p->p_size)); 1059 break; 1060 case OU_NICE: 1061 if (p->p_policy == SCHED_OTHER && p->p_pid != 0) { 1062 width += ZOMBIE(printf("%*d", o->o_len, 1063 (int)p->p_nice)); 1064 } else { 1065 width += ZOMBIE(printf("%*.*s", 1066 o->o_len, o->o_len, 1067 p->p_clname)); 1068 } 1069 break; 1070 case OU_NLWP: 1071 width += ZOMBIE(printf("%*u", o->o_len, p->p_nlwp)); 1072 break; 1073 case OU_NTP: 1074 width += ZOMBIE(printf("%*u", o->o_len, 1075 p->p_nlwp > 1 ? p->p_nlwp : 0)); 1076 break; 1077 case OU_TID: 1078 width += ZOMBIE(printf("%*s", o->o_len, "-")); 1079 break; 1080 case OU_ETIME: 1081 width += time2(now - p->p_start, o->o_len, 0); 1082 break; 1083 case OU_TTY: 1084 width += ZOMBIE(putdev(p->p_ttydev, o->o_len)); 1085 break; 1086 case OU_LTIME: 1087 case OU_OTIME: 1088 width += time2(p->p_time, o->o_len, 1); 1089 break; 1090 case OU_TIME: 1091 width += time2(p->p_time, o->o_len, 0); 1092 break; 1093 case OU_ACCUTIME: 1094 width += time2(p->p_accutime, o->o_len, 1); 1095 break; 1096 case OU_UTIME: 1097 width += time2(p->p_utime, o->o_len, 2); 1098 break; 1099 case OU_KTIME: 1100 width += time2(p->p_ktime, o->o_len, 2); 1101 break; 1102 case OU_COMM: 1103 width += putstr(width, o->o_nxt ? o->o_len : 0, 0, 1104 p->p_lstate[0] != 'Z' ? 1105 p->p_comm : DEFUNCT); 1106 break; 1107 case OU_ARGS: 1108 width += putstr(width, o->o_nxt ? o->o_len : 0, 0, 1109 p->p_lstate[0] != 'Z' ? 1110 p->p_psargs : DEFUNCT); 1111 break; 1112 case OU_F: 1113 width += printf("%*o", o->o_len, 1114 (int)(p->p_flag & 077)); 1115 break; 1116 case OU_S: 1117 width += printf("%*s", o->o_len, p->p_state); 1118 break; 1119 case OU_C: 1120 width += printf("%*d", o->o_len, p->p_c); 1121 break; 1122 case OU_UID: 1123 width += printf("%*u", o->o_len, (int)p->p_euid); 1124 break; 1125 case OU_RUID: 1126 width += printf("%*u", o->o_len, (int)p->p_uid); 1127 break; 1128 case OU_GID: 1129 width += printf("%*u", o->o_len, (int)p->p_egid); 1130 break; 1131 case OU_RGID: 1132 width += printf("%*u", o->o_len, (int)p->p_gid); 1133 break; 1134 case OU_SID: 1135 width += printf("%*u", o->o_len, (int)p->p_sid); 1136 break; 1137 case OU_CLASS: 1138 width += ZOMBIE(printf("%*s", o->o_len, p->p_clname)); 1139 break; 1140 case OU_PRI: 1141 width += ZOMBIE(printf("%*d", o->o_len, (int)p->p_pri)); 1142 break; 1143 case OU_OPRI: 1144 width += ZOMBIE(printf("%*d", o->o_len, 1145 (int)p->p_oldpri)); 1146 break; 1147 case OU_PSR: 1148 width += printf("%*d", o->o_len, (int)p->p_psr); 1149 break; 1150 case OU_ADDR: 1151 width += ZOMBIE(putxd(o->o_len, (long)p->p_addr)); 1152 break; 1153 case OU_OSZ: 1154 width += ZOMBIE(printf("%*lu", o->o_len, 1155 (long)p->p_osz)); 1156 break; 1157 case OU_WCHAN: 1158 if (p->p_lstate[0] == 'S' || p->p_lstate[0] == 'X' || 1159 p->p_lstate[0] == 'D') 1160 width += putxd(o->o_len, (long)p->p_wchan); 1161 else 1162 width += printf("%*s", o->o_len, " "); 1163 break; 1164 case OU_STIME: 1165 width += ZOMBIE(time3(p->p_start, o->o_len)); 1166 break; 1167 case OU_RSS: 1168 width += ZOMBIE(printf("%*lu", o->o_len, 1169 (long)p->p_rssize)); 1170 break; 1171 case OU_ORSS: 1172 case OU_MRSZ: 1173 width += ZOMBIE(printf("%*lu", o->o_len, 1174 (long)p->p_orss)); 1175 break; 1176 case OU_PMEM: 1177 width += printf("%*.1f", o->o_len, p->p_pctmem); 1178 break; 1179 case OU_PFLTS: 1180 width += printf("%*lu", o->o_len, p->p_pflts); 1181 break; 1182 case OU_BUFW: 1183 width += printf("%*lu", o->o_len, p->p_bufw); 1184 break; 1185 case OU_BUFR: 1186 width += printf("%*lu", o->o_len, p->p_bufr); 1187 break; 1188 case OU_MRCV: 1189 width += printf("%*lu", o->o_len, p->p_mrcv); 1190 break; 1191 case OU_MSND: 1192 width += printf("%*lu", o->o_len, p->p_msnd); 1193 break; 1194 case OU_FNAME: 1195 width += putstr(width, o->o_nxt ? o->o_len : 0, 1196 #ifndef UCB 1197 p->p_lstate[0] != 'Z' ? 8 : 9, 1198 #else /* UCB */ 1199 16, 1200 #endif /* UCB */ 1201 p->p_lstate[0] != 'Z' ? 1202 p->p_fname : DEFUNCT); 1203 break; 1204 case OU_SPACE: 1205 if (o->o_len > 1) 1206 width += printf("%*s", o->o_len - 1, ""); 1207 break; 1208 } 1209 if (o->o_nxt) { 1210 putchar(' '); 1211 width++; 1212 } 1213 } 1214 putchar('\n'); 1215 } 1216 1217 #if !defined (__hpux) && !defined (_AIX) && !defined (__NetBSD__) && \ 1218 !defined (__OpenBSD__) && !defined (__APPLE__) 1219 1220 #if defined (__linux__) || defined (__FreeBSD__) || defined (__DragonFly__) 1221 #define GETVAL_REQ(a) if ((v = getval(&cp, (a), ' ', 0)) == NULL) \ 1222 return STOP 1223 1224 #define GETVAL_OPT(a) if ((v = getval(&cp, (a), ' ', 0)) == NULL) \ 1225 goto complete 1226 1227 #define GETVAL_COMMA(a) if ((v = getval(&cp, (a), ' ', ',')) == NULL) \ 1228 return STOP 1229 #endif /* __linux__ || __FreeBSD__ || __DragonFly__ */ 1230 1231 #if defined (__linux__) 1232 static void 1233 get_linux_version(void) 1234 { 1235 struct utsname ut; 1236 char *x; 1237 long val; 1238 1239 if (uname(&ut) == 0) { 1240 if ((val = strtol(ut.release, &x, 10)) > 0 && 1241 (*x == '.' || *x == '\0')) { 1242 linux_version[0] = val; 1243 if (*x && (val = strtol(&x[1], &x, 10)) >= 0 && 1244 (*x == '.' || *x == '\0')) { 1245 linux_version[1] = val; 1246 if (*x && (val = strtol(&x[1], &x, 10)) >= 0) 1247 linux_version[2] = val; 1248 } 1249 } 1250 } 1251 } 1252 1253 static time_t 1254 sysup(void) 1255 { 1256 FILE *fp; 1257 char buf[32]; 1258 char *cp; 1259 union value *v; 1260 time_t s = 0; 1261 1262 if ((fp = fopen("uptime", "r")) == NULL) 1263 return 0; 1264 if (fread(buf, 1, sizeof buf, fp) > 0) { 1265 cp = buf; 1266 if ((v = getval(&cp, VT_ULONG, '.', 0)) != NULL) 1267 s = v->v_ulong; 1268 } 1269 fclose(fp); 1270 return s; 1271 } 1272 1273 static unsigned long 1274 getmem(void) 1275 { 1276 FILE *fp; 1277 char line[LINE_MAX]; 1278 char *cp; 1279 union value *v; 1280 unsigned long mem = 1; 1281 1282 if ((fp = fopen("meminfo", "r")) == NULL) 1283 return 0; 1284 while (fgets(line, sizeof line, fp) != NULL) { 1285 if (strncmp(line, "MemTotal:", 9) == 0) { 1286 cp = &line[9]; 1287 while (isspace(*cp)) 1288 cp++; 1289 if ((v = getval(&cp, VT_ULONG, ' ', 0)) != NULL) 1290 mem = v->v_ulong; 1291 break; 1292 } 1293 } 1294 fclose(fp); 1295 return mem; 1296 } 1297 1298 static time_t 1299 hz2time(long val, int mult) 1300 { 1301 long long t; 1302 1303 t = val * mult / hz; 1304 if ((val * mult) % hz >= (hz >> 1)) 1305 t++; 1306 return t; 1307 } 1308 1309 static void (*compute_priority)(struct proc *); 1310 1311 /* 1312 * Calculate reasonable values for priority fields using all we can get 1313 * from /proc in Linux 2.4: a crippled counter (in p->intpri) and the 1314 * nice value. 1315 */ 1316 static void 1317 compute_priority_old(struct proc *p) 1318 { 1319 static int def_counter, scale, max_goodness; 1320 int full_counter, counter, goodness; 1321 1322 /* 1323 * This is based on the computations in linux/sched.c, 2.4.19. 1324 */ 1325 if (def_counter == 0) { 1326 def_counter = 10 * hz / 100; 1327 if (hz < 200) 1328 scale = 4; 1329 else if (hz < 400) 1330 scale = 3; 1331 else if (hz < 800) 1332 scale = 2; 1333 else if (hz < 1600) 1334 scale = 1; 1335 else 1336 scale = 0; 1337 max_goodness = (((40 << 3) >> scale) + 2) + 40; 1338 } 1339 full_counter = (((40 - p->p_nice) << 3) >> scale) + 2; 1340 /* 1341 * Try to reverse the computation in linux/fs/proc/array.c, 1342 * 2.4.19. 1343 */ 1344 counter = (def_counter * (20 - p->p_intpri)) / 10; 1345 /* 1346 * This can apparently happen if the command is in its first 1347 * timeslice after a lower nice value has been set. 1348 */ 1349 if (counter > full_counter) 1350 counter = full_counter; 1351 /* 1352 * This approximation is even worse, as we cannot know about 1353 * PROC_CHANGE_PENALTY and MM. 1354 */ 1355 if ((goodness = counter) > 0) 1356 goodness += 40 - p->p_nice; 1357 /* 1358 * Keep all priorities for -c below 60 and with higher 1359 * priorities for higher numbers. 1360 */ 1361 p->p_pri = goodness * 59 / max_goodness; 1362 /* 1363 * Old-style priorities start at 60 and have lower numbers 1364 * for higher priorities. 1365 */ 1366 p->p_oldpri = 119 - p->p_pri; 1367 /* 1368 * Our counter emulation can be wrong by 2 in the worst 1369 * case. If the process is not currently on a run queue, 1370 * assume it did not use the CPU at all. 1371 */ 1372 p->p_c = full_counter - counter; 1373 if (p->p_lstate[0] != 'R' && p->p_c <= 2) 1374 p->p_c = 0; 1375 /* 1376 * The value for C still depends on the nice value. Make 80 1377 * the highest possible C value for all nice values. 1378 */ 1379 p->p_c *= 80 / full_counter; 1380 } 1381 1382 /* 1383 * Priority calculation for Linux 2.5 and (hopefully) above, based 1384 * on 2.5.31. This supplies a sensible priority value, but originally 1385 * nothing we could use to compute "CPU usage for scheduling". More 1386 * recent 2.6 versions have a SleepAVG field in the "status" file. 1387 */ 1388 static void 1389 compute_priority_new(struct proc *p) 1390 { 1391 if (p->p_rtpri) { 1392 p->p_pri = 100 + p->p_rtpri; 1393 p->p_oldpri = 60 - (p->p_rtpri >> 1); 1394 } else { 1395 p->p_pri = 40 - p->p_intpri; 1396 p->p_oldpri = 60 + p->p_intpri + (p->p_intpri >> 1); 1397 } 1398 } 1399 1400 static void 1401 compute_various(struct proc *p) 1402 { 1403 /* 1404 * All dead processes are considered zombies by us. 1405 */ 1406 if (p->p_lstate[0] == 'X') 1407 p->p_lstate[0] = 'Z'; 1408 /* 1409 * Set System V style status. There seems no method to 1410 * determine 'O' (not only on run queue, but actually 1411 * running). 1412 */ 1413 if (p->p_lstate[0] == 'D' || p->p_lstate[0] == 'W') 1414 p->p_state[0] = 'S'; 1415 else 1416 p->p_state[0] = p->p_lstate[0]; 1417 #ifdef notdef 1418 /* 1419 * Process flags vary too much between real and vendor kernels 1420 * and there's no method to distinguish them - don't use. 1421 */ 1422 if (p->p_lflag & 0x00000002) /* PF_STARTING */ 1423 p->p_state[0] = 'I'; 1424 else if (p->p_lflag & 0x00000800) /* PF_MEMALLOC */ 1425 p->p_state[0] = 'X'; 1426 #endif /* notdef */ 1427 /* 1428 * Set v7 / System III style flags. 1429 */ 1430 if (p->p_lstate[0] != 'Z') { 1431 if (p->p_flag & FL_SYS || p->p_rssize != 0) 1432 p->p_flag |= FL_LOAD; /* cf. statm processing */ 1433 else 1434 p->p_flag |= FL_SWAP; /* no rss -> swapped */ 1435 if (p->p_lstate[0] == 'D') { 1436 p->p_flag |= FL_LOCK; 1437 p->p_flag &= ~FL_SWAP; 1438 } else if (p->p_lstate[0] == 'W') 1439 p->p_flag |= FL_SWAP; 1440 /*if (p->p_lflag & 0x10) obsolete, doesn't work 1441 p->p_flag |= FL_TRC;*/ 1442 } 1443 } 1444 1445 static enum okay 1446 getproc_stat(struct proc *p, pid_t expected_pid) 1447 { 1448 static char *buf; 1449 static size_t buflen; 1450 union value *v; 1451 FILE *fp; 1452 char *cp, *cq, *ce; 1453 size_t sz, sc; 1454 unsigned long lval; 1455 /* 1456 * There is no direct method to determine if something is a system 1457 * process. We consider a process a system process if a certain set 1458 * of criteria is entirely zero. 1459 */ 1460 unsigned long sysfl = 0; 1461 1462 if ((fp = fopen("stat", "r")) == NULL) 1463 return STOP; 1464 for (cp = buf; ;) { 1465 const unsigned chunk = 32; 1466 1467 if (buflen < (sz = cp - buf + chunk)) { 1468 sc = cp - buf; 1469 buf = srealloc(buf, buflen = sz); 1470 cp = &buf[sc]; 1471 } 1472 if ((sz = fread(cp, 1, chunk, fp)) < chunk) { 1473 ce = &cp[sz - 1]; 1474 break; 1475 } 1476 cp += chunk; 1477 } 1478 fclose(fp); 1479 if (*ce != '\n') 1480 return STOP; 1481 *ce-- = '\0'; 1482 cp = buf; 1483 /* pid */ 1484 GETVAL_REQ(VT_INT); 1485 if ((p->p_pid = v->v_int) != expected_pid) 1486 return STOP; 1487 if (*cp++ != '(') 1488 return STOP; 1489 for (cq = ce; cq >= cp && *cq != ')'; cq--); 1490 if (cq < cp) 1491 return STOP; 1492 *cq = '\0'; 1493 strncpy(p->p_fname, cp, sizeof p->p_fname); 1494 p->p_fname[sizeof p->p_fname - 1] = '\0'; 1495 cp = &cq[1]; 1496 while (isspace(*cp)) 1497 cp++; 1498 /* state */ 1499 GETVAL_REQ(VT_CHAR); 1500 p->p_lstate[0] = v->v_char; 1501 sysfl |= v->v_char == 'Z'; 1502 /* ppid */ 1503 GETVAL_REQ(VT_INT); 1504 p->p_ppid = v->v_int; 1505 /* pgrp */ 1506 GETVAL_REQ(VT_INT); 1507 p->p_pgid = v->v_int; 1508 /* session */ 1509 GETVAL_REQ(VT_INT); 1510 p->p_sid = v->v_int; 1511 /* tty_nr */ 1512 GETVAL_REQ(VT_INT); 1513 p->p_ttydev = v->v_int; 1514 sysfl |= v->v_int; 1515 /* tty_pgrp */ 1516 GETVAL_REQ(VT_INT); 1517 /* flags */ 1518 GETVAL_REQ(VT_ULONG); 1519 p->p_lflag = v->v_ulong; 1520 /* minflt */ 1521 GETVAL_REQ(VT_ULONG); 1522 /* cminflt */ 1523 GETVAL_REQ(VT_ULONG); 1524 /* majflt */ 1525 GETVAL_REQ(VT_ULONG); 1526 p->p_pflts = v->v_ulong; 1527 /* cmajflt */ 1528 GETVAL_REQ(VT_ULONG); 1529 /* utime */ 1530 GETVAL_REQ(VT_ULONG); 1531 lval = v->v_ulong; 1532 p->p_utime = hz2time(lval, 10); 1533 sysfl |= v->v_ulong; 1534 /* stime */ 1535 GETVAL_REQ(VT_ULONG); 1536 p->p_ktime = hz2time(v->v_ulong, 10); 1537 lval += v->v_ulong; 1538 p->p_time = hz2time(lval, 1); 1539 /* cutime */ 1540 GETVAL_REQ(VT_LONG); 1541 lval += v->v_ulong; 1542 /* cstime */ 1543 GETVAL_REQ(VT_LONG); 1544 lval += v->v_ulong; 1545 p->p_accutime += hz2time(lval, 1); 1546 /* priority */ 1547 GETVAL_REQ(VT_LONG); 1548 p->p_intpri = v->v_long; 1549 /* nice */ 1550 GETVAL_REQ(VT_LONG); 1551 p->p_nice = v->v_long + 20; 1552 /* timeout */ 1553 GETVAL_REQ(VT_LONG); 1554 /* itrealvalue */ 1555 GETVAL_REQ(VT_LONG); 1556 /* starttime */ 1557 GETVAL_REQ(VT_ULONG); 1558 p->p_start = hz2time(v->v_ulong, 1) + now - uptime; 1559 /* vsize */ 1560 GETVAL_REQ(VT_ULONG); 1561 p->p_size = (v->v_ulong >> 10); 1562 p->p_osz = v->v_ulong / pagesize; 1563 sysfl |= v->v_ulong; 1564 /* rss */ 1565 GETVAL_REQ(VT_LONG); 1566 p->p_orss = v->v_long; 1567 p->p_rssize = v->v_long * kbytes_per_page; 1568 sysfl |= v->v_ulong; 1569 /* rlim */ 1570 GETVAL_REQ(VT_ULONG); 1571 /* startcode */ 1572 GETVAL_REQ(VT_ULONG); 1573 p->p_addr = v->v_ulong; 1574 sysfl |= v->v_ulong; 1575 /* endcode */ 1576 GETVAL_REQ(VT_ULONG); 1577 sysfl |= v->v_ulong; 1578 /* startstack */ 1579 GETVAL_REQ(VT_ULONG); 1580 sysfl |= v->v_ulong; 1581 /* kstkesp */ 1582 GETVAL_REQ(VT_ULONG); 1583 /* kstkeip */ 1584 GETVAL_REQ(VT_ULONG); 1585 /* signal */ 1586 GETVAL_REQ(VT_ULONG); 1587 /* blocked */ 1588 GETVAL_REQ(VT_ULONG); 1589 /* sigignore */ 1590 GETVAL_REQ(VT_ULONG); 1591 /* sigcatch */ 1592 GETVAL_REQ(VT_ULONG); 1593 /* wchan */ 1594 GETVAL_REQ(VT_ULONG); 1595 p->p_wchan = v->v_ulong; 1596 /* 1597 * These appeared in later Linux versions, so they are not 1598 * required to be present. 1599 */ 1600 p->p_policy = -1; /* initialize to invalid values */ 1601 /* nswap */ 1602 GETVAL_OPT(VT_ULONG); 1603 /* cnswap */ 1604 GETVAL_OPT(VT_ULONG); 1605 /* exit_signal */ 1606 GETVAL_OPT(VT_INT); 1607 /* processor */ 1608 GETVAL_OPT(VT_INT); 1609 p->p_psr = v->v_int; 1610 /* rt_priority */ 1611 GETVAL_OPT(VT_ULONG); 1612 p->p_rtpri = v->v_ulong; 1613 /* policy */ 1614 GETVAL_OPT(VT_ULONG); 1615 p->p_policy = v->v_ulong; 1616 complete: 1617 if (sysfl == 0) 1618 p->p_flag |= FL_SYS; 1619 compute_various(p); 1620 return OKAY; 1621 } 1622 1623 static enum okay 1624 getproc_scheduler(struct proc *p) 1625 { 1626 struct sched_param s; 1627 1628 if (p->p_policy == -1) /* Linux 2.4 and below */ 1629 p->p_policy = sched_getscheduler(p->p_pid); 1630 switch (p->p_policy) { 1631 case SCHED_FIFO: 1632 case SCHED_RR: 1633 switch (p->p_policy) { 1634 case SCHED_FIFO: p->p_clname = "FF"; break; 1635 #ifdef S42 1636 case SCHED_RR: p->p_clname = "FP"; break; 1637 #else 1638 case SCHED_RR: p->p_clname = "RT"; break; 1639 #endif 1640 } 1641 if (p->p_rtpri == 0 && sched_getparam(p->p_pid, &s) == 0) { 1642 p->p_rtpri = s.sched_priority; 1643 /* Linux 2.4 and below */ 1644 p->p_pri = 100 + s.sched_priority; 1645 } 1646 break; 1647 case SCHED_OTHER: 1648 p->p_clname = "TS"; 1649 break; 1650 #ifdef SCHED_BATCH 1651 case SCHED_BATCH: 1652 p->p_clname = "B"; 1653 break; 1654 #endif /* SCHED_BATCH */ 1655 #ifdef SCHED_ISO 1656 case SCHED_ISO: 1657 p->p_clname = "ISO"; 1658 break; 1659 #endif /* SCHED_ISO */ 1660 default: 1661 p->p_clname = "??"; 1662 } 1663 compute_priority(p); 1664 return OKAY; 1665 } 1666 1667 static enum okay 1668 getproc_cmdline(struct proc *p) 1669 { 1670 FILE *fp; 1671 char *cp, *cq, *ce; 1672 int hadzero = 0, c; 1673 1674 if ((fp = fopen("cmdline", "r")) != NULL) { 1675 cp = p->p_psargs; 1676 cq = p->p_comm; 1677 ce = cp + sizeof p->p_psargs - 1; 1678 while (cp < ce && (c = getc(fp)) != EOF) { 1679 if (c != '\0') { 1680 if (hadzero) { 1681 *cp++ = ' '; 1682 if (cp == ce) 1683 break; 1684 hadzero = 0; 1685 } 1686 *cp++ = c; 1687 if (cq) 1688 *cq++ = c; 1689 } else { 1690 hadzero = 1; 1691 if (cq) { 1692 *cq = c; 1693 cq = NULL; 1694 } 1695 } 1696 } 1697 *cp = '\0'; 1698 if (cq) 1699 *cq = '\0'; 1700 fclose(fp); 1701 } 1702 return OKAY; 1703 } 1704 1705 static enum okay 1706 getproc_status(struct proc *p) 1707 { 1708 char line[LINE_MAX]; 1709 union value *v; 1710 FILE *fp; 1711 char *cp; 1712 int scanr; 1713 1714 if ((fp = fopen("status", "r")) == NULL) 1715 return STOP; 1716 scanr = 0; 1717 while (fgets(line, sizeof line, fp) != NULL) { 1718 if (strncmp(line, "Uid:", 4) == 0) { 1719 cp = &line[4]; 1720 while (isspace(*cp)) 1721 cp++; 1722 if ((v = getval(&cp, VT_INT, ' ', 0)) == NULL) { 1723 fclose(fp); 1724 return STOP; 1725 } 1726 p->p_uid = v->v_int; 1727 if ((v = getval(&cp, VT_INT, ' ', 0)) == NULL) { 1728 fclose(fp); 1729 return STOP; 1730 } 1731 p->p_euid = v->v_int; 1732 scanr++; 1733 } else if (strncmp(line, "Gid:", 4) == 0) { 1734 cp = &line[4]; 1735 while (isspace(*cp)) 1736 cp++; 1737 if ((v = getval(&cp, VT_INT, ' ', 0)) == NULL) { 1738 fclose(fp); 1739 return STOP; 1740 } 1741 p->p_gid = v->v_int; 1742 if ((v = getval(&cp, VT_INT, ' ', 0)) == NULL) { 1743 fclose(fp); 1744 return STOP; 1745 } 1746 p->p_egid = v->v_int; 1747 scanr++; 1748 } else if (strncmp(line, "Threads:", 8) == 0) { 1749 cp = &line[8]; 1750 while (isspace(*cp)) 1751 cp++; 1752 if ((v = getval(&cp, VT_INT, ' ', 0)) == NULL) { 1753 fclose(fp); 1754 return STOP; 1755 } 1756 p->p_nlwp = v->v_int; 1757 } else if (strncmp(line, "Pid:", 4) == 0) { 1758 cp = &line[4]; 1759 while (isspace(*cp)) 1760 cp++; 1761 if ((v = getval(&cp, VT_INT, ' ', 0)) == NULL) { 1762 fclose(fp); 1763 return STOP; 1764 } 1765 p->p_lwp = v->v_int; 1766 } else if (strncmp(line, "SleepAVG:", 9) == 0) { 1767 cp = &line[9]; 1768 while (isspace(*cp)) 1769 cp++; 1770 if ((v = getval(&cp, VT_INT, '%', 0)) == NULL) { 1771 fclose(fp); 1772 return STOP; 1773 } 1774 p->p_c = (100 - v->v_int) * 80 / 100; 1775 } 1776 } 1777 fclose(fp); 1778 if (scanr != 2) 1779 return STOP; 1780 return OKAY; 1781 } 1782 1783 static enum okay 1784 getproc_statm(struct proc *p) 1785 { 1786 char line[LINE_MAX]; 1787 union value *v; 1788 FILE *fp; 1789 char *cp; 1790 unsigned long trs, drs, dt; 1791 1792 if ((fp = fopen("statm", "r")) == NULL) 1793 return OKAY; /* not crucial */ 1794 if (fgets(line, sizeof line, fp) != NULL) { 1795 cp = line; 1796 if ((v = getval(&cp, VT_LONG, ' ', 0)) == NULL) /* size */ 1797 goto out; 1798 if ((v = getval(&cp, VT_LONG, ' ', 0)) == NULL) /* resident */ 1799 goto out; 1800 if ((v = getval(&cp, VT_LONG, ' ', 0)) == NULL) /* share */ 1801 goto out; 1802 if ((v = getval(&cp, VT_LONG, ' ', 0)) == NULL) /* trs */ 1803 goto out; 1804 trs = v->v_long; 1805 if ((v = getval(&cp, VT_LONG, ' ', 0)) == NULL) /* drs */ 1806 goto out; 1807 drs = v->v_long; 1808 if ((v = getval(&cp, VT_LONG, ' ', 0)) == NULL) /* lrs */ 1809 goto out; 1810 if ((v = getval(&cp, VT_LONG, ' ', 0)) == NULL) /* dt */ 1811 goto out; 1812 dt = v->v_long; 1813 /* 1814 * A process is considered to be swapped out if it has 1815 * neither resident non-library text, data, nor dirty 1816 * pages. A system process is always considered to be 1817 * in core. 1818 */ 1819 if (trs + drs + dt == 0 && 1820 (p->p_flag&(FL_LOAD|FL_SYS|FL_LOCK))==FL_LOAD) { 1821 p->p_flag &= ~FL_LOAD; 1822 p->p_flag |= FL_SWAP; 1823 } 1824 } 1825 out: fclose(fp); 1826 return OKAY; 1827 } 1828 1829 static enum okay 1830 getproc(const char *dir, struct proc *p, pid_t expected_pid, pid_t lwp) 1831 { 1832 enum okay result; 1833 1834 memset(p, 0, sizeof *p); 1835 if (chdir(dir) == 0) { 1836 if ((result = getproc_stat(p, expected_pid)) == OKAY) 1837 if ((result = getproc_scheduler(p)) == OKAY) 1838 if ((result = getproc_cmdline(p)) == OKAY) 1839 if ((result= getproc_status(p)) == OKAY) 1840 result = getproc_statm(p); 1841 chdir_to_proc(); 1842 } else 1843 result = STOP; 1844 return result; 1845 } 1846 1847 static enum okay 1848 getLWPs(const char *dir, struct proc *p, pid_t expected_pid) 1849 { 1850 DIR *Dp; 1851 struct dirent *dp; 1852 unsigned long val; 1853 char *x; 1854 int fd; 1855 1856 if (chdir(dir) == 0 && 1857 (fd = open("task", O_RDONLY)) >= 0 && 1858 fchdir(fd) == 0 && 1859 (Dp = opendir(".")) != NULL) { 1860 while ((dp = readdir(Dp)) != NULL) { 1861 if (dp->d_name[0] == '.' && (dp->d_name[1]=='\0' || 1862 (dp->d_name[1]=='.' && 1863 dp->d_name[2]=='\0'))) 1864 continue; 1865 val = strtoul(dp->d_name, &x, 10); 1866 if (*x != 0) 1867 continue; 1868 if (fchdir(fd) < 0) { 1869 fprintf(stderr, 1870 "%s: cannot chdir to %s/%s/task\n", 1871 progname, PROCDIR, dir); 1872 errcnt = 1; 1873 break; 1874 } 1875 if (getproc(dp->d_name, p, val, val) == OKAY) { 1876 postproc(p); 1877 if (selectproc(p) == OKAY) { 1878 p->p_pid = expected_pid; 1879 outproc(p); 1880 } 1881 } 1882 } 1883 closedir(Dp); 1884 close(fd); 1885 return OKAY; 1886 } else { 1887 chdir_to_proc(); 1888 return STOP; 1889 } 1890 } 1891 1892 #elif defined (__FreeBSD__) || defined (__DragonFly__) 1893 1894 static unsigned long 1895 getmem(void) 1896 { 1897 return 0; 1898 } 1899 1900 static enum okay 1901 getproc_status(struct proc *p, pid_t expected_pid) 1902 { 1903 static char *buf; 1904 static size_t buflen; 1905 union value *v; 1906 FILE *fp; 1907 char *cp, *cq, *ce; 1908 size_t sz, sc; 1909 int mj, mi; 1910 1911 if ((fp = fopen("status", "r")) == NULL) 1912 return STOP; 1913 for (cp = buf; ;) { 1914 const unsigned chunk = 32; 1915 1916 if (buflen < (sz = cp - buf + chunk)) { 1917 sc = cp - buf; 1918 buf = srealloc(buf, buflen = sz); 1919 cp = &buf[sc]; 1920 } 1921 if ((sz = fread(cp, 1, chunk, fp)) < chunk) { 1922 ce = &cp[sz - 1]; 1923 break; 1924 } 1925 cp += chunk; 1926 } 1927 fclose(fp); 1928 if (*ce != '\n') 1929 return STOP; 1930 *ce-- = '\0'; 1931 cp = buf; 1932 cq = p->p_fname; 1933 while (*cp != ' ') { 1934 if (cq - p->p_fname < sizeof p->p_fname - 1) { 1935 if (cp[0] == '\\' && isdigit(cp[1]) && 1936 isdigit(cp[2]) && isdigit(cp[3])) { 1937 *cq++ = cp[3] - '0' + 1938 (cp[2] - '0' << 3) + 1939 (cp[1] - '0' << 6); 1940 cp += 4; 1941 } else 1942 *cq++ = *cp++; 1943 } else 1944 cp++; 1945 } 1946 *cq = '\0'; 1947 while (*cp == ' ') 1948 cp++; 1949 GETVAL_REQ(VT_INT); 1950 p->p_pid = v->v_int; 1951 GETVAL_REQ(VT_INT); 1952 p->p_ppid = v->v_int; 1953 GETVAL_REQ(VT_INT); 1954 p->p_pgid = v->v_int; 1955 GETVAL_REQ(VT_INT); 1956 p->p_sid = v->v_int; 1957 if (isdigit(*cp)) { 1958 GETVAL_COMMA(VT_INT); 1959 mj = v->v_int; 1960 GETVAL_REQ(VT_INT); 1961 mi = v->v_int; 1962 if (mj != -1 || mi != -1) 1963 p->p_ttydev = makedev(mj, mi); 1964 } else { 1965 struct stat st; 1966 char *dev; 1967 cq = cp; 1968 while (*cp != ' ') cp++; 1969 *cp = '\0'; 1970 dev = smalloc(cp - cq + 8); 1971 strcpy(dev, "/dev/"); 1972 strcpy(&dev[5], cq); 1973 if (stat(dev, &st) < 0) 1974 p->p_ttydev = PRNODEV; 1975 else 1976 p->p_ttydev = st.st_rdev; 1977 free(dev); 1978 *cp = ' '; 1979 while (*cp == ' ') cp++; 1980 } 1981 while (*cp != ' ') cp++; while (*cp == ' ') cp++; 1982 /* skip flags */ 1983 GETVAL_COMMA(VT_LONG); 1984 p->p_start = v->v_long; 1985 /* microseconds */ 1986 GETVAL_REQ(VT_LONG); 1987 GETVAL_COMMA(VT_LONG); 1988 p->p_time = v->v_long; 1989 p->p_utime = v->v_long; 1990 /* microseconds */ 1991 GETVAL_REQ(VT_LONG); 1992 p->p_utime += v->v_long / 100000; 1993 GETVAL_COMMA(VT_LONG); 1994 p->p_time += v->v_long; 1995 p->p_ktime = v->v_long; 1996 p->p_accutime = p->p_time; 1997 /* microseconds */ 1998 GETVAL_REQ(VT_LONG); 1999 p->p_ktime += v->v_long / 100000; 2000 if (strncmp(cp, "nochan ", 7) == 0) 2001 p->p_state[0] = p->p_lstate[0] = 'R'; 2002 else 2003 p->p_state[0] = p->p_lstate[0] = 'S'; 2004 while (*cp != ' ') { 2005 if (p->p_state[0] == 'S') 2006 p->p_wchan |= *cp << (*cp&30); /* fake */ 2007 cp++; 2008 } 2009 while (*cp == ' ') cp++; 2010 GETVAL_REQ(VT_INT); 2011 p->p_euid = v->v_int; 2012 GETVAL_REQ(VT_INT); 2013 p->p_uid = v->v_int; 2014 GETVAL_COMMA(VT_INT); 2015 p->p_gid = v->v_int; 2016 GETVAL_COMMA(VT_INT); 2017 p->p_egid = v->v_int; 2018 return OKAY; 2019 } 2020 2021 static enum okay 2022 getproc_cmdline(struct proc *p) 2023 { 2024 FILE *fp; 2025 char *cp, *ce; 2026 int hadzero = 0, c; 2027 2028 if ((fp = fopen("cmdline", "r")) != NULL) { 2029 cp = p->p_psargs; 2030 ce = cp + sizeof p->p_psargs - 1; 2031 while (cp < ce && (c = getc(fp)) != EOF) { 2032 if (c != '\0') { 2033 if (hadzero) { 2034 *cp++ = ' '; 2035 if (cp == ce) 2036 break; 2037 hadzero = 0; 2038 } 2039 *cp++ = c; 2040 } else { 2041 hadzero = 1; 2042 } 2043 } 2044 *cp = '\0'; 2045 fclose(fp); 2046 } 2047 if (*p->p_psargs == '\0' && p->p_size == 0) 2048 strcpy(p->p_psargs, p->p_fname); 2049 return OKAY; 2050 } 2051 2052 static void 2053 priocomp(struct proc *p) 2054 { 2055 static int once; 2056 static int ranges[3][2]; 2057 int *cur; 2058 2059 if (once++ == 0) { 2060 ranges[0][0] = sched_get_priority_min(SCHED_OTHER); 2061 ranges[0][1] = sched_get_priority_max(SCHED_OTHER); 2062 ranges[1][0] = sched_get_priority_min(SCHED_FIFO); 2063 ranges[1][1] = sched_get_priority_max(SCHED_FIFO); 2064 ranges[2][0] = sched_get_priority_min(SCHED_RR); 2065 ranges[3][1] = sched_get_priority_max(SCHED_RR); 2066 } 2067 switch (p->p_policy) { 2068 case SCHED_OTHER: 2069 cur = ranges[0]; 2070 break; 2071 case SCHED_FIFO: 2072 cur = ranges[1]; 2073 break; 2074 case SCHED_RR: 2075 cur = ranges[2]; 2076 break; 2077 default: 2078 return; 2079 } 2080 switch (p->p_policy) { 2081 case SCHED_OTHER: 2082 p->p_nice = getpriority(PRIO_PROCESS, p->p_pid) + 20; 2083 break; 2084 case SCHED_FIFO: 2085 case SCHED_RR: 2086 p->p_pri = ((double)p->p_intpri - cur[0]) / (cur[1] - cur[0]) * 2087 100 + 60; 2088 } 2089 } 2090 2091 static enum okay 2092 getproc_map(struct proc *p) 2093 { 2094 FILE *fp; 2095 long start, end, resident; 2096 int c; 2097 2098 if ((fp = fopen("map", "r")) == NULL) 2099 return OKAY; 2100 while (fscanf(fp, "0x%lx 0x%lx %ld", &start, &end, &resident) == 3) { 2101 if (p->p_addr == 0) 2102 p->p_addr = start; 2103 while ((c = getc(fp)) != EOF && c != '\n'); 2104 p->p_size += (end - start) / 1024; 2105 p->p_orss += resident; 2106 } 2107 p->p_osz = p->p_size / (pagesize / 1024); 2108 p->p_rssize = p->p_orss * (pagesize / 1024); 2109 fclose(fp); 2110 return OKAY; 2111 } 2112 2113 static enum okay 2114 getproc_scheduler(struct proc *p) 2115 { 2116 struct sched_param s; 2117 2118 switch (p->p_policy = sched_getscheduler(p->p_pid)) { 2119 case SCHED_FIFO: 2120 p->p_clname = "FF"; 2121 break; 2122 case SCHED_RR: 2123 #ifdef S42 2124 p->p_clname = "FP"; 2125 #else 2126 p->p_clname = "RT"; 2127 #endif 2128 break; 2129 case SCHED_OTHER: 2130 p->p_clname = "TS"; 2131 break; 2132 default: 2133 p->p_clname = "??"; 2134 } 2135 if (sched_getparam(p->p_pid, &s) == 0) 2136 p->p_intpri = s.sched_priority; 2137 priocomp(p); 2138 return OKAY; 2139 } 2140 2141 static enum okay 2142 getproc_kvm(struct proc *p) 2143 { 2144 static kvm_t *kv; 2145 struct kinfo_proc *kp; 2146 int c; 2147 2148 if (myeuid != 0) 2149 return OKAY; 2150 if (kv == NULL) { 2151 char err[_POSIX2_LINE_MAX]; 2152 if ((kv = kvm_open(NULL, NULL, NULL, O_RDONLY, err)) == NULL) 2153 return OKAY; 2154 } 2155 if ((kp = kvm_getprocs(kv, KERN_PROC_PID, p->p_pid, &c)) == NULL) 2156 return OKAY; 2157 #if (__FreeBSD__) < 5 || defined (__DragonFly__) 2158 switch (kp->kp_proc.p_stat) { 2159 #else /* __FreeBSD__ >= 5 */ 2160 switch (kp->ki_stat) { 2161 #endif /* __FreeBSD__ >= 5 */ 2162 case SIDL: 2163 p->p_state[0] = 'I'; 2164 break; 2165 case SRUN: 2166 p->p_state[0] = 'R'; 2167 break; 2168 #if defined (SWAIT) || defined (SLOCK) 2169 #ifdef SWAIT 2170 case SWAIT: 2171 #endif /* SWAIT */ 2172 #ifdef SLOCK 2173 case SLOCK: 2174 #endif /* SLOCK */ 2175 p->p_flag |= FL_LOCK; 2176 /*FALLTHRU*/ 2177 #endif /* SWAIT || SLOCK */ 2178 case SSLEEP: 2179 p->p_state[0] = 'S'; 2180 break; 2181 case SSTOP: 2182 p->p_state[0] = 'T'; 2183 break; 2184 case SZOMB: 2185 p->p_state[0] = 'Z'; 2186 break; 2187 } 2188 p->p_lstate[0] = p->p_state[0]; 2189 #if (__FreeBSD__) < 5 || defined (__DragonFly__) 2190 #define ki_flag kp_proc.p_flag 2191 #define ki_oncpu kp_proc.p_oncpu 2192 #define ki_wchan kp_proc.p_wchan 2193 #define ki_pri kp_proc.p_pri 2194 #endif /* __FreeBSD__ < 5 */ 2195 if (kp->ki_flag & P_SYSTEM) 2196 p->p_flag |= FL_SYS; 2197 if (kp->ki_flag & P_TRACED) 2198 p->p_flag |= FL_TRC; 2199 #if (__FreeBSD__) < 5 || defined (__DragonFly__) 2200 #ifndef __DragonFly__ 2201 p->p_intpri = kp->kp_proc.p_usrpri; 2202 p->p_oldpri = kp->kp_proc.p_usrpri; 2203 p->p_pri = kp->kp_proc.p_priority; 2204 #endif /* !__DragonFly__ */ 2205 p->p_policy = SCHED_OTHER; 2206 p->p_clname = "TS"; 2207 #else /* __FreeBSD__ >= 5 */ 2208 if (kp->ki_sflag & PS_INMEM) 2209 p->p_flag |= FL_LOAD; 2210 if (kp->ki_sflag & PS_SWAPPINGOUT) 2211 p->p_flag |= FL_SWAP; 2212 p->p_oldpri = ((double)kp->ki_pri.pri_user - PRI_MIN) / 2213 (PRI_MAX - PRI_MIN) * 60 + 60; 2214 p->p_pri = 40 - ((double)kp->ki_pri.pri_user - PRI_MIN) / 2215 (PRI_MAX - PRI_MIN) * 40; 2216 if (p->p_policy != SCHED_OTHER) 2217 p->p_pri += 100; 2218 #endif /* __FreeBSD__ >= 5 */ 2219 #ifndef __DragonFly__ 2220 p->p_psr = kp->ki_oncpu; 2221 p->p_wchan = (unsigned long)kp->ki_wchan; 2222 #endif /* !__DragonFly__ */ 2223 return OKAY; 2224 } 2225 2226 static enum okay 2227 getproc(const char *dir, struct proc *p, pid_t expected_pid, pid_t lwp) 2228 { 2229 enum okay result; 2230 2231 memset(p, 0, sizeof *p); 2232 if (chdir(dir) == 0) { 2233 if ((result = getproc_status(p, expected_pid)) == OKAY) 2234 if ((result = getproc_cmdline(p)) == OKAY) 2235 if ((result = getproc_map(p)) == OKAY) 2236 if ((result = getproc_scheduler(p)) == 2237 OKAY) 2238 result = getproc_kvm(p); 2239 chdir_to_proc(); 2240 } else 2241 result = STOP; 2242 return result; 2243 } 2244 2245 #else /* !__linux__, !__FreeBSD__, !__DragonFly__ */ 2246 2247 #ifndef __sun 2248 static unsigned long 2249 getmem(void) 2250 { 2251 #ifdef _SC_USEABLE_MEMORY 2252 long usm; 2253 2254 if ((usm = sysconf(_SC_USEABLE_MEMORY)) > 0) 2255 return usm * (pagesize / 1024); 2256 #endif /* _SC_USEABLE_MEMORY */ 2257 return 0; 2258 } 2259 #endif /* !__sun */ 2260 2261 static const char * 2262 concat(const char *dir, const char *base) 2263 { 2264 static char *name; 2265 static long size; 2266 long length; 2267 char *np; 2268 const char *cp; 2269 2270 if ((length = strlen(dir) + strlen(base) + 2) > size) 2271 name = srealloc(name, size = length); 2272 np = name; 2273 for (cp = dir; *cp; cp++) 2274 *np++ = *cp; 2275 *np++ = '/'; 2276 for (cp = base; *cp; cp++) 2277 *np++ = *cp; 2278 *np = '\0'; 2279 return name; 2280 } 2281 2282 static time_t 2283 tv2sec(timestruc_t tv, int mult) 2284 { 2285 return tv.tv_sec*mult + (tv.tv_nsec >= 500000000/mult); 2286 } 2287 2288 static enum okay 2289 getproc_psinfo(const char *dir, struct proc *p, pid_t expected_pid) 2290 { 2291 FILE *fp; 2292 struct psinfo pi; 2293 const char *cp; 2294 char *np; 2295 2296 if ((fp = fopen(concat(dir, "psinfo"), "r")) == NULL) 2297 return STOP; 2298 if (fread(&pi, 1, sizeof pi, fp) != sizeof pi || 2299 pi.pr_pid != expected_pid) { 2300 fclose(fp); 2301 return STOP; 2302 } 2303 fclose(fp); 2304 p->p_pid = pi.pr_pid; 2305 strncpy(p->p_fname, pi.pr_fname, sizeof p->p_fname); 2306 p->p_fname[sizeof p->p_fname - 1] = '\0'; 2307 p->p_ppid = pi.pr_ppid; 2308 p->p_pgid = pi.pr_pgid; 2309 p->p_sid = pi.pr_sid; 2310 p->p_nlwp = pi.pr_nlwp; 2311 p->p_ttydev = pi.pr_ttydev; 2312 p->p_time = tv2sec(pi.pr_time, 1); 2313 #ifdef __sun 2314 p->p_accutime = tv2sec(pi.pr_ctime, 1); 2315 #endif /* __sun */ 2316 p->p_start = tv2sec(pi.pr_start, 1); 2317 p->p_size = pi.pr_size; 2318 p->p_osz = pi.pr_size / kbytes_per_page; 2319 p->p_rssize = pi.pr_rssize; 2320 p->p_orss = pi.pr_rssize / kbytes_per_page; 2321 p->p_addr = (unsigned long)pi.pr_addr; 2322 #ifdef __sun 2323 p->p_pctcpu = (double)pi.pr_pctcpu / 0x8000 * 100; 2324 p->p_pctmem = (double)pi.pr_pctmem / 0x8000 * 100; 2325 #endif /* __sun */ 2326 strncpy(p->p_psargs, pi.pr_psargs, sizeof p->p_psargs); 2327 p->p_psargs[sizeof p->p_psargs - 1] = '\0'; 2328 for (np = p->p_comm, cp = p->p_psargs; *cp && !isblank(*cp); cp++) 2329 *np++ = *cp; 2330 p->p_uid = pi.pr_uid; 2331 p->p_gid = pi.pr_gid; 2332 #ifdef __sun 2333 p->p_euid = pi.pr_euid; 2334 p->p_egid = pi.pr_egid; 2335 #endif /* __sun */ 2336 p->p_lflag = pi.pr_flag; 2337 #if defined (SLOAD) 2338 if (p->p_lflag & SLOAD) 2339 p->p_flag |= FL_LOAD; 2340 #elif defined (P_LOAD) 2341 if (p->p_lflag & P_LOAD) 2342 p->p_flag |= FL_LOAD; 2343 #endif /* SLOAD, P_LOAD */ 2344 #if defined (SSYS) 2345 if (p->p_lflag & SSYS) 2346 p->p_flag |= FL_SYS; 2347 #elif defined (P_SYS) 2348 if (p->p_lflag & P_SYS) 2349 p->p_flag |= FL_SYS; 2350 #endif /* SSYS, P_SYS */ 2351 #if defined (SLOCK) 2352 if (p->p_lflag & SLOCK) 2353 p->p_flag |= FL_LOCK; 2354 #elif defined (P_NOSWAP) 2355 if (p->p_lflag & P_NOSWAP) 2356 p->p_flag |= FL_LOCK; 2357 #endif /* SLOCK, P_NOSWAP */ 2358 #if defined (SPROCTR) 2359 if (p->p_lflag & SPROCTR) 2360 p->p_flag |= FL_TRC; 2361 #elif defined (P_PROCTR) 2362 if (p->p_lflag & P_PROCTR) 2363 p->p_flag |= FL_TRC; 2364 #endif /* SPROCTR, P_PROCTR */ 2365 return OKAY; 2366 } 2367 2368 static enum okay 2369 getproc_lwpsinfo(const char *dir, struct proc *p, pid_t lwp) 2370 { 2371 static char clname[PRCLSZ+1]; 2372 char base[100]; 2373 FILE *fp; 2374 struct lwpsinfo li; 2375 2376 if (p->p_nlwp == 0) { /* zombie process */ 2377 p->p_lstate[0] = p->p_state[0] = 'Z'; 2378 return OKAY; 2379 } 2380 if (lwp != (pid_t)-1) { 2381 snprintf(base, sizeof base, "lwp/%d/lwpsinfo", (int)lwp); 2382 fp = fopen(concat(dir, base), "r"); 2383 } else { 2384 int i; 2385 for (i = 1; i <= 255; i++) { 2386 snprintf(base, sizeof base, "lwp/%d/lwpsinfo", i); 2387 if ((fp = fopen(concat(dir, base), "r")) != NULL || 2388 errno != ENOENT) 2389 break; 2390 } 2391 } 2392 if (fp == NULL) 2393 return STOP; 2394 if (fread(&li, 1, sizeof li, fp) != sizeof li) { 2395 fclose(fp); 2396 return STOP; 2397 } 2398 fclose(fp); 2399 p->p_lwp = li.pr_lwpid; 2400 if (Lflag) { 2401 p->p_time = tv2sec(li.pr_time, 1); 2402 if (li.pr_name[0]) { 2403 strncpy(p->p_fname, li.pr_name, sizeof p->p_fname); 2404 p->p_fname[sizeof p->p_fname - 1] = '\0'; 2405 } 2406 } 2407 p->p_lstate[0] = p->p_state[0] = li.pr_sname; 2408 p->p_intpri = li.pr_pri; 2409 p->p_rtpri = li.pr_pri; 2410 p->p_clname = clname; 2411 memcpy(clname, li.pr_clname, PRCLSZ); 2412 #ifdef __sun 2413 p->p_oldpri = li.pr_oldpri; 2414 #endif /* __sun */ 2415 p->p_pri = li.pr_pri; 2416 p->p_nice = li.pr_nice; 2417 p->p_wchan = (unsigned long)li.pr_wchan; 2418 p->p_psr = li.pr_onpro; 2419 return OKAY; 2420 } 2421 2422 #ifdef __sun 2423 static enum okay 2424 getproc_usage(const char *dir, struct proc *p) 2425 { 2426 FILE *fp; 2427 struct prusage pu; 2428 2429 if ((fp = fopen(concat(dir, "usage"), "r")) == NULL) 2430 return OKAY; 2431 if (fread(&pu, 1, sizeof pu, fp) != sizeof pu) { 2432 fclose(fp); 2433 return STOP; 2434 } 2435 fclose(fp); 2436 p->p_pflts = pu.pr_majf; 2437 p->p_bufr = pu.pr_inblk; 2438 p->p_bufw = pu.pr_oublk; 2439 p->p_mrcv = pu.pr_mrcv; 2440 p->p_msnd = pu.pr_msnd; 2441 p->p_utime = tv2sec(pu.pr_utime, 10); 2442 p->p_ktime = tv2sec(pu.pr_stime, 10); 2443 return OKAY; 2444 } 2445 #else /* !__sun */ 2446 static enum okay 2447 getproc_cred(const char *dir, struct proc *p) 2448 { 2449 FILE *fp; 2450 struct prcred pc; 2451 2452 if ((fp = fopen(concat(dir, "cred"), "r")) == NULL) 2453 /* 2454 * Don't require this, as it may be accessible to root 2455 * only and it's better to have no effective uids than 2456 * to display no content at all. 2457 */ 2458 return OKAY; 2459 if (fread(&pc, 1, sizeof pc, fp) != sizeof pc) { 2460 fclose(fp); 2461 return STOP; 2462 } 2463 fclose(fp); 2464 p->p_euid = pc.pr_euid; 2465 p->p_egid = pc.pr_egid; 2466 return OKAY; 2467 } 2468 #endif /* !__sun */ 2469 2470 static enum okay 2471 getproc_status(const char *dir, struct proc *p) 2472 { 2473 FILE *fp; 2474 struct pstatus ps; 2475 2476 if ((fp = fopen(concat(dir, "status"), "r")) == NULL) 2477 /* 2478 * Don't require this, as it may be accessible to root 2479 * only and the children times are not that important. 2480 */ 2481 return OKAY; 2482 if (fread(&ps, 1, sizeof ps, fp) != sizeof ps) { 2483 fclose(fp); 2484 return STOP; 2485 } 2486 fclose(fp); 2487 p->p_utime = tv2sec(ps.pr_utime, 10); 2488 p->p_ktime = tv2sec(ps.pr_stime, 10); 2489 p->p_accutime = tv2sec(ps.pr_cutime, 1) + tv2sec(ps.pr_cstime, 1); 2490 return OKAY; 2491 } 2492 2493 static enum okay 2494 getproc_lwpstatus(const char *dir, struct proc *p, pid_t lwp) 2495 { 2496 FILE *fp; 2497 char base[100]; 2498 struct lwpstatus ls; 2499 2500 if (p->p_nlwp == 0) /* zombie process */ 2501 return OKAY; 2502 if (lwp != (pid_t)-1) { 2503 snprintf(base, sizeof base, "lwp/%d/lwpstatus", (int)lwp); 2504 fp = fopen(concat(dir, base), "r"); 2505 } else { 2506 int i; 2507 for (i = 1; i <= 20; i++) { 2508 snprintf(base, sizeof base, "lwp/%d/lwpstatus", i); 2509 if ((fp = fopen(concat(dir, base), "r")) != NULL || 2510 errno != ENOENT) 2511 break; 2512 } 2513 } 2514 if (fp == NULL) 2515 /* 2516 * Don't require this, as it may be accessible to root 2517 * only and the process flags are not that important. 2518 */ 2519 return OKAY; 2520 if (fread(&ls, 1, sizeof ls, fp) != sizeof ls) { 2521 fclose(fp); 2522 return STOP; 2523 } 2524 fclose(fp); 2525 if (ls.pr_flags == PR_STOPPED && 2526 (ls.pr_why == PR_SYSENTRY || ls.pr_why == PR_SYSEXIT)) 2527 p->p_flag |= FL_LOCK; 2528 return OKAY; 2529 } 2530 2531 static enum okay 2532 getproc(const char *dir, struct proc *p, pid_t expected_pid, pid_t lwp) 2533 { 2534 enum okay result; 2535 2536 memset(p, 0, sizeof *p); 2537 if ((result = getproc_psinfo(dir, p, expected_pid)) == OKAY) { 2538 if ((result = getproc_status(dir, p)) == OKAY) 2539 #ifdef __sun 2540 if ((result = getproc_usage(dir, p)) == OKAY) 2541 #else /* !__sun */ 2542 if ((result = getproc_cred(dir, p)) == OKAY) 2543 #endif /* !__sun */ 2544 if ((result = getproc_lwpsinfo(dir, p, lwp)) 2545 == OKAY) 2546 result = getproc_lwpstatus(dir, p, lwp); 2547 } else 2548 result = STOP; 2549 return result; 2550 } 2551 2552 static enum okay 2553 getLWPs(const char *dir, struct proc *p, pid_t expected_pid) 2554 { 2555 DIR *Dp; 2556 struct dirent *dp; 2557 unsigned long val; 2558 char *x; 2559 2560 if ((Dp = opendir(concat(dir, "lwp"))) != NULL) { 2561 while ((dp = readdir(Dp)) != NULL) { 2562 if (dp->d_name[0] == '.' && (dp->d_name[1]=='\0' || 2563 (dp->d_name[1]=='.' && 2564 dp->d_name[2]=='\0'))) 2565 continue; 2566 val = strtoul(dp->d_name, &x, 10); 2567 if (*x != 0) 2568 continue; 2569 if (getproc(dir, p, expected_pid, val) == OKAY) { 2570 postproc(p); 2571 if (selectproc(p) == OKAY) 2572 outproc(p); 2573 } 2574 } 2575 closedir(Dp); 2576 return OKAY; 2577 } else 2578 return STOP; 2579 } 2580 2581 #endif /* !__linux__, !__FreeBSD__, !__DragonFly__ */ 2582 2583 static void 2584 postproc(struct proc *p) 2585 { 2586 cleanline(p); 2587 #ifndef __sun 2588 if ((p->p_pctcpu = now - p->p_start) != 0) { 2589 p->p_pctcpu = (double)p->p_time * 100 / p->p_pctcpu; 2590 if (p->p_pctcpu < 0) 2591 p->p_pctcpu = 0; 2592 } 2593 if (totalmem) 2594 p->p_pctmem = (double)p->p_size * 100 / totalmem; 2595 #endif /* !__sun */ 2596 #if !defined (__linux__) && !defined (__sun) && !defined (__FreeBSD__) \ 2597 && !defined (__DragonFly__) 2598 p->p_oldpri = 160 - p->p_pri; 2599 #endif /* !__linux__, !__sun */ 2600 #if !defined (__linux__) && !defined (__FreeBSD__) && !defined (__DragonFly__) 2601 p->p_policy = p->p_clname && strcmp(p->p_clname, "TS") ? 2602 SCHED_RR : SCHED_OTHER; 2603 #endif /* !__linux__, !__FreeBSD__, !__DragonFly__ */ 2604 } 2605 #endif /* !__hpux, !_AIX, !__NetBSD__, !__OpenBSD__, !__APPLE__ */ 2606 2607 static enum okay 2608 selectproc(struct proc *p) 2609 { 2610 struct criterion *ct; 2611 2612 for (ct = c0; ct; ct = ct->c_nxt) { 2613 if (ucb_rflag && p->p_lstate[0] != 'R') 2614 continue; 2615 switch (ct->c_typ) { 2616 case CR_ALL: 2617 return OKAY; 2618 case CR_ALL_WITH_TTY: 2619 if (p->p_lstate[0] == 'Z') 2620 break; 2621 #ifndef UCB 2622 if (p->p_pid == p->p_sid) 2623 break; 2624 #endif /* !UCB */ 2625 if (p->p_ttydev != (dev_type)PRNODEV) 2626 return OKAY; 2627 break; 2628 case CR_ALL_BUT_SESSION_LEADERS: 2629 if (p->p_pid != p->p_sid) 2630 return OKAY; 2631 break; 2632 case CR_WITHOUT_TTY: 2633 if (p->p_ttydev == (dev_type)PRNODEV || 2634 p->p_lstate[0] == 'Z') 2635 return OKAY; 2636 break; 2637 case CR_NO_TTY_NO_SESSION_LEADER: 2638 if (p->p_ttydev == (dev_type)PRNODEV && 2639 p->p_pid != p->p_sid && 2640 p->p_lstate[0] != 'Z') 2641 return OKAY; 2642 break; 2643 case CR_PROCESS_GROUP: 2644 #if defined (SUS) || defined (UCB) 2645 if (p->p_sid == ct->c_val) 2646 return OKAY; 2647 #else /* !SUS, !UCB */ 2648 if (p->p_pgid == ct->c_val) 2649 return OKAY; 2650 #endif /* !SUS, !UCB */ 2651 break; 2652 case CR_REAL_GID: 2653 if (p->p_gid == ct->c_val) 2654 return OKAY; 2655 break; 2656 case CR_PROCESS_ID: 2657 if (p->p_pid == ct->c_val) 2658 return OKAY; 2659 break; 2660 case CR_TTY_DEVICE: 2661 if (/*p->p_ttydev != (dev_type)PRNODEV &&*/ 2662 p->p_ttydev == ct->c_val && 2663 p->p_lstate[0] != 'Z') 2664 return OKAY; 2665 break; 2666 case CR_SESSION_LEADER: 2667 if (p->p_sid == ct->c_val) 2668 return OKAY; 2669 break; 2670 case CR_EFF_UID: 2671 if (p->p_euid == ct->c_val) 2672 return OKAY; 2673 break; 2674 case CR_REAL_UID: 2675 if (p->p_uid == ct->c_val) 2676 return OKAY; 2677 break; 2678 case CR_ADD_UNINTERESTING: 2679 if (p->p_lstate[0] != 'Z' && 2680 p->p_euid == myuid && 2681 p->p_ttydev != (dev_type)PRNODEV && 2682 p->p_ttydev == myproc.p_ttydev) 2683 return OKAY; 2684 break; 2685 case CR_DEFAULT: 2686 if (p->p_lstate[0] != 'Z' && 2687 #if defined (SUS) || defined (UCB) 2688 p->p_euid == myuid && 2689 #endif /* SUS || UCB */ 2690 #ifdef UCB 2691 p->p_pid != p->p_sid && 2692 p->p_ttydev != (dev_type)PRNODEV && 2693 #endif /* UCB */ 2694 p->p_ttydev == myproc.p_ttydev) 2695 return OKAY; 2696 break; 2697 } 2698 } 2699 return STOP; 2700 } 2701 2702 #if !defined (__hpux) && !defined (_AIX) && !defined (__NetBSD__) && \ 2703 !defined (__OpenBSD__) && !defined (__APPLE__) 2704 static void 2705 do_procs(void) 2706 { 2707 struct proc p; 2708 DIR *Dp; 2709 struct dirent *dp; 2710 unsigned long val; 2711 char *x; 2712 2713 if ((Dp = opendir(".")) != NULL) { 2714 while ((dp = readdir(Dp)) != NULL) { 2715 if (dp->d_name[0] == '.' && (dp->d_name[1] == '\0' || 2716 (dp->d_name[1] == '.' && 2717 dp->d_name[2] == '\0'))) 2718 continue; 2719 val = strtoul(dp->d_name, &x, 10); 2720 if (*x != 0) 2721 continue; 2722 #if !defined (__FreeBSD__) && !defined (__DragonFly__) 2723 if (Lflag) 2724 if (getLWPs(dp->d_name, &p, val) == OKAY) 2725 continue; 2726 #endif /* !__FreeBSD__, !__DragonFly__ */ 2727 if (getproc(dp->d_name, &p, val, -1) == OKAY) { 2728 postproc(&p); 2729 if (selectproc(&p) == OKAY) 2730 outproc(&p); 2731 } 2732 } 2733 closedir(Dp); 2734 } 2735 } 2736 #elif defined (__hpux) 2737 2738 static unsigned long 2739 getmem(void) 2740 { 2741 return 0; 2742 } 2743 2744 static void 2745 getproc(struct proc *p, struct pst_status *pst) 2746 { 2747 char *cp, *np; 2748 2749 memset(p, 0, sizeof *p); 2750 p->p_pid = pst->pst_pid; 2751 strncpy(p->p_fname, pst->pst_ucomm, sizeof p->p_fname); 2752 p->p_fname[sizeof p->p_fname - 1] = '\0'; 2753 strncpy(p->p_psargs, pst->pst_cmd, sizeof p->p_psargs); 2754 p->p_psargs[sizeof p->p_psargs - 1] = '\0'; 2755 for (np = p->p_comm, cp = p->p_psargs; *cp && !isblank(*cp); cp++) 2756 *np++ = *cp; 2757 p->p_lstate[0] = pst->pst_stat; 2758 p->p_ppid = pst->pst_ppid; 2759 p->p_pgid = pst->pst_pgrp; 2760 p->p_sid = pst->pst_sid; 2761 /*p->p_lwp = pst->pst_lwpid;*/ 2762 if (pst->pst_term.psd_major != -1 || pst->pst_term.psd_minor != -1) 2763 p->p_ttydev = makedev(pst->pst_term.psd_major, 2764 pst->pst_term.psd_minor); 2765 p->p_lflag = pst->pst_flag; 2766 p->p_time = pst->pst_utime + pst->pst_stime; 2767 p->p_accutime = pst->pst_utime + pst->pst_stime + 2768 pst->pst_child_utime.pst_sec + 2769 (pst->pst_child_utime.pst_usec > + 500000) + 2770 pst->pst_child_stime.pst_sec + 2771 (pst->pst_child_stime.pst_usec > + 500000); 2772 p->p_utime = pst->pst_utime * 10; 2773 p->p_ktime = pst->pst_stime * 10; 2774 p->p_intpri = p->p_rtpri = pst->pst_pri; 2775 p->p_policy = pst->pst_schedpolicy; 2776 p->p_c = pst->pst_cpu; 2777 p->p_nice = pst->pst_nice; 2778 p->p_nlwp = pst->pst_nlwps; 2779 p->p_start = pst->pst_start; 2780 p->p_osz = pst->pst_dsize + pst->pst_tsize + pst->pst_ssize; 2781 p->p_size = p->p_osz * kbytes_per_page; 2782 p->p_orss = pst->pst_rssize; 2783 p->p_rssize = p->p_orss * kbytes_per_page; 2784 p->p_pflts = pst->pst_majorfaults; 2785 p->p_mrcv = pst->pst_msgrcv; 2786 p->p_msnd = pst->pst_msgsnd; 2787 p->p_addr = pst->pst_addr; 2788 p->p_wchan = pst->pst_wchan; 2789 p->p_psr = pst->pst_procnum; 2790 p->p_pctcpu = pst->pst_pctcpu; 2791 p->p_uid = pst->pst_uid; 2792 p->p_euid = pst->pst_euid; 2793 p->p_gid = pst->pst_gid; 2794 p->p_egid = pst->pst_egid; 2795 } 2796 2797 static void 2798 getlwp(struct proc *p, struct lwp_status *lwp) 2799 { 2800 p->p_lwp = lwp->lwp_lwpid; 2801 p->p_intpri = p->p_rtpri = lwp->lwp_pri; 2802 p->p_c = lwp->lwp_cpu; 2803 p->p_wchan = lwp->lwp_wchan; 2804 p->p_psr = lwp->lwp_cpu; 2805 p->p_start = lwp->lwp_start; 2806 p->p_lstate[0] = lwp->lwp_stat; 2807 p->p_policy = lwp->lwp_schedpolicy; 2808 p->p_utime = lwp->lwp_utime * 10; 2809 p->p_ktime = lwp->lwp_stime * 10; 2810 p->p_pflts = lwp->lwp_majorfaults; 2811 p->p_mrcv = lwp->lwp_msgrcv; 2812 p->p_msnd = lwp->lwp_msgsnd; 2813 /*p->p_pctcpu = lwp->lwp_pctcpu;*/ 2814 } 2815 2816 static void 2817 postproc(struct proc *p) 2818 { 2819 cleanline(p); 2820 switch (p->p_lstate[0]) { 2821 case PS_SLEEP: 2822 p->p_lstate[0] = 'S'; 2823 break; 2824 case PS_RUN: 2825 p->p_lstate[0] = 'R'; 2826 break; 2827 case PS_STOP: 2828 p->p_lstate[0] = 'T'; 2829 break; 2830 case PS_ZOMBIE: 2831 p->p_lstate[0] = 'Z'; 2832 break; 2833 case PS_IDLE: 2834 case PS_OTHER: 2835 default: 2836 p->p_lstate[0] = 'I'; 2837 break; 2838 } 2839 p->p_state[0] = p->p_lstate[0]; 2840 if (p->p_lflag & PS_INCORE) 2841 p->p_flag |= FL_LOAD; 2842 if (p->p_lflag & PS_SYS) 2843 p->p_flag |= FL_SYS; 2844 if (p->p_lflag & PS_LOCKED) 2845 p->p_flag |= FL_LOCK; 2846 if (p->p_lflag & PS_TRACE) 2847 p->p_flag |= FL_TRC; 2848 if (p->p_lflag & PS_TRACE2) 2849 p->p_flag |= FL_WTED; 2850 p->p_oldpri = p->p_intpri; 2851 p->p_pri = 220 - p->p_intpri; 2852 switch (p->p_policy) { 2853 case PS_TIMESHARE: 2854 p->p_clname = "TS"; 2855 p->p_policy = SCHED_OTHER; 2856 p->p_pri /= 2; 2857 break; 2858 case PS_RTPRIO: 2859 case PS_RR: 2860 case PS_RR2: 2861 #ifdef S42 2862 p->p_clname = "FP"; 2863 #else 2864 p->p_clname = "RT"; 2865 #endif 2866 p->p_policy = SCHED_RR; 2867 p->p_pri += 100; 2868 break; 2869 case PS_FIFO: 2870 p->p_clname = "FF"; 2871 p->p_policy = SCHED_FIFO; 2872 p->p_pri += 100; 2873 break; 2874 case PS_NOAGE: 2875 p->p_clname = "FC"; 2876 p->p_policy = SCHED_NOAGE; 2877 p->p_pri /= 2; 2878 break; 2879 default: 2880 p->p_clname = "??"; 2881 } 2882 } 2883 2884 #define burst ((size_t)10) 2885 2886 static void 2887 getLWPs(struct proc *p) 2888 { 2889 struct lwp_status lwp[burst]; 2890 int i, count; 2891 int idx = 0; 2892 2893 while ((count = pstat_getlwp(lwp, sizeof *lwp, burst, idx, p->p_pid)) 2894 > 0) { 2895 for (i = 0; i < count; i++) { 2896 getlwp(p, &lwp[i]); 2897 postproc(p); 2898 if (selectproc(p) == OKAY) 2899 outproc(p); 2900 } 2901 idx = lwp[count-1].lwp_idx + 1; 2902 } 2903 } 2904 2905 static void 2906 do_procs(void) 2907 { 2908 struct proc p; 2909 struct pst_status pst[burst]; 2910 int i, count; 2911 int idx = 0; 2912 2913 while ((count = pstat_getproc(pst, sizeof *pst, burst, idx)) > 0) { 2914 for (i = 0; i < count; i++) { 2915 getproc(&p, &pst[i]); 2916 if (Lflag && p.p_nlwp > 1) 2917 getLWPs(&p); 2918 else { 2919 postproc(&p); 2920 if (selectproc(&p) == OKAY) 2921 outproc(&p); 2922 } 2923 } 2924 idx = pst[count-1].pst_idx + 1; 2925 } 2926 } 2927 2928 #elif defined (_AIX) 2929 2930 static unsigned long 2931 getmem(void) 2932 { 2933 return 0; 2934 } 2935 2936 static time_t 2937 tv2sec(struct timeval64 tv, int mult) 2938 { 2939 return tv.tv_sec*mult + (tv.tv_usec >= 500000/mult); 2940 } 2941 2942 static void 2943 getproc(struct proc *p, struct procentry64 *pi) 2944 { 2945 char args[100], *ap, *cp, *xp; 2946 2947 memset(p, 0, sizeof *p); 2948 p->p_pid = pi->pi_pid; 2949 strncpy(p->p_fname, pi->pi_comm, sizeof p->p_fname); 2950 p->p_fname[sizeof p->p_fname - 1] = '\0'; 2951 p->p_lstate[0] = pi->pi_state; 2952 p->p_ppid = pi->pi_ppid; 2953 p->p_pgid = pi->pi_pgrp; 2954 p->p_sid = pi->pi_sid; 2955 p->p_ttydev = pi->pi_ttyp ? pi->pi_ttyd : PRNODEV; 2956 p->p_lflag = pi->pi_flags; 2957 p->p_time = pi->pi_utime + pi->pi_stime; 2958 p->p_accutime = pi->pi_utime + pi->pi_stime; 2959 p->p_utime = pi->pi_utime * 10; 2960 p->p_ktime = pi->pi_stime * 10; 2961 p->p_intpri = pi->pi_pri; 2962 p->p_c = pi->pi_cpu; 2963 p->p_nice = pi->pi_nice; 2964 p->p_nlwp = pi->pi_thcount; 2965 p->p_start = pi->pi_start; 2966 p->p_osz = pi->pi_size; 2967 p->p_orss = pi->pi_drss + pi->pi_trss; 2968 p->p_pflts = pi->pi_majflt; 2969 p->p_addr = pi->pi_adspace; 2970 p->p_uid = pi->pi_uid; 2971 p->p_euid = pi->pi_cred.crx_uid; 2972 p->p_gid = pi->pi_cred.crx_rgid; 2973 p->p_egid = pi->pi_cred.crx_gid; 2974 if (getargs(pi, sizeof *pi, args, sizeof args) == 0) { 2975 ap = args; 2976 cp = p->p_psargs; 2977 xp = p->p_comm; 2978 while (cp < &p->p_psargs[sizeof p->p_psargs - 1]) { 2979 if (ap[0] == '\0') { 2980 if (ap[1] == '\0') 2981 break; 2982 *cp++ = ' '; 2983 if (xp) { 2984 *xp = '\0'; 2985 xp = NULL; 2986 } 2987 } else { 2988 *cp++ = *ap; 2989 if (xp) 2990 *xp++ = *ap; 2991 } 2992 ap++; 2993 } 2994 *cp = '\0'; 2995 if (xp) 2996 *xp = '\0'; 2997 } 2998 } 2999 3000 static void 3001 postproc(struct proc *p) 3002 { 3003 char *np, *cp; 3004 3005 if (p->p_psargs[0] == '\0') { 3006 strncpy(p->p_psargs, p->p_fname, sizeof p->p_psargs); 3007 p->p_psargs[sizeof p->p_psargs - 1] = '\0'; 3008 } 3009 if (p->p_comm[0] == '\0') { 3010 for (np = p->p_comm, cp = p->p_psargs; 3011 *cp && !isblank(*cp); cp++) 3012 *np++ = *cp; 3013 } 3014 cleanline(p); 3015 p->p_clname = "TS"; 3016 switch (p->p_lstate[0]) { 3017 case SSWAP: 3018 p->p_flag |= FL_SWAP; 3019 /*FALLTHRU*/ 3020 default: 3021 case SIDL: 3022 p->p_state[0] = 'I'; 3023 break; 3024 case SZOMB: 3025 p->p_state[0] = 'Z'; 3026 break; 3027 case SSTOP: 3028 p->p_state[0] = 'T'; 3029 break; 3030 case SACTIVE: 3031 p->p_state[0] = 'R'; 3032 break; 3033 } 3034 p->p_lstate[0] = p->p_state[0]; 3035 if (p->p_lflag & SLOAD) 3036 p->p_flag |= FL_LOAD; 3037 if (p->p_lflag & SNOSWAP) 3038 p->p_flag |= FL_LOCK; 3039 if (p->p_lflag & SKPROC) 3040 p->p_flag |= FL_SYS; 3041 if (p->p_lflag & SFIXPRI) 3042 p->p_clname = "RT"; 3043 p->p_oldpri = p->p_intpri / 2; 3044 p->p_pri = 255 - p->p_intpri; 3045 p->p_size = p->p_osz * kbytes_per_page; 3046 p->p_rssize = p->p_orss * kbytes_per_page; 3047 } 3048 3049 static void 3050 getlwp(struct proc *p, struct thrdentry64 *ti) 3051 { 3052 p->p_lwp = ti->ti_tid; 3053 p->p_psr = ti->ti_cpuid; 3054 p->p_wchan = ti->ti_wchan; 3055 if (Lflag) { 3056 p->p_intpri = ti->ti_pri; 3057 p->p_c = ti->ti_cpu; 3058 p->p_policy = ti->ti_policy; 3059 p->p_utime = tv2sec(ti->ti_ru.ru_utime, 10); 3060 p->p_ktime = tv2sec(ti->ti_ru.ru_stime, 10); 3061 p->p_time = (p->p_utime + p->p_ktime) / 10; 3062 } 3063 p->p_pflts = ti->ti_ru.ru_majflt; 3064 p->p_bufr = ti->ti_ru.ru_inblock; 3065 p->p_bufw = ti->ti_ru.ru_oublock; 3066 p->p_mrcv = ti->ti_ru.ru_msgrcv; 3067 p->p_msnd = ti->ti_ru.ru_msgsnd; 3068 } 3069 3070 #define burst ((size_t)10) 3071 3072 static void 3073 getLWPs(struct proc *p) 3074 { 3075 struct thrdentry64 ti[burst]; 3076 tid64_t idx = 0; 3077 int i, count; 3078 3079 while ((count=getthrds64(p->p_pid, ti, sizeof *ti, &idx, burst)) > 0) { 3080 for (i = 0; i < count; i++) { 3081 getlwp(p, &ti[i]); 3082 postproc(p); 3083 if (selectproc(p) == OKAY) 3084 outproc(p); 3085 } 3086 if (count < burst) 3087 break; 3088 } 3089 } 3090 3091 static void 3092 oneLWP(struct proc *p) 3093 { 3094 struct thrdentry64 ti; 3095 tid64_t idx = 0; 3096 3097 if (getthrds64(p->p_pid, &ti, sizeof ti, &idx, 1) == 1) 3098 getlwp(p, &ti); 3099 } 3100 3101 static void 3102 do_procs(void) 3103 { 3104 struct proc p; 3105 struct procentry64 pi[burst]; 3106 pid_t idx = 0; 3107 int i, count; 3108 3109 while ((count = getprocs64(pi, sizeof *pi, NULL, 0, &idx, burst)) > 0) { 3110 for (i = 0; i < count; i++) { 3111 getproc(&p, &pi[i]); 3112 if (Lflag && p.p_nlwp > 1) 3113 getLWPs(&p); 3114 else { 3115 oneLWP(&p); 3116 postproc(&p); 3117 if (selectproc(&p) == OKAY) 3118 outproc(&p); 3119 } 3120 } 3121 if (count < burst) 3122 break; 3123 } 3124 } 3125 3126 #elif defined (__OpenBSD__) 3127 3128 #include <uvm/uvm_extern.h> 3129 3130 static unsigned long 3131 getmem(void) 3132 { 3133 return 0; 3134 } 3135 3136 static time_t 3137 tv2sec(long sec, long usec, int mult) 3138 { 3139 return sec*mult + (usec >= 500000/mult); 3140 } 3141 3142 static void 3143 getproc(struct proc *p, struct kinfo_proc *kp) 3144 { 3145 memset(p, 0, sizeof *p); 3146 p->p_pid = kp->kp_proc.p_pid; 3147 strncpy(p->p_fname, kp->kp_proc.p_comm, sizeof p->p_fname); 3148 p->p_fname[sizeof p->p_fname - 1] = '\0'; 3149 p->p_lstate[0] = kp->kp_proc.p_stat; 3150 p->p_ppid = kp->kp_eproc.e_ppid; 3151 p->p_pgid = kp->kp_eproc.e_pgid; 3152 p->p_sid = kp->kp_eproc.e_tpgid; /* ? */ 3153 p->p_ttydev = kp->kp_eproc.e_tdev; 3154 p->p_lflag = kp->kp_proc.p_flag; 3155 p->p_time = tv2sec(kp->kp_eproc.e_pstats.p_ru.ru_utime.tv_sec + 3156 kp->kp_eproc.e_pstats.p_ru.ru_stime.tv_sec, 3157 kp->kp_eproc.e_pstats.p_ru.ru_utime.tv_usec + 3158 kp->kp_eproc.e_pstats.p_ru.ru_stime.tv_usec, 1); 3159 p->p_accutime = p->p_time + 3160 tv2sec(kp->kp_eproc.e_pstats.p_cru.ru_utime.tv_sec + 3161 kp->kp_eproc.e_pstats.p_cru.ru_stime.tv_sec, 3162 kp->kp_eproc.e_pstats.p_cru.ru_utime.tv_usec + 3163 kp->kp_eproc.e_pstats.p_cru.ru_stime.tv_usec, 3164 1); 3165 p->p_utime = tv2sec(kp->kp_eproc.e_pstats.p_ru.ru_utime.tv_sec, 3166 kp->kp_eproc.e_pstats.p_ru.ru_utime.tv_usec, 10); 3167 p->p_ktime = tv2sec(kp->kp_eproc.e_pstats.p_ru.ru_stime.tv_sec, 3168 kp->kp_eproc.e_pstats.p_ru.ru_stime.tv_usec, 10); 3169 p->p_intpri = kp->kp_proc.p_usrpri; 3170 p->p_rtpri = kp->kp_proc.p_priority; 3171 p->p_policy = SCHED_OTHER; 3172 p->p_c = kp->kp_proc.p_cpticks; 3173 p->p_nice = kp->kp_proc.p_nice; 3174 p->p_nlwp = 1; 3175 p->p_start = tv2sec(kp->kp_eproc.e_pstats.p_start.tv_sec, 3176 kp->kp_eproc.e_pstats.p_start.tv_usec, 1); 3177 p->p_osz = kp->kp_eproc.e_vm.vm_tsize + kp->kp_eproc.e_vm.vm_dsize + 3178 kp->kp_eproc.e_vm.vm_ssize; 3179 p->p_orss = kp->kp_eproc.e_vm.vm_rssize; 3180 p->p_pflts = kp->kp_eproc.e_pstats.p_ru.ru_majflt; 3181 p->p_bufr = kp->kp_eproc.e_pstats.p_ru.ru_inblock; 3182 p->p_bufw = kp->kp_eproc.e_pstats.p_ru.ru_oublock; 3183 p->p_mrcv = kp->kp_eproc.e_pstats.p_ru.ru_msgrcv; 3184 p->p_msnd = kp->kp_eproc.e_pstats.p_ru.ru_msgsnd; 3185 p->p_addr = (unsigned long)kp->kp_proc.p_addr; 3186 p->p_wchan = (unsigned long)kp->kp_proc.p_wchan; 3187 p->p_pctcpu = kp->kp_proc.p_pctcpu; 3188 p->p_clname = "TS"; 3189 p->p_uid = kp->kp_eproc.e_pcred.p_ruid; 3190 p->p_euid = kp->kp_eproc.e_ucred.cr_uid; 3191 p->p_gid = kp->kp_eproc.e_pcred.p_rgid; 3192 p->p_egid = kp->kp_eproc.e_ucred.cr_gid; 3193 } 3194 3195 static void 3196 getargv(struct proc *p, struct kinfo_proc *kp, kvm_t *kt) 3197 { 3198 char **args; 3199 char *ap, *pp, *xp; 3200 3201 if ((args = kvm_getargv(kt, kp, sizeof p->p_psargs)) == NULL) { 3202 strncpy(p->p_psargs, p->p_fname, sizeof p->p_psargs); 3203 p->p_psargs[sizeof p->p_psargs - 1] = '\0'; 3204 for (ap = p->p_comm, pp = p->p_psargs; 3205 *pp && !isblank(*pp); pp++) 3206 *ap++ = *pp; 3207 return; 3208 } 3209 ap = args[0]; 3210 xp = p->p_comm; 3211 for (pp = p->p_psargs; pp < &p->p_psargs[sizeof p->p_psargs-1]; pp++) { 3212 if (*ap == '\0') { 3213 *pp = ' '; 3214 if (xp) { 3215 *xp = '\0'; 3216 xp = NULL; 3217 } 3218 ap = *++args; 3219 if (ap == NULL) 3220 break; 3221 } else { 3222 if (xp) 3223 *xp++ = *ap; 3224 *pp = *ap++; 3225 } 3226 } 3227 } 3228 3229 static void 3230 postproc(struct proc *p) 3231 { 3232 cleanline(p); 3233 switch (p->p_lstate[0]) { 3234 default: 3235 case SIDL: 3236 p->p_state[0] = 'I'; 3237 break; 3238 case SRUN: 3239 p->p_state[0] = 'R'; 3240 break; 3241 case SSLEEP: 3242 p->p_state[0] = 'S'; 3243 break; 3244 case SSTOP: 3245 p->p_state[0] = 'T'; 3246 break; 3247 case SZOMB: 3248 case SDEAD: 3249 p->p_state[0] = 'Z'; 3250 break; 3251 } 3252 p->p_lstate[0] = p->p_state[0]; 3253 if ((p->p_lflag & P_CONTROLT) == 0) 3254 p->p_ttydev = PRNODEV; 3255 if ((p->p_lflag & P_INMEM) == 0) 3256 p->p_flag |= FL_SWAP; 3257 else 3258 p->p_flag |= FL_LOAD; 3259 if (p->p_lflag & P_SYSTEM) 3260 p->p_flag |= FL_SYS; 3261 if ((p->p_lflag & P_SINTR) == 0) 3262 p->p_flag |= FL_LOCK; 3263 p->p_pri = p->p_rtpri; 3264 p->p_oldpri = p->p_intpri + 40; 3265 p->p_size = p->p_osz * kbytes_per_page; 3266 p->p_rssize = p->p_orss * kbytes_per_page; 3267 } 3268 3269 static void 3270 do_procs(void) 3271 { 3272 struct proc p; 3273 kvm_t *kt; 3274 struct kinfo_proc *kp; 3275 int i, cnt; 3276 pid_t mypid = getpid(); 3277 int gotme = 0; 3278 3279 if ((kt = kvm_open(NULL, NULL, NULL, KVM_NO_FILES, "kvm_open")) == NULL) 3280 exit(1); 3281 kp = kvm_getprocs(kt, KERN_PROC_ALL, 0, &cnt); 3282 i = cnt; 3283 while (--i >= 0) { 3284 one: if (kp[i].kp_proc.p_pid == mypid) 3285 gotme = 1; 3286 getproc(&p, &kp[i]); 3287 getargv(&p, &kp[i], kt); 3288 postproc(&p); 3289 if (selectproc(&p) == OKAY) 3290 outproc(&p); 3291 } 3292 if (gotme == 0) { 3293 kp = kvm_getprocs(kt, KERN_PROC_PID, mypid, &cnt); 3294 goto one; 3295 } 3296 kvm_close(kt); 3297 } 3298 3299 #elif defined (__NetBSD__) 3300 3301 static unsigned long 3302 getmem(void) 3303 { 3304 return 0; 3305 } 3306 3307 static time_t 3308 tv2sec(long sec, long usec, int mult) 3309 { 3310 return sec*mult + (usec >= 500000/mult); 3311 } 3312 3313 static void 3314 getproc(struct proc *p, struct kinfo_proc2 *kp) 3315 { 3316 memset(p, 0, sizeof *p); 3317 p->p_pid = kp->p_pid; 3318 strncpy(p->p_fname, kp->p_comm, sizeof p->p_fname); 3319 p->p_fname[sizeof p->p_fname - 1] = '\0'; 3320 p->p_lstate[0] = kp->p_stat; 3321 p->p_ppid = kp->p_ppid; 3322 p->p_pgid = kp->p__pgid; 3323 p->p_sid = kp->p_sid; 3324 p->p_ttydev = kp->p_tdev; 3325 p->p_lflag = kp->p_flag; 3326 p->p_time = tv2sec(kp->p_uutime_sec + kp->p_ustime_sec, 3327 kp->p_uutime_usec + kp->p_ustime_usec, 1); 3328 p->p_accutime = p->p_time + tv2sec(kp->p_uctime_sec, 3329 kp->p_uctime_usec, 1); 3330 p->p_utime = tv2sec(kp->p_uutime_sec, kp->p_uutime_usec, 10); 3331 p->p_ktime = tv2sec(kp->p_ustime_sec, kp->p_ustime_usec, 10); 3332 p->p_intpri = kp->p_usrpri; 3333 p->p_rtpri = kp->p_priority; 3334 p->p_policy = SCHED_OTHER; 3335 p->p_c = kp->p_cpticks; 3336 p->p_nice = kp->p_nice; 3337 p->p_nlwp = 1; 3338 p->p_start = tv2sec(kp->p_ustart_sec, kp->p_ustart_usec, 1); 3339 p->p_osz = kp->p_vm_tsize + kp->p_vm_dsize + kp->p_vm_ssize; 3340 p->p_orss = kp->p_vm_rssize; 3341 p->p_pflts = kp->p_uru_majflt; 3342 p->p_bufr = kp->p_uru_inblock; 3343 p->p_bufw = kp->p_uru_oublock; 3344 p->p_mrcv = kp->p_uru_msgrcv; 3345 p->p_msnd = kp->p_uru_msgsnd; 3346 p->p_addr = kp->p_addr; 3347 p->p_wchan = kp->p_wchan; 3348 p->p_psr = kp->p_cpuid; 3349 p->p_pctcpu = kp->p_pctcpu; 3350 p->p_clname = "TS"; 3351 p->p_uid = kp->p_ruid; 3352 p->p_euid = kp->p_uid; 3353 p->p_gid = kp->p_rgid; 3354 p->p_egid = kp->p_gid; 3355 } 3356 3357 static void 3358 getargv(struct proc *p, struct kinfo_proc2 *kp, kvm_t *kt) 3359 { 3360 char **args; 3361 char *ap, *pp, *xp; 3362 3363 if ((args = kvm_getargv2(kt, kp, sizeof p->p_psargs)) == NULL) { 3364 strncpy(p->p_psargs, p->p_fname, sizeof p->p_psargs); 3365 p->p_psargs[sizeof p->p_psargs - 1] = '\0'; 3366 for (ap = p->p_comm, pp = p->p_psargs; 3367 *pp && !isblank(*pp); pp++) 3368 *ap++ = *pp; 3369 return; 3370 } 3371 ap = args[0]; 3372 xp = p->p_comm; 3373 for (pp = p->p_psargs; pp < &p->p_psargs[sizeof p->p_psargs-1]; pp++) { 3374 if (*ap == '\0') { 3375 *pp = ' '; 3376 if (xp) { 3377 *xp = '\0'; 3378 xp = NULL; 3379 } 3380 ap = *++args; 3381 if (ap == NULL) 3382 break; 3383 } else { 3384 if (xp) 3385 *xp++ = *ap; 3386 *pp = *ap++; 3387 } 3388 } 3389 } 3390 3391 static void 3392 postproc(struct proc *p) 3393 { 3394 cleanline(p); 3395 switch (p->p_lstate[0]) { 3396 default: 3397 case SIDL: 3398 p->p_state[0] = 'I'; 3399 break; 3400 case SRUN: 3401 p->p_state[0] = 'R'; 3402 break; 3403 case SSLEEP: 3404 p->p_state[0] = 'S'; 3405 break; 3406 case SSTOP: 3407 p->p_state[0] = 'T'; 3408 break; 3409 case SZOMB: 3410 case SDEAD: 3411 p->p_state[0] = 'Z'; 3412 break; 3413 case SONPROC: 3414 p->p_state[0] = 'O'; 3415 break; 3416 } 3417 p->p_lstate[0] = p->p_state[0]; 3418 if ((p->p_lflag & P_CONTROLT) == 0) 3419 p->p_ttydev = PRNODEV; 3420 if ((p->p_lflag & P_INMEM) == 0) 3421 p->p_flag |= FL_SWAP; 3422 else 3423 p->p_flag |= FL_LOAD; 3424 if (p->p_lflag & P_SYSTEM) 3425 p->p_flag |= FL_SYS; 3426 if ((p->p_lflag & P_SINTR) == 0) 3427 p->p_flag |= FL_LOCK; 3428 p->p_pri = p->p_rtpri; 3429 p->p_oldpri = p->p_intpri + 40; 3430 p->p_size = p->p_osz * kbytes_per_page; 3431 p->p_rssize = p->p_orss * kbytes_per_page; 3432 } 3433 3434 static void 3435 do_procs(void) 3436 { 3437 struct proc p; 3438 kvm_t *kt; 3439 struct kinfo_proc2 *kp; 3440 int i, cnt; 3441 pid_t mypid = getpid(); 3442 int gotme = 0; 3443 3444 if ((kt = kvm_open(NULL, NULL, NULL, KVM_NO_FILES, "kvm_open")) == NULL) 3445 exit(1); 3446 kp = kvm_getproc2(kt, KERN_PROC_ALL, 0, sizeof *kp, &cnt); 3447 i = cnt; 3448 while (--i >= 0) { 3449 one: if (kp[i].p_pid == mypid) 3450 gotme = 1; 3451 getproc(&p, &kp[i]); 3452 getargv(&p, &kp[i], kt); 3453 postproc(&p); 3454 if (selectproc(&p) == OKAY) 3455 outproc(&p); 3456 } 3457 if (gotme == 0) { 3458 kp = kvm_getproc2(kt, KERN_PROC_PID, mypid, sizeof *kp, &cnt); 3459 goto one; 3460 } 3461 kvm_close(kt); 3462 } 3463 3464 #elif defined (__APPLE__) 3465 3466 typedef struct kinfo_proc kinfo_proc; 3467 3468 static int 3469 GetBSDProcessList(pid_t thepid, struct kinfo_proc **procList, size_t *procCount) 3470 /* derived from http://developer.apple.com/qa/qa2001/qa1123.html */ 3471 /* Returns a list of all BSD processes on the system. This routine 3472 allocates the list and puts it in *procList and a count of the 3473 number of entries in *procCount. You are responsible for freeing 3474 this list (use "free" from System framework). 3475 all classic apps run in one process 3476 On success, the function returns 0. 3477 On error, the function returns a BSD errno value. 3478 Preconditions: 3479 assert( procList != NULL); 3480 assert(*procList == NULL); 3481 assert(procCount != NULL); 3482 Postconditions: 3483 assert( (err == 0) == (*procList != NULL) ); 3484 */ 3485 { 3486 int err; 3487 struct kinfo_proc *result; 3488 int mib[4]; 3489 size_t length; 3490 3491 mib[0] = CTL_KERN; 3492 mib[1] = KERN_PROC; 3493 if (thepid == 0) { 3494 mib[2] = KERN_PROC_ALL; 3495 mib[3] = 0; 3496 } else { 3497 mib[2] = KERN_PROC_PID; 3498 mib[3] = thepid; 3499 } 3500 /* We start by calling sysctl with result == NULL and length == 0. 3501 That will succeed, and set length to the appropriate length. 3502 We then allocate a buffer of that size and call sysctl again 3503 with that buffer. 3504 */ 3505 length = 0; 3506 err = sysctl(mib, 4, NULL, &length, NULL, 0); 3507 if (err == -1) 3508 err = errno; 3509 if (err == 0) { 3510 result = smalloc(length); 3511 err = sysctl(mib, 4, result, &length, NULL, 0); 3512 if (err == -1) 3513 err = errno; 3514 if (err == ENOMEM) { 3515 free(result); /* clean up */ 3516 result = NULL; 3517 } 3518 } 3519 *procList = result; 3520 *procCount = err == 0 ? length / sizeof **procList : 0; 3521 return err; 3522 } 3523 3524 static time_t 3525 tv2sec(time_value_t *tv, int mult) 3526 { 3527 return tv->seconds*mult + (tv->microseconds >= 500000/mult); 3528 } 3529 3530 static unsigned long 3531 getmem(void) 3532 { 3533 static int mib[] = {CTL_HW, HW_PHYSMEM, 0}; 3534 size_t size; 3535 unsigned long mem; 3536 3537 size = sizeof mem; 3538 if (sysctl(mib, 2, &mem, &size, NULL, 0) == -1) { 3539 fprintf(stderr, "error in sysctl(): %s\n", strerror(errno)); 3540 exit(3); 3541 } 3542 return mem; 3543 } 3544 3545 extern kern_return_t task_for_pid(task_port_t task, pid_t pid, task_port_t *target); 3546 3547 static void 3548 getproc(struct proc *p, struct kinfo_proc *kp) 3549 { 3550 kern_return_t error; 3551 unsigned int info_count = TASK_BASIC_INFO_COUNT; 3552 unsigned int thread_info_count = THREAD_BASIC_INFO_COUNT; 3553 task_port_t task; 3554 pid_t pid; 3555 struct task_basic_info task_binfo; 3556 struct task_thread_times_info task_times; 3557 time_value_t total_time, system_time; 3558 struct task_events_info task_events; 3559 struct policy_timeshare_info tshare; 3560 struct policy_rr_info rr; 3561 struct policy_fifo_info fifo; 3562 struct thread_basic_info th_binfo; 3563 thread_port_array_t thread_list; 3564 int thread_count; 3565 int j, temp, curpri; 3566 3567 memset(p, 0, sizeof *p); 3568 3569 p->p_pid = kp->kp_proc.p_pid; 3570 strncpy(p->p_fname, kp->kp_proc.p_comm, sizeof p->p_fname); 3571 p->p_fname[sizeof p->p_fname - 1] = '\0'; 3572 p->p_lstate[0] = kp->kp_proc.p_stat; /* contains at least zombie info */ 3573 p->p_lflag = kp->kp_proc.p_flag; 3574 p->p_ppid = kp->kp_eproc.e_ppid; 3575 p->p_pgid = kp->kp_eproc.e_pgid; 3576 p->p_sid = kp->kp_eproc.e_tpgid; 3577 p->p_ttydev = kp->kp_eproc.e_tdev == -1 ? PRNODEV : kp->kp_eproc.e_tdev; 3578 p->p_uid = kp->kp_eproc.e_pcred.p_ruid; 3579 p->p_euid = kp->kp_eproc.e_ucred.cr_uid; 3580 p->p_gid = kp->kp_eproc.e_pcred.p_rgid; 3581 p->p_egid = kp->kp_eproc.e_ucred.cr_gid; 3582 p->p_start = kp->kp_proc.p_starttime.tv_sec + 3583 (kp->kp_proc.p_starttime.tv_usec >= 500000); 3584 p->p_addr = (unsigned long)kp->kp_proc.p_addr; 3585 p->p_wchan = (unsigned long)kp->kp_proc.p_wchan; 3586 3587 if (p->p_lstate[0] == SZOMB) { 3588 p->p_lstate[0] = 7; 3589 return; /* do not fetch more data for zombies */ 3590 } 3591 3592 pid = kp->kp_proc.p_pid; 3593 error = task_for_pid(mach_task_self(), pid, &task); 3594 if (error != KERN_SUCCESS) { 3595 /* process already left the system */ 3596 p->p_lstate[0] = 7; /* handle exited process/task like zombie */ 3597 p->p_clname = "??"; /* will be used as nice value */ 3598 return; 3599 } 3600 info_count = TASK_BASIC_INFO_COUNT; 3601 error = task_info(task, TASK_BASIC_INFO, &task_binfo, &info_count); 3602 if (error != KERN_SUCCESS) { 3603 fprintf(stderr, "Error calling task_info():%d\n", error); 3604 exit(3); 3605 } 3606 info_count = TASK_THREAD_TIMES_INFO_COUNT; 3607 error = task_info(task, TASK_THREAD_TIMES_INFO, &task_times, &info_count); 3608 if (error != KERN_SUCCESS) { 3609 fprintf(stderr, "Error calling task_info():%d\n", error); 3610 exit(3); 3611 } 3612 info_count = TASK_EVENTS_INFO_COUNT; 3613 error = task_info(task, TASK_EVENTS_INFO, &task_events, &info_count); 3614 if (error != KERN_SUCCESS) { 3615 fprintf(stderr, "Error calling task_info():%d\n", error); 3616 exit(3); 3617 } 3618 3619 total_time = task_times.user_time; 3620 p->p_utime = tv2sec(&total_time, 1); 3621 3622 system_time = task_times.system_time; 3623 p->p_ktime = tv2sec(&system_time, 1); 3624 3625 time_value_add(&total_time, &system_time); 3626 p->p_time = tv2sec(&total_time, 1); 3627 3628 time_value_add(&total_time, &task_binfo.user_time); 3629 time_value_add(&total_time, &task_binfo.system_time); 3630 p->p_accutime = tv2sec(&total_time, 1); 3631 3632 switch(task_binfo.policy) { 3633 case POLICY_TIMESHARE : 3634 info_count = POLICY_TIMESHARE_INFO_COUNT; 3635 error = task_info(task, TASK_SCHED_TIMESHARE_INFO, &tshare, &info_count); 3636 if (error == KERN_SUCCESS) { 3637 p->p_intpri = tshare.cur_priority; 3638 p->p_rtpri = tshare.base_priority; 3639 p->p_clname = "TS"; 3640 p->p_policy = SCHED_OTHER; 3641 } 3642 break; 3643 case POLICY_RR : 3644 info_count = POLICY_RR_INFO_COUNT; 3645 error = task_info(task, TASK_SCHED_RR_INFO, &rr, &info_count); 3646 if (error == KERN_SUCCESS) { 3647 p->p_intpri = rr.base_priority; 3648 p->p_rtpri = rr.base_priority; 3649 p->p_clname = "RT"; 3650 p->p_policy = SCHED_RR; 3651 } 3652 break; 3653 case POLICY_FIFO : 3654 info_count = POLICY_FIFO_INFO_COUNT; 3655 error = task_info(task, TASK_SCHED_FIFO_INFO, &fifo, &info_count); 3656 if (error == KERN_SUCCESS) { 3657 p->p_intpri = fifo.base_priority; 3658 p->p_rtpri = fifo.base_priority; 3659 p->p_clname = "FF"; 3660 p->p_policy = SCHED_FIFO; 3661 } 3662 break; 3663 } 3664 p->p_nice = kp->kp_proc.p_nice; 3665 3666 /* allocates a thread port array */ 3667 error = task_threads(task, &thread_list, &thread_count); 3668 if (error != KERN_SUCCESS) { 3669 mach_port_deallocate(mach_task_self(), task); 3670 fprintf(stderr, "Error calling task_threads():%d\n", error); 3671 exit(3); 3672 } 3673 p->p_nlwp = thread_count; 3674 /* iterate over all threads for: cpu, state, swapped, prio */ 3675 /* it should also be possible to print all mach threads as LWPs */ 3676 p->p_lflag |= FL_SWAP; /* assume swapped */ 3677 curpri = p->p_intpri; 3678 for (j = 0; j < thread_count; j++) { 3679 info_count = THREAD_BASIC_INFO_COUNT; 3680 error = thread_info(thread_list[j], THREAD_BASIC_INFO, &th_binfo, &info_count); 3681 if (error != KERN_SUCCESS) { 3682 fprintf(stderr, "Error calling thread_info():%d\n", error); 3683 exit(3); 3684 } 3685 p->p_c += th_binfo.cpu_usage; 3686 switch (th_binfo.run_state) { 3687 case TH_STATE_RUNNING: 3688 temp=1; 3689 break; 3690 case TH_STATE_UNINTERRUPTIBLE: 3691 temp=2; 3692 break; 3693 case TH_STATE_WAITING: 3694 temp=(th_binfo.sleep_time <= 20) ? 3 : 4; 3695 break; 3696 case TH_STATE_STOPPED: 3697 temp=5; 3698 break; 3699 case TH_STATE_HALTED: 3700 temp=6; 3701 break; 3702 default: 3703 temp=8; 3704 } 3705 if (temp < p->p_lstate[0]) 3706 p->p_lstate[0] = temp; 3707 if ((th_binfo.flags & TH_FLAGS_SWAPPED ) == 0) 3708 p->p_lflag &= ~FL_SWAP; /* in mem */ 3709 switch(th_binfo.policy) { 3710 case POLICY_TIMESHARE : 3711 info_count = POLICY_TIMESHARE_INFO_COUNT; 3712 error = thread_info(thread_list[j], THREAD_SCHED_TIMESHARE_INFO, &tshare, &info_count); 3713 if (error == KERN_SUCCESS && curpri < tshare.cur_priority) 3714 curpri = tshare.cur_priority; 3715 break; 3716 case POLICY_RR : 3717 info_count = POLICY_RR_INFO_COUNT; 3718 error = thread_info(thread_list[j], THREAD_SCHED_RR_INFO, &rr, &info_count); 3719 if (error == KERN_SUCCESS && curpri < rr.base_priority) 3720 curpri = rr.base_priority; 3721 break; 3722 case POLICY_FIFO : 3723 info_count = POLICY_FIFO_INFO_COUNT; 3724 error = thread_info(thread_list[j], THREAD_SCHED_FIFO_INFO, &fifo, &info_count); 3725 if (error == KERN_SUCCESS && curpri < fifo.base_priority) 3726 curpri = fifo.base_priority; 3727 break; 3728 } 3729 mach_port_deallocate(mach_task_self(), thread_list[j]); 3730 } 3731 p->p_intpri = curpri; 3732 /* free the thread port array */ 3733 error = vm_deallocate(mach_task_self(), (vm_address_t)thread_list, thread_count * sizeof(thread_port_array_t)); 3734 p->p_c = p->p_c / (TH_USAGE_SCALE/100); 3735 p->p_pctcpu = p->p_c; 3736 3737 p->p_osz = task_binfo.virtual_size / pagesize; 3738 p->p_orss = task_binfo.resident_size / pagesize; 3739 3740 p->p_pflts = task_events.pageins; 3741 p->p_bufr = 0; 3742 p->p_bufw = 0; 3743 p->p_mrcv = task_events.messages_sent; /* Mach messages */ 3744 p->p_msnd = task_events.messages_received; 3745 3746 mach_port_deallocate(mach_task_self(), task); 3747 } 3748 3749 static void 3750 getargv(struct proc *p, struct kinfo_proc *kp) 3751 { 3752 size_t size, argsz; 3753 char *argbuf; 3754 int mib[3]; 3755 long nargs; 3756 char *ap, *pp, *xp; 3757 3758 /* ignore kernel and zombies */ 3759 if (kp->kp_proc.p_pid == 0 || p->p_lstate[0] == 7) 3760 return; 3761 3762 /* allocate a procargs space per process */ 3763 mib[0] = CTL_KERN; 3764 mib[1] = KERN_ARGMAX; 3765 size = sizeof argsz; 3766 if (sysctl(mib, 2, &argsz, &size, NULL, 0) == -1) { 3767 fprintf(stderr, "error in sysctl(): %s\n", strerror(errno)); 3768 exit(3); 3769 } 3770 argbuf = smalloc(argsz); 3771 3772 /* fetch the process arguments */ 3773 mib[0] = CTL_KERN; 3774 mib[1] = KERN_PROCARGS2; 3775 mib[2] = kp->kp_proc.p_pid; 3776 if (sysctl(mib, 3, argbuf, &argsz, NULL, 0) == -1) { 3777 /* process already left the system */ 3778 return; 3779 } 3780 3781 /* the number of args is at offset 0, this works for 32 and 64bit */ 3782 memcpy(&nargs, argbuf, sizeof nargs); 3783 ap = argbuf + sizeof nargs; 3784 3785 /* skip the exec_path */ 3786 while (ap < &argbuf[argsz] && *ap != '\0') 3787 ap++; 3788 if (ap == &argbuf[argsz]) 3789 goto DONE; /* no args to show */ 3790 /* skip trailing '\0' chars */ 3791 while (ap < &argbuf[argsz] && *ap == '\0') 3792 ap++; 3793 if (ap == &argbuf[argsz]) 3794 goto DONE; /* no args to show */ 3795 3796 xp = p->p_comm; /* copy the command name also */ 3797 /* now concat copy the arguments */ 3798 for (pp = p->p_psargs; pp < &p->p_psargs[sizeof p->p_psargs-1]; pp++) { 3799 if (*ap == '\0') { 3800 if (xp) { 3801 *xp = '\0'; 3802 xp = NULL; 3803 } 3804 if (--nargs == 0) 3805 break; 3806 *pp = ' '; 3807 ++ap; 3808 } else { 3809 if (xp) 3810 *xp++ = *ap; 3811 *pp = *ap++; 3812 } 3813 } 3814 *pp = '\0'; 3815 3816 DONE: free(argbuf); 3817 return; 3818 } 3819 3820 static void 3821 postproc(struct proc *p) 3822 { 3823 cleanline(p); 3824 if (p->p_lstate[0] < 0 || p->p_lstate[0] > 8) /* play safe */ 3825 p->p_lstate[0] = 8; 3826 p->p_state[0] = " RSSITHZ?"[p->p_lstate[0]]; 3827 p->p_lstate[0] = p->p_state[0]; 3828 if (p->p_lflag & P_SYSTEM) 3829 p->p_flag |= FL_SYS; 3830 p->p_pri = p->p_rtpri; 3831 p->p_oldpri = p->p_intpri; 3832 p->p_size = p->p_osz * kbytes_per_page; 3833 p->p_rssize = p->p_orss * kbytes_per_page; 3834 } 3835 3836 static void 3837 do_procs(void) 3838 { 3839 struct proc p; 3840 struct kinfo_proc *kp = NULL; 3841 size_t i, cnt; 3842 pid_t pid0; 3843 int err; 3844 3845 /* get all processes */ 3846 pid0 = 0; 3847 if ((err = GetBSDProcessList(pid0, &kp, &cnt)) != 0) { 3848 fprintf(stderr, "error getting proc list: %s\n", strerror(err)); 3849 exit(3); 3850 } 3851 i = cnt; 3852 while (--i >= 0) { 3853 /* ignore trailing garbage processes with pid 0 */ 3854 if (kp[i].kp_proc.p_pid == 0 && pid0++ > 0) 3855 break; 3856 getproc(&p, &kp[i]); 3857 getargv(&p, &kp[i]); 3858 postproc(&p); 3859 if (selectproc(&p) == OKAY) 3860 outproc(&p); 3861 } 3862 /* free the memory allocated by GetBSDProcessList */ 3863 free(kp); 3864 } 3865 3866 #endif /* all */ 3867 3868 /************************************************************************ 3869 * Option scanning * 3870 ************************************************************************/ 3871 3872 static void 3873 add_device(const char *prefix, size_t prefixlen, 3874 const char *name, struct stat *sp) 3875 { 3876 char *str; 3877 dev_type sz; 3878 3879 if (eq(name, "stdin") || eq(name, "stdout") || eq(name, "stderr")) 3880 return; 3881 sz = prefixlen + strlen(name) + 1; 3882 str = smalloc(sz); 3883 strcpy(str, prefix); 3884 strcpy(&str[prefixlen], name); 3885 dlook(sp->st_rdev, d0, str); 3886 #ifdef USE_PS_CACHE 3887 if (devfp != NULL) { 3888 dev_type dev = sp->st_rdev; 3889 3890 fwrite(&dev, sizeof dev, 1, devfp); 3891 fwrite(&sz, sizeof sz, 1, devfp); 3892 fwrite(str, 1, sz, devfp); 3893 } 3894 #endif /* USE_PS_CACHE */ 3895 } 3896 3897 static void 3898 add_devices_from(const char *path, const char *prefix) 3899 { 3900 DIR *Dp; 3901 struct dirent *dp; 3902 struct stat st; 3903 size_t prefixlen; 3904 3905 if (chdir(path) == 0) { 3906 if ((Dp = opendir(".")) != NULL) { 3907 prefixlen = strlen(prefix); 3908 while ((dp = readdir(Dp)) != NULL) { 3909 if (stat(dp->d_name, &st) == 0 && 3910 S_ISCHR(st.st_mode)) 3911 add_device(prefix, prefixlen, 3912 dp->d_name, &st); 3913 } 3914 closedir(Dp); 3915 } 3916 } 3917 } 3918 3919 static void 3920 devices(void) 3921 { 3922 #ifdef USE_PS_CACHE 3923 struct stat dst, fst; 3924 #endif /* USE_PS_CACHE */ 3925 struct output *o; 3926 3927 for (o = o0; o; o = o->o_nxt) 3928 if (o->o_typ == OU_TTY) 3929 break; 3930 if (o == NULL) 3931 return; 3932 d0 = scalloc(256, sizeof *d0); 3933 add_devices_from("/dev/pts", "pts/"); 3934 /* 3935 * Names in devfs. 3936 */ 3937 add_devices_from("/dev/tts", "tts/"); 3938 add_devices_from("/dev/cua", "cua/"); 3939 add_devices_from("/dev/vc", "vc/"); 3940 add_devices_from("/dev/vcc", "vcc/"); 3941 add_devices_from("/dev/pty", "pty/"); 3942 #ifdef USE_PS_CACHE 3943 if (stat(ps_cache_file, &fst) < 0 || 3944 (stat("/dev", &dst) == 0 && dst.st_mtime > fst.st_mtime) || 3945 (stat("/dev/usb", &dst) == 0 && dst.st_mtime > fst.st_mtime) || 3946 (stat("/dev/term", &dst) == 0 && dst.st_mtime > fst.st_mtime)) { 3947 putcache: 3948 if (dropprivs && myuid && myeuid && myuid != myeuid) 3949 setuid(myeuid); 3950 umask(0022); 3951 if ((devfp = wopen(ps_cache_file)) != NULL) { 3952 fchown(fileno(devfp), myeuid, ps_cache_gid); 3953 fchmod(fileno(devfp), ps_cache_mode); 3954 fwrite(cacheid, 1, strlen(cacheid) + 1, devfp); 3955 } 3956 if (dropprivs && myuid != myeuid) 3957 setuid(myuid); 3958 muststat: 3959 #endif /* USE_PS_CACHE */ 3960 add_devices_from("/dev/term", "term/"); 3961 add_devices_from("/dev/usb", "usb/"); 3962 add_devices_from("/dev", ""); 3963 #ifdef USE_PS_CACHE 3964 } else { 3965 char *str; 3966 dev_type dev; 3967 dev_type sz; 3968 char *thisid; 3969 3970 if ((fst.st_uid != 0 && fst.st_uid != myeuid) || 3971 (devfp = fopen(ps_cache_file, "r")) == NULL) 3972 goto muststat; 3973 sz = strlen(cacheid) + 1; 3974 thisid = alloca(sz); 3975 if (fread(thisid, 1, sz, devfp) != sz || 3976 strcmp(cacheid, thisid)) { 3977 fclose(devfp); 3978 devfp = NULL; 3979 goto putcache; 3980 } 3981 if (dropprivs && myuid != myeuid) 3982 setuid(myuid); 3983 while (fread(&dev, sizeof dev, 1, devfp) == 1 && 3984 fread(&sz, sizeof sz, 1, devfp) == 1) { 3985 str = smalloc(sz); 3986 if (fread(str, 1, sz, devfp) != sz) 3987 break; 3988 dlook(dev, d0, str); 3989 } 3990 } 3991 if (devfp != NULL) { 3992 fclose(devfp); 3993 devfp = NULL; 3994 } 3995 #endif /* USE_PS_CACHE */ 3996 } 3997 3998 #ifdef UCB 3999 static void 4000 usage(void) 4001 { 4002 fprintf(stderr, "usage: %s [ -acglnrSuvwx ] [ -t term ] [ num ]\n", 4003 progname); 4004 exit(2); 4005 } 4006 #else /* !UCB */ 4007 static void 4008 usage(void) 4009 { 4010 fprintf(stderr, "\ 4011 usage: %s [ -edalfcj ] [ -r sysname ] [ -t termlist ]\n\ 4012 [ -u uidlist ] [ -p proclist ] [ -g grplist ] [ -s sidlist ]\n", 4013 progname); 4014 exit(2); 4015 } 4016 #endif /* !UCB */ 4017 4018 static const char * 4019 element(const char **listp, int override) 4020 { 4021 static char *buf; 4022 static size_t buflen; 4023 const char *cp, *op; 4024 char *cq; 4025 size_t sz; 4026 int stop = ','; 4027 4028 if (**listp == '\0') 4029 return NULL; 4030 op = *listp; 4031 while (**listp != '\0') { 4032 if (**listp == override) 4033 stop = '\0'; 4034 if (stop != '\0' && (**listp == stop || isblank(**listp))) 4035 break; 4036 (*listp)++; 4037 } 4038 if (**listp == '\0') 4039 return op; 4040 if ((sz = *listp - op + 1) > buflen) { 4041 buflen = sz; 4042 buf = srealloc(buf, buflen); 4043 } 4044 for (cp = op, cq = buf; cp < *listp; cp++, cq++) 4045 *cq = *cp; 4046 *cq = '\0'; 4047 if (**listp) { 4048 while (**listp == stop || isblank(**listp)) 4049 (*listp)++; 4050 } 4051 return buf; 4052 } 4053 4054 static void 4055 add_criterion(enum crtype cy, unsigned long val) 4056 { 4057 struct criterion *ct; 4058 4059 ct = scalloc(1, sizeof *ct); 4060 ct->c_typ = cy; 4061 ct->c_val = val; 4062 ct->c_nxt = c0; 4063 c0 = ct; 4064 } 4065 4066 static enum okay 4067 get_rdev(const char *device, unsigned long *id) 4068 { 4069 struct stat st; 4070 char *file; 4071 4072 *id = 0; 4073 file = alloca(strlen(device) + 9); 4074 strcpy(file, "/dev/"); 4075 strcpy(&file[5], device); 4076 if (stat(file, &st) < 0) { 4077 strcpy(file, "/dev/tty"); 4078 strcpy(&file[8], device); 4079 if (stat(file, &st) == 0) 4080 *id = st.st_rdev; 4081 else if ((device[0] == '?' || device[0] == '-') && 4082 device[1] == '\0') 4083 add_criterion(CR_WITHOUT_TTY, 0); 4084 else 4085 return STOP; 4086 } else 4087 *id = st.st_rdev; 4088 return OKAY; 4089 } 4090 4091 static void 4092 nonnumeric(const char *string, enum crtype ct) 4093 { 4094 #ifndef UCB 4095 int c; 4096 4097 switch (ct) { 4098 case CR_PROCESS_GROUP: 4099 c = 'g'; 4100 break; 4101 case CR_PROCESS_ID: 4102 c = 'p'; 4103 break; 4104 case CR_SESSION_LEADER: 4105 c = 's'; 4106 break; 4107 default: 4108 c = '?'; 4109 } 4110 fprintf(stderr, 4111 "%s: %s is an invalid non-numeric argument for -%c option\n", 4112 progname, string, c); 4113 #else /* UCB */ 4114 fprintf(stderr, 4115 "%s: %s is an invalid non-numeric argument for a process id\n", 4116 progname, string); 4117 #endif /* UCB */ 4118 } 4119 4120 static void 4121 add_criterion_string(enum crtype ct, const char *string) 4122 { 4123 struct passwd *pwd; 4124 struct group *grp; 4125 char *x; 4126 unsigned long val = 0; 4127 4128 switch (ct) { 4129 case CR_ALL: 4130 case CR_ALL_WITH_TTY: 4131 case CR_ALL_BUT_SESSION_LEADERS: 4132 case CR_WITHOUT_TTY: 4133 case CR_NO_TTY_NO_SESSION_LEADER: 4134 case CR_ADD_UNINTERESTING: 4135 case CR_DEFAULT: 4136 val = 0; 4137 break; 4138 case CR_PROCESS_GROUP: 4139 case CR_PROCESS_ID: 4140 case CR_SESSION_LEADER: 4141 val = strtoul(string, &x, 10); 4142 if (*x != '\0' || *string == '+' || *string == '-' || 4143 *string == '\0') { 4144 nonnumeric(string, ct); 4145 ct = CR_INVALID_STOP; 4146 } 4147 break; 4148 case CR_REAL_GID: 4149 if ((grp = getgrnam(string)) != NULL) { 4150 val = grp->gr_gid; 4151 } else { 4152 val = strtoul(string, &x, 10); 4153 if (*x != '\0' || *string == '+' || *string == '-' || 4154 *string == '\0') { 4155 fprintf(stderr, "%s: unknown group %s\n", 4156 progname, string); 4157 ct = CR_INVALID_REAL_GID; 4158 } 4159 } 4160 break; 4161 case CR_EFF_UID: 4162 case CR_REAL_UID: 4163 if ((pwd = getpwnam(string)) != NULL) { 4164 val = pwd->pw_uid; 4165 } else { 4166 val = strtoul(string, &x, 10); 4167 if (*x != '\0' || *string == '+' || *string == '-' || 4168 *string == '\0') { 4169 fprintf(stderr, "%s: unknown user %s\n", 4170 progname, string); 4171 ct = (ct == CR_EFF_UID ? CR_INVALID_EFF_UID : 4172 CR_INVALID_REAL_UID); 4173 } 4174 } 4175 break; 4176 case CR_TTY_DEVICE: 4177 if (get_rdev(string, &val) == STOP) { 4178 add_criterion(CR_INVALID_TTY_DEVICE, 0); 4179 return; 4180 } 4181 break; 4182 } 4183 add_criterion(ct, val); 4184 } 4185 4186 static void 4187 add_criteria_list(enum crtype ct, const char *list) 4188 { 4189 const char *cp; 4190 4191 if (*list) 4192 while ((cp = element(&list, '\0')) != NULL) 4193 add_criterion_string(ct, cp); 4194 else 4195 add_criterion_string(ct, ""); 4196 } 4197 4198 static void 4199 add_format(enum outype ot, const char *name) 4200 { 4201 struct output *op, *oq; 4202 unsigned i = 0; 4203 4204 while (outspec[i].os_typ != ot) 4205 i++; 4206 op = scalloc(1, sizeof *op); 4207 op->o_typ = ot; 4208 if (outspec[i].os_flags & OS_Lflag) 4209 Lflag |= 1; 4210 if (name == NULL) { 4211 op->o_nam = outspec[i].os_def; 4212 op->o_len = strlen(op->o_nam); 4213 dohdr++; 4214 } else if (*name == '\0') { 4215 op->o_nam = ""; 4216 op->o_len = strlen(outspec[i].os_def); 4217 } else { 4218 op->o_nam = smalloc(strlen(name) + 1); 4219 strcpy(op->o_nam, name); 4220 op->o_len = strlen(op->o_nam); 4221 dohdr++; 4222 } 4223 if (o0 != NULL) { 4224 for (oq = o0; oq->o_nxt; oq = oq->o_nxt); 4225 oq->o_nxt = op; 4226 } else 4227 o0 = op; 4228 } 4229 4230 static void 4231 add_format_string(const char *string) 4232 { 4233 char *fmt; 4234 char *name = NULL; 4235 unsigned i; 4236 4237 fmt = alloca(strlen(string) + 1); 4238 strcpy(fmt, string); 4239 if ((name = strchr(fmt, '=')) != NULL) { 4240 *name++ = '\0'; 4241 } 4242 for (i = 0; outspec[i].os_fmt != NULL; i++) { 4243 if (eq(outspec[i].os_fmt, fmt)) { 4244 add_format(outspec[i].os_typ, name); 4245 break; 4246 } 4247 } 4248 if (outspec[i].os_fmt == NULL) { 4249 fprintf(stderr, "%s: unknown output format: -o %s\n", 4250 progname, string); 4251 usage(); 4252 } 4253 } 4254 4255 static void 4256 add_format_list(const char *list) 4257 { 4258 const char *cp; 4259 4260 while ((cp = element(&list, '=')) != NULL) 4261 add_format_string(cp); 4262 } 4263 4264 static void 4265 defaults(void) 4266 { 4267 FILE *fp; 4268 4269 if ((fp = fopen(DEFAULT, "r")) != NULL) { 4270 char buf[LINE_MAX]; 4271 char *cp, *x; 4272 4273 while (fgets(buf, sizeof buf, fp) != NULL) { 4274 if (buf[0] == '\0' || buf[0] == '\n' || buf[0] == '#') 4275 continue; 4276 if ((cp = strchr(buf, '\n')) != NULL) 4277 *cp = '\0'; 4278 if (strncmp(buf, "O1_SCHEDULER=", 13) == 0) { 4279 sched_selection = atoi(&buf[13]) ? 1 : -1; 4280 } else if (strncmp(buf, "DROPPRIVS=", 10) == 0) { 4281 dropprivs = strtol(&buf[10], &x, 10); 4282 if (*x != '\0' || dropprivs != 1) 4283 dropprivs = 0; 4284 } 4285 #ifdef USE_PS_CACHE 4286 else if (strncmp(buf, "CACHE_FILE=", 11) == 0) { 4287 if (buf[11] == '/' && buf[12] != '\0') { 4288 ps_cache_file = smalloc(strlen( 4289 &buf[11]) + 1); 4290 strcpy(ps_cache_file, &buf[11]); 4291 } 4292 } else if (strncmp(buf, "CACHE_MODE=", 11) == 0) { 4293 mode_t m; 4294 4295 m = strtol(&buf[11], &x, 8); 4296 if (*x == '\0') 4297 ps_cache_mode = m; 4298 } else if (strncmp(buf, "CACHE_GROUP=", 12) == 0) { 4299 struct group *grp; 4300 gid_t gid; 4301 4302 if ((grp = getgrnam(&buf[12])) == NULL) { 4303 gid = strtoul(&buf[12], &x, 10); 4304 if (*x == '\0') 4305 ps_cache_gid = gid; 4306 } else 4307 ps_cache_gid = grp->gr_gid; 4308 } 4309 #endif /* USE_PS_CACHE */ 4310 } 4311 fclose(fp); 4312 } 4313 } 4314 4315 #ifndef UCB 4316 static const char optstring[] = ":aAcdefg:G:jlLn:o:Pp:r:Rs:t:u:U:Ty"; 4317 #else /* UCB */ 4318 static const char optstring[] = ":acglLnrSuvwxt:R:AG:p:U:o:"; 4319 #endif /* UCB */ 4320 4321 /* 4322 * If -r sysname is given, chroot() needs to be done before any files are 4323 * opened -> scan options twice, first for evaluating '-r' and syntactic 4324 * correctness, then for evaluating other options (in options() below). 4325 */ 4326 static void 4327 sysname(int ac, char **av) 4328 { 4329 extern int chroot(const char *); 4330 const char *dir = NULL; 4331 int i, hadflag = 0, illegal = 0; 4332 4333 while ((i = getopt(ac, av, optstring)) != EOF) { 4334 switch (i) { 4335 #ifndef UCB 4336 case 'r': 4337 rflag = optarg; 4338 break; 4339 case 'e': 4340 case 's': 4341 case 'd': 4342 case 'a': 4343 case 't': 4344 case 'p': 4345 case 'u': 4346 case 'g': 4347 case 'U': 4348 case 'G': 4349 case 'A': 4350 hadflag = 1; 4351 break; 4352 #else /* UCB */ 4353 case 'R': 4354 rflag = optarg; 4355 break; 4356 case 'a': 4357 case 'x': 4358 case 't': 4359 case 'p': 4360 case 'U': 4361 case 'G': 4362 case 'A': 4363 hadflag = 1; 4364 break; 4365 #endif /* UCB */ 4366 case ':': 4367 fprintf(stderr, 4368 "%s: option requires an argument -- %c\n", 4369 progname, optopt); 4370 illegal = 1; 4371 break; 4372 case '?': 4373 fprintf(stderr, "%s: illegal option -- %c\n", 4374 progname, optopt); 4375 illegal = 1; 4376 break; 4377 } 4378 } 4379 if (illegal) 4380 usage(); 4381 #ifndef UCB 4382 if (av[optind]) 4383 usage(); 4384 #else /* UCB */ 4385 if (av[optind] && av[optind + 1]) { 4386 fprintf(stderr, "%s: too many arguments\n", progname); 4387 usage(); 4388 } 4389 #endif /* UCB */ 4390 if (rflag) { 4391 if (hadflag == 0) { 4392 fprintf(stderr, 4393 "%s: one of -%s must be used with -%c sysname\n", 4394 progname, 4395 #ifndef UCB 4396 "esdatpugUGA", 'r' 4397 #else 4398 "axtpUGA", 'R' 4399 #endif 4400 ); 4401 usage(); 4402 } 4403 if (*rflag != '/') { 4404 #if defined (__linux__) || defined (__hpux) || defined (_AIX) 4405 FILE *fp; 4406 struct mntent *mp; 4407 #if defined (__linux__) || defined (_AIX) 4408 const char mtab[] = "/etc/mtab"; 4409 #else 4410 const char mtab[] = "/etc/mnttab"; 4411 #endif 4412 4413 if ((fp = setmntent(mtab, "r")) == NULL) { 4414 fprintf(stderr, "%s: cannot open %s\n", 4415 progname, mtab); 4416 exit(1); 4417 } 4418 dir = NULL; 4419 while ((mp = getmntent(fp)) != NULL) { 4420 if (strcmp(mp->mnt_type, MNTTYPE_IGNORE) == 0) 4421 continue; 4422 if (strcmp(rflag, basename(mp->mnt_dir)) == 0) { 4423 dir = sstrdup(mp->mnt_dir); 4424 break; 4425 } 4426 } 4427 endmntent(fp); 4428 #elif defined (__FreeBSD__) || defined (__NetBSD__) || defined (__OpenBSD__) \ 4429 || defined (__DragonFly__) || defined (__APPLE__) 4430 struct statfs *sp = NULL; 4431 int cnt, i; 4432 4433 if ((cnt = getmntinfo(&sp, MNT_WAIT)) <= 0) { 4434 fprintf(stderr, "%s: cannot get mounts\n", 4435 progname); 4436 exit(1); 4437 } 4438 for (i = 0; i < cnt; i++) 4439 if (!strcmp(rflag, 4440 basename(sp[i].f_mntonname))) { 4441 dir = sstrdup(sp[i].f_mntonname); 4442 break; 4443 } 4444 #else /* SVR4 */ 4445 FILE *fp; 4446 struct mnttab mt; 4447 const char mtab[] = "/etc/mnttab"; 4448 4449 if ((fp = fopen(mtab, "r")) == NULL) { 4450 fprintf(stderr, "%s: cannot open %s\n", 4451 progname, mtab); 4452 exit(1); 4453 } 4454 dir = NULL; 4455 while (getmntent(fp, &mt) == 0) 4456 if (!strcmp(rflag, basename(mt.mnt_mountp))) { 4457 dir = sstrdup(mt.mnt_mountp); 4458 break; 4459 } 4460 fclose(fp); 4461 #endif /* SVR4 */ 4462 if (dir == NULL) { 4463 fprintf(stderr, 4464 "%s: cannot find path to system %s\n", 4465 progname, rflag); 4466 exit(1); 4467 } 4468 } else 4469 dir = rflag; 4470 if (chroot(dir) < 0) { 4471 fprintf(stderr, "%s: cannot change root to %s\n", 4472 progname, dir); 4473 exit(1); 4474 } 4475 } 4476 optind = 1; 4477 } 4478 4479 #ifndef UCB 4480 extern int sysv3; /* emulate SYSV3 behavior */ 4481 4482 static void 4483 options(int ac, char **av) 4484 { 4485 int cflag = 0; /* priocntl format */ 4486 int fflag = 0; /* full format */ 4487 int jflag = 0; /* jobs format */ 4488 int lflag = 0; /* long format */ 4489 int Pflag = 0; /* print processor information */ 4490 int Rflag = 0; /* EP/IX resource format */ 4491 int Tflag = 0; /* EP/IX thread format */ 4492 int yflag = 0; /* modify format */ 4493 int i; 4494 4495 if (getenv("SYSV3") != NULL) 4496 sysv3 = 1; 4497 #ifdef S42 4498 cflag = 1; 4499 #endif /* S42 */ 4500 while ((i = getopt(ac, av, optstring)) != EOF) { 4501 switch (i) { 4502 case 'a': 4503 add_criterion(CR_ALL_WITH_TTY, 0); 4504 break; 4505 case 'c': 4506 cflag++; 4507 break; 4508 case 'd': 4509 add_criterion(CR_ALL_BUT_SESSION_LEADERS, 0); 4510 break; 4511 case 'e': 4512 case 'A': 4513 add_criterion(CR_ALL, 0); 4514 break; 4515 case 'f': 4516 fflag = 1; 4517 break; 4518 case 'g': 4519 add_criteria_list(CR_PROCESS_GROUP, optarg); 4520 break; 4521 case 'G': 4522 add_criteria_list(CR_REAL_GID, optarg); 4523 break; 4524 case 'j': 4525 jflag = 1; 4526 break; 4527 case 'l': 4528 lflag = 1; 4529 break; 4530 case 'L': 4531 Lflag = 3; 4532 break; 4533 case 'n': 4534 fprintf(stderr, "%s: warning: -n option ignored\n", 4535 progname); 4536 break; 4537 case 'o': 4538 oflag = 1; 4539 add_format_list(optarg); 4540 break; 4541 case 'P': 4542 Pflag = 1; 4543 break; 4544 case 'p': 4545 add_criteria_list(CR_PROCESS_ID, optarg); 4546 break; 4547 case 'r': 4548 rflag = optarg; 4549 break; 4550 case 'R': 4551 Rflag = 1; 4552 break; 4553 case 's': 4554 add_criteria_list(CR_SESSION_LEADER, optarg); 4555 break; 4556 case 't': 4557 add_criteria_list(CR_TTY_DEVICE, optarg); 4558 break; 4559 case 'T': 4560 Tflag = 1; 4561 break; 4562 case 'u': 4563 #ifdef SUS 4564 add_criteria_list(CR_EFF_UID, optarg); 4565 break; 4566 #else /* !SUS */ 4567 /*FALLTHRU*/ 4568 #endif /* !SUS */ 4569 case 'U': 4570 add_criteria_list(CR_REAL_UID, optarg); 4571 break; 4572 case 'y': 4573 yflag = 1; 4574 break; 4575 } 4576 } 4577 if (Rflag) 4578 lflag = fflag = 0; 4579 if (o0 == NULL) { 4580 #ifdef SUS 4581 const char *cmd_str = "CMD"; 4582 #else 4583 const char *cmd_str = "COMD"; 4584 if (sysv3 && !lflag) 4585 cmd_str = "COMMAND"; 4586 #endif 4587 if (fflag || jflag || lflag) { 4588 if (jflag || (lflag && yflag)) 4589 add_format(OU_SPACE, NULL); 4590 if (lflag && !yflag) 4591 add_format(OU_F, NULL); 4592 if (lflag) 4593 add_format(OU_S, NULL); 4594 #ifdef SUS 4595 if (fflag) 4596 add_format(OU_USER, " UID"); 4597 else if (lflag) 4598 add_format(OU_UID, NULL); 4599 #else /* !SUS */ 4600 if (fflag) 4601 add_format(OU_RUSER, " UID"); 4602 else if (lflag) 4603 add_format(OU_RUID, " UID"); 4604 #endif /* !SUS */ 4605 add_format(OU_PID, NULL); 4606 if (Tflag && !fflag) 4607 add_format(OU_STID, NULL); 4608 if (fflag || lflag) 4609 add_format(OU_PPID, NULL); 4610 if (jflag) { 4611 add_format(OU_PGID, NULL); 4612 add_format(OU_SID, NULL); 4613 } 4614 if (Lflag & 2) { 4615 add_format(OU_LWP, NULL); 4616 if (fflag) 4617 add_format(OU_NLWP, NULL); 4618 } 4619 if (Tflag) 4620 add_format(OU_TID, NULL); 4621 if (Pflag || Tflag) 4622 add_format(OU_PSR, NULL); 4623 if (Tflag && !fflag) 4624 add_format(OU_NTP, NULL); 4625 #ifndef S42 4626 if (cflag) { 4627 add_format(OU_CLASS, NULL); 4628 add_format(OU_PRI, NULL); 4629 } else { 4630 if (fflag || lflag) 4631 add_format(OU_C, NULL); 4632 if (lflag) { 4633 add_format(OU_OPRI, NULL); 4634 add_format(OU_NICE, NULL); 4635 } 4636 } 4637 #else /* S42 */ 4638 add_format(OU_CLASS, NULL); 4639 add_format(OU_PRI, NULL); 4640 if (fflag || lflag) 4641 add_format(OU_C, NULL); 4642 #endif /* S42 */ 4643 if (lflag) { 4644 if (yflag) { 4645 add_format(OU_RSS, NULL); 4646 add_format(OU_VSZ, " SZ"); 4647 } else { 4648 add_format(OU_ADDR, NULL); 4649 add_format(OU_OSZ, NULL); 4650 } 4651 add_format(OU_WCHAN, NULL); 4652 } 4653 if (fflag) 4654 add_format(OU_STIME, NULL); 4655 add_format(OU_TTY, "TTY "); 4656 if (Lflag & 2) 4657 add_format(OU_LTIME, NULL); 4658 else 4659 add_format(OU_OTIME, NULL); 4660 if (fflag) 4661 add_format(OU_ARGS, cmd_str); 4662 else 4663 add_format(OU_FNAME, cmd_str); 4664 } else { 4665 add_format(OU_SPACE, NULL); 4666 add_format(OU_PID, NULL); 4667 if (Lflag & 2) 4668 add_format(OU_LWP, NULL); 4669 if (Tflag) { 4670 add_format(OU_STID, NULL); 4671 add_format(OU_TID, NULL); 4672 } 4673 if (Pflag || Tflag) 4674 add_format(OU_PSR, NULL); 4675 if (Tflag) 4676 add_format(OU_NTP, NULL); 4677 if (cflag) { 4678 add_format(OU_CLASS, NULL); 4679 add_format(OU_PRI, NULL); 4680 } 4681 if (Rflag) { 4682 add_format(OU_OSZ, " SZ"); 4683 add_format(OU_MRSZ, NULL); 4684 add_format(OU_PFLTS, NULL); 4685 add_format(OU_BUFR, NULL); 4686 add_format(OU_BUFW, NULL); 4687 add_format(OU_MRCV, NULL); 4688 add_format(OU_MSND, NULL); 4689 add_format(OU_UTIME, NULL); 4690 add_format(OU_KTIME, NULL); 4691 } else { 4692 add_format(OU_TTY, "TTY "); 4693 if (Lflag & 2) 4694 add_format(OU_LTIME, NULL); 4695 else 4696 add_format(OU_OTIME, NULL); 4697 } 4698 add_format(OU_FNAME, cmd_str); 4699 } 4700 } 4701 } 4702 #else /* UCB */ 4703 /* 4704 * Note that the 'UCB' version is not actually oriented at historical 4705 * BSD usage, but at /usr/ucb/ps of SVR4 (with POSIX.2 extensions). 4706 */ 4707 static void 4708 options(int ac, char **av) 4709 { 4710 char *cp; 4711 int i, format = 0, agxsel = 0, illegal = 0; 4712 int cflag = 0; /* display command name instead of args */ 4713 int nflag = 0; /* print numerical IDs */ 4714 int Sflag = 0; /* display accumulated time */ 4715 int wflag = 0; /* screen width */ 4716 4717 while ((i = getopt(ac, av, optstring)) != EOF) { 4718 switch (i) { 4719 case 'a': 4720 agxsel |= 01; 4721 break; 4722 case 'A': 4723 add_criterion(CR_ALL, 0); 4724 break; 4725 case 'c': 4726 cflag = 1; 4727 break; 4728 case 'g': 4729 agxsel |= 02; 4730 break; 4731 case 'G': 4732 add_criteria_list(CR_REAL_GID, optarg); 4733 break; 4734 case 'l': 4735 format = 'l'; 4736 break; 4737 case 'L': 4738 Lflag = 1; 4739 break; 4740 case 'n': 4741 nflag = 1; 4742 break; 4743 case 'o': 4744 oflag = 1; 4745 wflag = 2; /* do not limit width */ 4746 add_format_list(optarg); 4747 break; 4748 case 'p': 4749 add_criteria_list(CR_PROCESS_ID, optarg); 4750 break; 4751 case 'r': 4752 ucb_rflag = 1; 4753 break; 4754 case 'S': 4755 Sflag = 1; 4756 break; 4757 case 't': 4758 add_criteria_list(CR_TTY_DEVICE, optarg); 4759 agxsel &= ~04; 4760 break; 4761 case 'u': 4762 format = 'u'; 4763 break; 4764 case 'U': 4765 /* 4766 * 'U' without argument is 'update ps database' in 4767 * historical /usr/ucb/ps. We implement the POSIX.2 4768 * option instead. 4769 */ 4770 add_criteria_list(CR_REAL_UID, optarg); 4771 break; 4772 case 'v': 4773 format = 'v'; 4774 break; 4775 case 'w': 4776 wflag++; 4777 break; 4778 case 'x': 4779 agxsel |= 04; 4780 break; 4781 } 4782 } 4783 if (illegal) 4784 usage(); 4785 if (av[optind]) { 4786 add_criteria_list(CR_PROCESS_ID, av[optind]); 4787 agxsel = 0; 4788 ucb_rflag = 0; 4789 } 4790 switch (agxsel) { 4791 case 01|04: 4792 case 01|02|04: 4793 add_criterion(CR_ALL, 0); 4794 break; 4795 case 02|04: 4796 add_criterion(CR_WITHOUT_TTY, 0); 4797 add_criterion(CR_ADD_UNINTERESTING, 0); 4798 break; 4799 case 01: 4800 case 01|02: 4801 add_criterion(CR_ALL_WITH_TTY, 0); 4802 break; 4803 case 02: 4804 add_criterion(CR_ADD_UNINTERESTING, 0); 4805 break; 4806 case 04: 4807 add_criterion(CR_NO_TTY_NO_SESSION_LEADER, 0); 4808 break; 4809 } 4810 if (o0 == NULL) { 4811 if (format == 'l') { 4812 add_format(OU_F, NULL); 4813 add_format(OU_RUID, " UID"); 4814 } else if (format == 'u') { 4815 if (nflag) 4816 add_format(OU_RUID, " UID"); 4817 else 4818 add_format(OU_RUSER, "USER "); 4819 } 4820 if (format == 'l') { 4821 add_format(OU_PID, NULL); 4822 add_format(OU_PPID, NULL); 4823 } else if (format == 'u') 4824 add_format(OU_PID, " PID"); 4825 else 4826 add_format(OU_PID, " PID"); 4827 if (format == 'l' || format == 'u') 4828 add_format(OU_C, "CP"); 4829 if (format == 'l') { 4830 add_format(OU_OPRI, NULL); 4831 add_format(OU_NICE, NULL); 4832 } 4833 if (format == 'l' || format == 'u') { 4834 add_format(OU_OSZ, " SZ"); 4835 add_format(OU_ORSS, " RSS"); 4836 } 4837 if (format == 'l') { 4838 add_format(OU_WCHAN, NULL); 4839 add_format(OU_S, NULL); 4840 add_format(OU_TTY, "TT "); 4841 } else 4842 add_format(OU_TTY, "TT "); 4843 if (format == 'u' || format == 'v' || format == 0) 4844 add_format(OU_S, " S"); 4845 if (format == 'u') 4846 add_format(OU_STIME, " START"); 4847 else if (format == 'v') { 4848 add_format(OU_OSZ, " SIZE"); 4849 add_format(OU_ORSS, " RSS"); 4850 } 4851 add_format(Sflag ? OU_ACCUTIME : OU_OTIME, NULL); 4852 add_format(cflag ? OU_FNAME : OU_ARGS, "COMMAND"); 4853 } 4854 if ((cp = getenv("COLUMNS")) != NULL) 4855 maxcolumn = strtol(cp, NULL, 10); 4856 if (maxcolumn <= 0) { 4857 #ifdef TIOCGWINSZ 4858 struct winsize winsz; 4859 4860 if (ioctl(1, TIOCGWINSZ, &winsz) == 0 && winsz.ws_col > 0) 4861 maxcolumn = winsz.ws_col; 4862 else 4863 #endif /* TIOCGWINSZ */ 4864 maxcolumn = 80; 4865 } 4866 if (wflag == 1) 4867 maxcolumn += 52; 4868 else if (wflag > 1) 4869 maxcolumn = 0; 4870 } 4871 #endif /* UCB */ 4872 4873 int 4874 main(int argc, char **argv) 4875 { 4876 #ifdef __GLIBC__ 4877 putenv("POSIXLY_CORRECT=1"); 4878 #endif 4879 progname = basename(argv[0]); 4880 sysname(argc, argv); 4881 defaults(); 4882 myuid = getuid(); 4883 myeuid = geteuid(); 4884 if (dropprivs && myuid && myeuid && myuid != myeuid) 4885 setuid(myuid); 4886 setlocale(LC_CTYPE, ""); 4887 setlocale(LC_TIME, ""); 4888 mb_cur_max = MB_CUR_MAX; 4889 ontty = isatty(1); 4890 options(argc, argv); 4891 devices(); 4892 #if !defined (__hpux) && !defined (_AIX) && !defined (__NetBSD__) && \ 4893 !defined (__OpenBSD__) && !defined (__APPLE__) 4894 chdir_to_proc(); 4895 #endif 4896 #ifdef __linux__ 4897 get_linux_version(); 4898 if (linux_version_lt(2, 5, 0) && has_o1_sched() == 0) 4899 compute_priority = compute_priority_old; 4900 else 4901 compute_priority = compute_priority_new; 4902 #endif /* __linux__ */ 4903 hz = sysconf(_SC_CLK_TCK); 4904 time(&now); 4905 #ifdef __linux__ 4906 uptime = sysup(); 4907 #endif /* __linux__ */ 4908 #ifdef __APPLE__ 4909 { 4910 static int mib[] = {CTL_HW, HW_PAGESIZE, 0}; 4911 size_t size; 4912 size = sizeof pagesize; 4913 if (sysctl(mib, 2, &pagesize, &size, NULL, 0) == -1) { 4914 fprintf(stderr, "error in sysctl(): %s\n", strerror(errno)); 4915 exit(3); 4916 } 4917 } 4918 #else 4919 pagesize = sysconf(_SC_PAGESIZE); 4920 #endif 4921 kbytes_per_page = (pagesize >> 10); 4922 #ifndef __sun 4923 totalmem = getmem(); 4924 #endif /* !__sun */ 4925 #if defined (__linux__) || defined (__sun) 4926 getproc("self", &myproc, getpid(), -1); 4927 #elif defined (__FreeBSD__) || defined (__DragonFly__) 4928 getproc("curproc", &myproc, getpid(), -1); 4929 #elif defined (__hpux) 4930 { 4931 struct pst_status pst; 4932 pid_t mypid = getpid(); 4933 pstat_getproc(&pst, sizeof pst, (size_t)0, mypid); 4934 getproc(&myproc, &pst); 4935 } 4936 #elif defined (_AIX) 4937 { 4938 struct stat st; 4939 int fd; 4940 4941 if ((fd = open("/dev/tty", O_RDONLY)) >= 0) { 4942 if (stat(ttyname(fd), &st) == 0) 4943 myproc.p_ttydev = st.st_rdev; 4944 close(fd); 4945 } 4946 } 4947 #elif defined (__OpenBSD__) 4948 { 4949 kvm_t *kt; 4950 struct kinfo_proc *kp; 4951 int mypid = getpid(); 4952 int cnt; 4953 4954 if ((kt = kvm_open(NULL, NULL, NULL, KVM_NO_FILES, 4955 "kvm_open")) == NULL) 4956 exit(1); 4957 kp = kvm_getprocs(kt, KERN_PROC_PID, mypid, &cnt); 4958 if (kp != NULL) 4959 getproc(&myproc, &kp[0]); 4960 kvm_close(kt); 4961 } 4962 #elif defined (__NetBSD__) 4963 { 4964 kvm_t *kt; 4965 struct kinfo_proc2 *kp; 4966 int mypid = getpid(); 4967 int cnt; 4968 4969 if ((kt = kvm_open(NULL, NULL, NULL, KVM_NO_FILES, 4970 "kvm_open")) == NULL) 4971 exit(1); 4972 kp = kvm_getproc2(kt, KERN_PROC_PID, mypid, 4973 sizeof *kp, &cnt); 4974 if (kp != NULL) 4975 getproc(&myproc, &kp[0]); 4976 kvm_close(kt); 4977 } 4978 #elif defined (__APPLE__) 4979 { 4980 struct kinfo_proc *kp; 4981 pid_t mypid = getpid(); 4982 size_t cnt; 4983 int err; 4984 4985 kp = NULL; 4986 if ((err = GetBSDProcessList(mypid, &kp, &cnt)) != 0) { 4987 fprintf(stderr, "error getting proc list: %s\n", strerror(err)); 4988 exit(3); 4989 } 4990 if (kp != NULL) { 4991 getproc(&myproc, kp); 4992 free(kp); 4993 } 4994 } 4995 #else /* SVR4 */ 4996 { 4997 /* 4998 * /proc/self has no useful pr_ttydev value on Open UNIX 8. 4999 */ 5000 char num[20]; 5001 pid_t mypid = getpid(); 5002 snprintf(num, sizeof num, "%d", mypid); 5003 getproc(num, &myproc, mypid, -1); 5004 } 5005 #endif /* SVR4 */ 5006 if (c0 == NULL) { 5007 #ifndef UCB 5008 if (myproc.p_ttydev == (dev_type)PRNODEV) { 5009 fprintf(stderr, 5010 "%s: can't find controlling terminal\n", 5011 progname); 5012 exit(1); 5013 } 5014 #endif /* !UCB */ 5015 add_criterion(CR_DEFAULT, 0); 5016 } else { 5017 struct criterion *ct; 5018 int valid = 0, invalid = 0; 5019 5020 for (ct = c0; ct; ct = ct->c_nxt) { 5021 if (ct->c_typ == CR_INVALID_STOP) 5022 usage(); 5023 else if (ct->c_typ == CR_EFF_UID) 5024 valid |= 01; 5025 else if (ct->c_typ == CR_INVALID_EFF_UID) 5026 invalid |= 01; 5027 else if (ct->c_typ == CR_REAL_UID) 5028 valid |= 02; 5029 else if (ct->c_typ == CR_INVALID_REAL_UID) 5030 invalid |= 02; 5031 else if (ct->c_typ == CR_REAL_GID) 5032 valid |= 04; 5033 else if (ct->c_typ == CR_INVALID_REAL_GID) 5034 invalid |= 04; 5035 } 5036 if ((invalid & valid) != invalid) 5037 return 1; 5038 } 5039 if (dohdr) 5040 putheader(); 5041 do_procs(); 5042 return errcnt; 5043 }