1*5db3b398Sflorian /* $OpenBSD: ps.c,v 1.74 2019/02/05 18:13:20 florian Exp $ */ 2df930be7Sderaadt /* $NetBSD: ps.c,v 1.15 1995/05/18 20:33:25 mycroft Exp $ */ 3df930be7Sderaadt 4df930be7Sderaadt /*- 5df930be7Sderaadt * Copyright (c) 1990, 1993, 1994 6df930be7Sderaadt * The Regents of the University of California. All rights reserved. 7df930be7Sderaadt * 8df930be7Sderaadt * Redistribution and use in source and binary forms, with or without 9df930be7Sderaadt * modification, are permitted provided that the following conditions 10df930be7Sderaadt * are met: 11df930be7Sderaadt * 1. Redistributions of source code must retain the above copyright 12df930be7Sderaadt * notice, this list of conditions and the following disclaimer. 13df930be7Sderaadt * 2. Redistributions in binary form must reproduce the above copyright 14df930be7Sderaadt * notice, this list of conditions and the following disclaimer in the 15df930be7Sderaadt * documentation and/or other materials provided with the distribution. 1629295d1cSmillert * 3. Neither the name of the University nor the names of its contributors 17df930be7Sderaadt * may be used to endorse or promote products derived from this software 18df930be7Sderaadt * without specific prior written permission. 19df930be7Sderaadt * 20df930be7Sderaadt * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND 21df930be7Sderaadt * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 22df930be7Sderaadt * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 23df930be7Sderaadt * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE 24df930be7Sderaadt * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 25df930be7Sderaadt * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS 26df930be7Sderaadt * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 27df930be7Sderaadt * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 28df930be7Sderaadt * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY 29df930be7Sderaadt * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 30df930be7Sderaadt * SUCH DAMAGE. 31df930be7Sderaadt */ 32df930be7Sderaadt 33b9fc9a72Sderaadt #include <sys/param.h> /* MAXCOMLEN NODEV */ 34b9fc9a72Sderaadt #include <sys/types.h> 350adec678Sderaadt #include <sys/sysctl.h> 36df930be7Sderaadt #include <sys/time.h> 37df930be7Sderaadt #include <sys/resource.h> 38df930be7Sderaadt #include <sys/proc.h> 39df930be7Sderaadt #include <sys/stat.h> 40df930be7Sderaadt #include <sys/ioctl.h> 41df930be7Sderaadt 42df930be7Sderaadt #include <ctype.h> 43df930be7Sderaadt #include <err.h> 44df930be7Sderaadt #include <errno.h> 45df930be7Sderaadt #include <fcntl.h> 46df930be7Sderaadt #include <kvm.h> 47033e8ff0Sschwarze #include <locale.h> 48df930be7Sderaadt #include <nlist.h> 49df930be7Sderaadt #include <paths.h> 5052576792Salex #include <pwd.h> 51df930be7Sderaadt #include <stdio.h> 52df930be7Sderaadt #include <stdlib.h> 53df930be7Sderaadt #include <string.h> 54df930be7Sderaadt #include <unistd.h> 556763c4d8Sderaadt #include <limits.h> 56df930be7Sderaadt 57df930be7Sderaadt #include "ps.h" 58df930be7Sderaadt 599517852aSmpech extern char *__progname; 609517852aSmpech 6179f972fbSderaadt struct varent *vhead; 62df930be7Sderaadt 63df930be7Sderaadt int eval; /* exit value */ 64df930be7Sderaadt int sumrusage; /* -S */ 65df930be7Sderaadt int termwidth; /* width of screen (0 == infinity) */ 66df930be7Sderaadt int totwidth; /* calculated width of requested variables */ 67df930be7Sderaadt 686b176adcSmillert int needcomm, needenv, neednlist, commandonly; 69df930be7Sderaadt 704527c594Smillert enum sort { DEFAULT, SORTMEM, SORTCPU } sortby = DEFAULT; 71df930be7Sderaadt 72c72b5b24Smillert static char *kludge_oldps_options(char *); 73c72b5b24Smillert static int pscomp(const void *, const void *); 74c72b5b24Smillert static void scanvars(void); 75c72b5b24Smillert static void usage(void); 76df930be7Sderaadt 77df930be7Sderaadt char dfmt[] = "pid tt state time command"; 78b9d9655cSjsing char tfmt[] = "pid tid tt state time command"; 79df930be7Sderaadt char jfmt[] = "user pid ppid pgid sess jobc state tt time command"; 80df930be7Sderaadt char lfmt[] = "uid pid ppid cpu pri nice vsz rss wchan state tt time command"; 81df930be7Sderaadt char o1[] = "pid"; 82df930be7Sderaadt char o2[] = "tt state time command"; 83df930be7Sderaadt char ufmt[] = "user pid %cpu %mem vsz rss tt state start time command"; 84df930be7Sderaadt char vfmt[] = "pid state time sl re pagein vsz rss lim tsiz %cpu %mem command"; 85df930be7Sderaadt 86df930be7Sderaadt kvm_t *kd; 875877eea9Sart int kvm_sysctl_only; 88df930be7Sderaadt 89df930be7Sderaadt int 9028416801Sderaadt main(int argc, char *argv[]) 91df930be7Sderaadt { 925027561dSguenther struct kinfo_proc *kp, **kinfo; 93df930be7Sderaadt struct varent *vent; 94df930be7Sderaadt struct winsize ws; 95df930be7Sderaadt dev_t ttydev; 96df930be7Sderaadt pid_t pid; 97df930be7Sderaadt uid_t uid; 981601eb99Sguenther int all, ch, flag, i, fmt, lineno, nentries; 99fc7b2cf1Sguenther int prtheader, showthreads, wflag, kflag, what, Uflag, xflg; 100c2e41e89Sguenther char *nlistf, *memf, *swapf, *cols, errbuf[_POSIX2_LINE_MAX]; 101df930be7Sderaadt 102033e8ff0Sschwarze setlocale(LC_CTYPE, ""); 103033e8ff0Sschwarze 1047220d8ecSbentley termwidth = 0; 1057220d8ecSbentley if ((cols = getenv("COLUMNS")) != NULL) 1067220d8ecSbentley termwidth = strtonum(cols, 1, INT_MAX, NULL); 107511be169Sbentley if (termwidth == 0 && 108511be169Sbentley (ioctl(STDOUT_FILENO, TIOCGWINSZ, &ws) == 0 || 109511be169Sbentley ioctl(STDERR_FILENO, TIOCGWINSZ, &ws) == 0 || 110511be169Sbentley ioctl(STDIN_FILENO, TIOCGWINSZ, &ws) == 0) && 1117220d8ecSbentley ws.ws_col > 0) 112df930be7Sderaadt termwidth = ws.ws_col - 1; 1137220d8ecSbentley if (termwidth == 0) 1147220d8ecSbentley termwidth = 79; 115df930be7Sderaadt 116df930be7Sderaadt if (argc > 1) 117df930be7Sderaadt argv[1] = kludge_oldps_options(argv[1]); 118df930be7Sderaadt 119fc7b2cf1Sguenther all = fmt = prtheader = showthreads = wflag = kflag = Uflag = xflg = 0; 120df930be7Sderaadt pid = -1; 121b9badb0aSotto uid = 0; 122df930be7Sderaadt ttydev = NODEV; 123df930be7Sderaadt memf = nlistf = swapf = NULL; 124df930be7Sderaadt while ((ch = getopt(argc, argv, 1259ea50c04Sokan "AaCcegHhjkLlM:mN:O:o:p:rSTt:U:uvW:wx")) != -1) 126c9c5a36dSkevlo switch (ch) { 1279ea50c04Sokan case 'A': 1289ea50c04Sokan all = 1; 1299ea50c04Sokan xflg = 1; 1309ea50c04Sokan break; 131df930be7Sderaadt case 'a': 132df930be7Sderaadt all = 1; 133df930be7Sderaadt break; 1349ea50c04Sokan case 'C': 1354bdadadaSbluhm break; /* no-op */ 136df930be7Sderaadt case 'c': 137df930be7Sderaadt commandonly = 1; 138df930be7Sderaadt break; 139df930be7Sderaadt case 'e': /* XXX set ufmt */ 140df930be7Sderaadt needenv = 1; 141df930be7Sderaadt break; 142df930be7Sderaadt case 'g': 143df930be7Sderaadt break; /* no-op */ 144fc7b2cf1Sguenther case 'H': 145fc7b2cf1Sguenther showthreads = 1; 146fc7b2cf1Sguenther break; 147df930be7Sderaadt case 'h': 148df930be7Sderaadt prtheader = ws.ws_row > 5 ? ws.ws_row : 22; 149df930be7Sderaadt break; 150df930be7Sderaadt case 'j': 151df930be7Sderaadt parsefmt(jfmt); 152df930be7Sderaadt fmt = 1; 153df930be7Sderaadt jfmt[0] = '\0'; 154df930be7Sderaadt break; 1553f2d366dSniklas case 'k': 1563f36dab3Sokan kflag = 1; 1573f2d366dSniklas break; 158df930be7Sderaadt case 'L': 159df930be7Sderaadt showkey(); 160df930be7Sderaadt exit(0); 161df930be7Sderaadt case 'l': 162df930be7Sderaadt parsefmt(lfmt); 163df930be7Sderaadt fmt = 1; 164df930be7Sderaadt lfmt[0] = '\0'; 165df930be7Sderaadt break; 166df930be7Sderaadt case 'M': 167df930be7Sderaadt memf = optarg; 168df930be7Sderaadt break; 169df930be7Sderaadt case 'm': 170df930be7Sderaadt sortby = SORTMEM; 171df930be7Sderaadt break; 172df930be7Sderaadt case 'N': 173df930be7Sderaadt nlistf = optarg; 174df930be7Sderaadt break; 175df930be7Sderaadt case 'O': 176df930be7Sderaadt parsefmt(o1); 177df930be7Sderaadt parsefmt(optarg); 178df930be7Sderaadt parsefmt(o2); 179df930be7Sderaadt o1[0] = o2[0] = '\0'; 180df930be7Sderaadt fmt = 1; 181df930be7Sderaadt break; 182df930be7Sderaadt case 'o': 183df930be7Sderaadt parsefmt(optarg); 184df930be7Sderaadt fmt = 1; 185df930be7Sderaadt break; 186df930be7Sderaadt case 'p': 187df930be7Sderaadt pid = atol(optarg); 188df930be7Sderaadt xflg = 1; 189df930be7Sderaadt break; 190df930be7Sderaadt case 'r': 191df930be7Sderaadt sortby = SORTCPU; 192df930be7Sderaadt break; 193df930be7Sderaadt case 'S': 194df930be7Sderaadt sumrusage = 1; 195df930be7Sderaadt break; 196df930be7Sderaadt case 'T': 197df930be7Sderaadt if ((optarg = ttyname(STDIN_FILENO)) == NULL) 198df930be7Sderaadt errx(1, "stdin: not a terminal"); 199df930be7Sderaadt /* FALLTHROUGH */ 200df930be7Sderaadt case 't': { 201df930be7Sderaadt struct stat sb; 202b9fc9a72Sderaadt char *ttypath, pathbuf[PATH_MAX]; 203df930be7Sderaadt 204df930be7Sderaadt if (strcmp(optarg, "co") == 0) 205df930be7Sderaadt ttypath = _PATH_CONSOLE; 206df930be7Sderaadt else if (*optarg != '/') 207df930be7Sderaadt (void)snprintf(ttypath = pathbuf, 208df930be7Sderaadt sizeof(pathbuf), "%s%s", _PATH_TTY, optarg); 209df930be7Sderaadt else 210df930be7Sderaadt ttypath = optarg; 211df930be7Sderaadt if (stat(ttypath, &sb) == -1) 212df930be7Sderaadt err(1, "%s", ttypath); 213df930be7Sderaadt if (!S_ISCHR(sb.st_mode)) 214df930be7Sderaadt errx(1, "%s: not a terminal", ttypath); 215df930be7Sderaadt ttydev = sb.st_rdev; 216df930be7Sderaadt break; 217df930be7Sderaadt } 21852576792Salex case 'U': 219a0f924b8Smillert if (uid_from_user(optarg, &uid) == -1) 22052576792Salex errx(1, "%s: no such user", optarg); 221b9badb0aSotto Uflag = xflg = 1; 22252576792Salex break; 223df930be7Sderaadt case 'u': 224df930be7Sderaadt parsefmt(ufmt); 225df930be7Sderaadt sortby = SORTCPU; 226df930be7Sderaadt fmt = 1; 227df930be7Sderaadt ufmt[0] = '\0'; 228df930be7Sderaadt break; 229df930be7Sderaadt case 'v': 230df930be7Sderaadt parsefmt(vfmt); 231df930be7Sderaadt sortby = SORTMEM; 232df930be7Sderaadt fmt = 1; 233df930be7Sderaadt vfmt[0] = '\0'; 234df930be7Sderaadt break; 235df930be7Sderaadt case 'W': 236df930be7Sderaadt swapf = optarg; 237df930be7Sderaadt break; 238df930be7Sderaadt case 'w': 239df930be7Sderaadt if (wflag) 240df930be7Sderaadt termwidth = UNLIMITED; 241df930be7Sderaadt else if (termwidth < 131) 242df930be7Sderaadt termwidth = 131; 2433f36dab3Sokan wflag = 1; 244df930be7Sderaadt break; 245df930be7Sderaadt case 'x': 246df930be7Sderaadt xflg = 1; 247df930be7Sderaadt break; 248df930be7Sderaadt default: 249df930be7Sderaadt usage(); 250df930be7Sderaadt } 251df930be7Sderaadt argc -= optind; 252df930be7Sderaadt argv += optind; 253df930be7Sderaadt 254df930be7Sderaadt #define BACKWARD_COMPATIBILITY 255df930be7Sderaadt #ifdef BACKWARD_COMPATIBILITY 256df930be7Sderaadt if (*argv) { 257df930be7Sderaadt nlistf = *argv; 258df930be7Sderaadt if (*++argv) { 259df930be7Sderaadt memf = *argv; 260df930be7Sderaadt if (*++argv) 261df930be7Sderaadt swapf = *argv; 262df930be7Sderaadt } 263df930be7Sderaadt } 264df930be7Sderaadt #endif 265df930be7Sderaadt 2665877eea9Sart if (nlistf == NULL && memf == NULL && swapf == NULL) { 2675877eea9Sart kd = kvm_openfiles(NULL, NULL, NULL, KVM_NO_FILES, errbuf); 2685877eea9Sart kvm_sysctl_only = 1; 2695877eea9Sart } else { 270df930be7Sderaadt kd = kvm_openfiles(nlistf, memf, swapf, O_RDONLY, errbuf); 2715877eea9Sart } 272f2812ea1Sguenther if (kd == NULL) 273df930be7Sderaadt errx(1, "%s", errbuf); 274df930be7Sderaadt 275*5db3b398Sflorian if (unveil(_PATH_DEVDB, "r") == -1 && errno != ENOENT) 2762f5bf968Sderaadt err(1, "unveil"); 277*5db3b398Sflorian if (unveil(_PATH_DEV, "r") == -1 && errno != ENOENT) 2782f5bf968Sderaadt err(1, "unveil"); 2792f5bf968Sderaadt if (swapf) 2802f5bf968Sderaadt if (unveil(swapf, "r") == -1) 2812f5bf968Sderaadt err(1, "unveil"); 2822f5bf968Sderaadt if (nlistf) 2832f5bf968Sderaadt if (unveil(nlistf, "r") == -1) 2842f5bf968Sderaadt err(1, "unveil"); 2852f5bf968Sderaadt if (memf) 2862f5bf968Sderaadt if (unveil(memf, "r") == -1) 2872f5bf968Sderaadt err(1, "unveil"); 288dcce26deSderaadt if (pledge("stdio rpath getpw ps", NULL) == -1) 28946a2cbd9Sderaadt err(1, "pledge"); 2904120813fSderaadt 291b9d9655cSjsing if (!fmt) { 292b9d9655cSjsing if (showthreads) 293b9d9655cSjsing parsefmt(tfmt); 294b9d9655cSjsing else 295df930be7Sderaadt parsefmt(dfmt); 296b9d9655cSjsing } 297df930be7Sderaadt 29852576792Salex /* XXX - should be cleaner */ 299ba86f864Sotto if (!all && ttydev == NODEV && pid == -1 && !Uflag) { 300df930be7Sderaadt uid = getuid(); 301ba86f864Sotto Uflag = 1; 302ba86f864Sotto } 303df930be7Sderaadt 304df930be7Sderaadt /* 305df930be7Sderaadt * scan requested variables, noting what structures are needed, 30605ea949fSmillert * and adjusting header widths as appropriate. 307df930be7Sderaadt */ 308df930be7Sderaadt scanvars(); 3096b176adcSmillert 3106b176adcSmillert if (neednlist && !nlistread) 3116b176adcSmillert (void) donlist(); 3126b176adcSmillert 313df930be7Sderaadt /* 314df930be7Sderaadt * get proc list 315df930be7Sderaadt */ 316b9badb0aSotto if (Uflag) { 31790624e93Smillert what = KERN_PROC_UID; 31890624e93Smillert flag = uid; 319df930be7Sderaadt } else if (ttydev != NODEV) { 32090624e93Smillert what = KERN_PROC_TTY; 32190624e93Smillert flag = ttydev; 322df930be7Sderaadt } else if (pid != -1) { 32390624e93Smillert what = KERN_PROC_PID; 32490624e93Smillert flag = pid; 3253f2d366dSniklas } else if (kflag) { 32690624e93Smillert what = KERN_PROC_KTHREAD; 3273f2d366dSniklas flag = 0; 328df930be7Sderaadt } else { 32990624e93Smillert what = KERN_PROC_ALL; 330df930be7Sderaadt flag = 0; 331df930be7Sderaadt } 3326171375dSpirofti if (showthreads) 3336171375dSpirofti what |= KERN_PROC_SHOW_THREADS; 334970ac3e4Sderaadt 335df930be7Sderaadt /* 336df930be7Sderaadt * select procs 337df930be7Sderaadt */ 3385027561dSguenther kp = kvm_getprocs(kd, what, flag, sizeof(*kp), &nentries); 339e6592a11Sangelos if (kp == NULL) 34090624e93Smillert errx(1, "%s", kvm_geterr(kd)); 341f2812ea1Sguenther 342df930be7Sderaadt /* 343df930be7Sderaadt * print header 344df930be7Sderaadt */ 345df930be7Sderaadt printheader(); 346df930be7Sderaadt if (nentries == 0) 347a30d4cafSmichaels exit(1); 348df930be7Sderaadt /* 34990624e93Smillert * sort proc list, we convert from an array of structs to an array 35090624e93Smillert * of pointers to make the sort cheaper. 351df930be7Sderaadt */ 35271633524Stedu if ((kinfo = reallocarray(NULL, nentries, sizeof(*kinfo))) == NULL) 35390624e93Smillert err(1, "failed to allocate memory for proc pointers"); 35490624e93Smillert for (i = 0; i < nentries; i++) 35590624e93Smillert kinfo[i] = &kp[i]; 35690624e93Smillert qsort(kinfo, nentries, sizeof(*kinfo), pscomp); 357df930be7Sderaadt /* 358df930be7Sderaadt * for each proc, call each variable output function. 359df930be7Sderaadt */ 360df930be7Sderaadt for (i = lineno = 0; i < nentries; i++) { 361fc7b2cf1Sguenther if (showthreads == 0 && (kinfo[i]->p_flag & P_THREAD) != 0) 362fc7b2cf1Sguenther continue; 36379f972fbSderaadt if (xflg == 0 && ((int)kinfo[i]->p_tdev == NODEV || 364447f61ceSguenther (kinfo[i]->p_psflags & PS_CONTROLT ) == 0)) 365df930be7Sderaadt continue; 366243c13beSpirofti if (showthreads && kinfo[i]->p_tid == -1) 367243c13beSpirofti continue; 368df930be7Sderaadt for (vent = vhead; vent; vent = vent->next) { 36990624e93Smillert (vent->var->oproc)(kinfo[i], vent); 370df930be7Sderaadt if (vent->next != NULL) 371df930be7Sderaadt (void)putchar(' '); 372df930be7Sderaadt } 373df930be7Sderaadt (void)putchar('\n'); 374df930be7Sderaadt if (prtheader && lineno++ == prtheader - 4) { 375df930be7Sderaadt (void)putchar('\n'); 376df930be7Sderaadt printheader(); 377df930be7Sderaadt lineno = 0; 378df930be7Sderaadt } 379df930be7Sderaadt } 380df930be7Sderaadt exit(eval); 381df930be7Sderaadt } 382df930be7Sderaadt 383df930be7Sderaadt static void 38428416801Sderaadt scanvars(void) 385df930be7Sderaadt { 386df930be7Sderaadt struct varent *vent; 387df930be7Sderaadt VAR *v; 388df930be7Sderaadt int i; 389df930be7Sderaadt 390df930be7Sderaadt for (vent = vhead; vent; vent = vent->next) { 391df930be7Sderaadt v = vent->var; 392df930be7Sderaadt i = strlen(v->header); 393df930be7Sderaadt if (v->width < i) 394df930be7Sderaadt v->width = i; 395df930be7Sderaadt totwidth += v->width + 1; /* +1 for space */ 396df930be7Sderaadt if (v->flag & COMM) 397df930be7Sderaadt needcomm = 1; 3986b176adcSmillert if (v->flag & NLIST) 3996b176adcSmillert neednlist = 1; 400df930be7Sderaadt } 401df930be7Sderaadt totwidth--; 402df930be7Sderaadt } 403df930be7Sderaadt 404df930be7Sderaadt static int 40590624e93Smillert pscomp(const void *v1, const void *v2) 406df930be7Sderaadt { 4075027561dSguenther const struct kinfo_proc *kp1 = *(const struct kinfo_proc **)v1; 4085027561dSguenther const struct kinfo_proc *kp2 = *(const struct kinfo_proc **)v2; 409df930be7Sderaadt int i; 41090624e93Smillert #define VSIZE(k) ((k)->p_vm_dsize + (k)->p_vm_ssize + (k)->p_vm_tsize) 411df930be7Sderaadt 41290624e93Smillert if (sortby == SORTCPU && (i = getpcpu(kp2) - getpcpu(kp1)) != 0) 41390624e93Smillert return (i); 41490624e93Smillert if (sortby == SORTMEM && (i = VSIZE(kp2) - VSIZE(kp1)) != 0) 41590624e93Smillert return (i); 41690624e93Smillert if ((i = kp1->p_tdev - kp2->p_tdev) == 0 && 41790624e93Smillert (i = kp1->p_ustart_sec - kp2->p_ustart_sec) == 0) 41890624e93Smillert i = kp1->p_ustart_usec - kp2->p_ustart_usec; 419fffbb510Smillert return (i); 420fffbb510Smillert } 421df930be7Sderaadt 422df930be7Sderaadt /* 423df930be7Sderaadt * ICK (all for getopt), would rather hide the ugliness 424df930be7Sderaadt * here than taint the main code. 425df930be7Sderaadt * 426df930be7Sderaadt * ps foo -> ps -foo 427df930be7Sderaadt * ps 34 -> ps -p34 428df930be7Sderaadt * 429df930be7Sderaadt * The old convention that 't' with no trailing tty arg means the users 430df930be7Sderaadt * tty, is only supported if argv[1] doesn't begin with a '-'. This same 431df930be7Sderaadt * feature is available with the option 'T', which takes no argument. 432df930be7Sderaadt */ 433df930be7Sderaadt static char * 43428416801Sderaadt kludge_oldps_options(char *s) 435df930be7Sderaadt { 436df930be7Sderaadt size_t len; 437df930be7Sderaadt char *newopts, *ns, *cp; 438df930be7Sderaadt 439df930be7Sderaadt len = strlen(s); 440263704f2Sderaadt if ((newopts = ns = malloc(2 + len + 1)) == NULL) 441df930be7Sderaadt err(1, NULL); 442df930be7Sderaadt /* 443df930be7Sderaadt * options begin with '-' 444df930be7Sderaadt */ 445df930be7Sderaadt if (*s != '-') 446df930be7Sderaadt *ns++ = '-'; /* add option flag */ 447263704f2Sderaadt 448df930be7Sderaadt /* 449df930be7Sderaadt * gaze to end of argv[1] 450df930be7Sderaadt */ 451df930be7Sderaadt cp = s + len - 1; 452df930be7Sderaadt /* 453df930be7Sderaadt * if last letter is a 't' flag with no argument (in the context 454df930be7Sderaadt * of the oldps options -- option string NOT starting with a '-' -- 455df930be7Sderaadt * then convert to 'T' (meaning *this* terminal, i.e. ttyname(0)). 456df930be7Sderaadt */ 457df930be7Sderaadt if (*cp == 't' && *s != '-') 458df930be7Sderaadt *cp = 'T'; 459df930be7Sderaadt else { 460df930be7Sderaadt /* 461df930be7Sderaadt * otherwise check for trailing number, which *may* be a 462df930be7Sderaadt * pid. 463df930be7Sderaadt */ 464cd3e3e8cSderaadt while (cp >= s && isdigit((unsigned char)*cp)) 465df930be7Sderaadt --cp; 466df930be7Sderaadt } 467df930be7Sderaadt cp++; 468df930be7Sderaadt memmove(ns, s, (size_t)(cp - s)); /* copy up to trailing number */ 469df930be7Sderaadt ns += cp - s; 470df930be7Sderaadt /* 471df930be7Sderaadt * if there's a trailing number, and not a preceding 'p' (pid) or 472df930be7Sderaadt * 't' (tty) flag, then assume it's a pid and insert a 'p' flag. 473df930be7Sderaadt */ 474cd3e3e8cSderaadt if (isdigit((unsigned char)*cp) && 475cd3e3e8cSderaadt (cp == s || (cp[-1] != 't' && cp[-1] != 'p' && 476764064c4Smickey (cp - 1 == s || cp[-2] != 't')))) 477df930be7Sderaadt *ns++ = 'p'; 478263704f2Sderaadt /* and append the number */ 479263704f2Sderaadt (void)strlcpy(ns, cp, newopts + len + 3 - ns); 480df930be7Sderaadt 481df930be7Sderaadt return (newopts); 482df930be7Sderaadt } 483df930be7Sderaadt 484df930be7Sderaadt static void 48528416801Sderaadt usage(void) 486df930be7Sderaadt { 487df930be7Sderaadt (void)fprintf(stderr, 4884bdadadaSbluhm "usage: %s [-AaceHhjkLlmrSTuvwx] [-M core] [-N system] [-O fmt] [-o fmt] [-p pid]\n", 4899517852aSmpech __progname); 4909517852aSmpech (void)fprintf(stderr, 4915c0ffb2cSchl "%-*s[-t tty] [-U username] [-W swap]\n", (int)strlen(__progname) + 8, ""); 492df930be7Sderaadt exit(1); 493df930be7Sderaadt } 494