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