Print this page
OS-3280 need a way to specify the root of a native system in the lx brand
OS-3279 lx brand should allow delegated datasets
Reviewed by: Jerry Jelinek <jerry.jelinek@joyent.com>
| Split |
Close |
| Expand all |
| Collapse all |
--- old/usr/src/cmd/ptools/ptree/ptree.c
+++ new/usr/src/cmd/ptools/ptree/ptree.c
1 1 /*
2 2 * CDDL HEADER START
3 3 *
4 4 * The contents of this file are subject to the terms of the
5 5 * Common Development and Distribution License (the "License").
6 6 * You may not use this file except in compliance with the License.
7 7 *
8 8 * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
9 9 * or http://www.opensolaris.org/os/licensing.
10 10 * See the License for the specific language governing permissions
11 11 * and limitations under the License.
12 12 *
13 13 * When distributing Covered Code, include this CDDL HEADER in each
|
↓ open down ↓ |
13 lines elided |
↑ open up ↑ |
14 14 * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
15 15 * If applicable, add the following below this CDDL HEADER, with the
16 16 * fields enclosed by brackets "[]" replaced with your own identifying
17 17 * information: Portions Copyright [yyyy] [name of copyright owner]
18 18 *
19 19 * CDDL HEADER END
20 20 */
21 21 /*
22 22 * Copyright 2007 Sun Microsystems, Inc. All rights reserved.
23 23 * Use is subject to license terms.
24 + * Copyright (c) 2014, Joyent, Inc. All rights reserved.
24 25 */
25 26
26 27 /*
27 28 * ptree -- print family tree of processes
28 29 */
29 30
30 -#pragma ident "%Z%%M% %I% %E% SMI"
31 -
32 31 #include <assert.h>
33 32 #include <stdio.h>
34 33 #include <string.h>
35 34 #include <errno.h>
36 35 #include <fcntl.h>
37 36 #include <sys/types.h>
38 37 #include <sys/termios.h>
39 38 #include <unistd.h>
40 39 #include <stdlib.h>
41 40 #include <dirent.h>
42 41 #include <pwd.h>
43 42 #include <libproc.h>
44 43 #include <libzonecfg.h>
45 44 #include <limits.h>
46 45 #include <libcontract.h>
47 46 #include <sys/contract.h>
48 47 #include <sys/ctfs.h>
49 48 #include <libcontract_priv.h>
50 49 #include <sys/stat.h>
50 +#include "ptools_common.h"
51 51
52 52 #define FAKEDPID0(p) (p->pid == 0 && p->psargs[0] == '\0')
53 53
54 54 typedef struct ps {
55 55 int done;
56 56 uid_t uid;
57 57 uid_t gid;
58 58 pid_t pid; /* pid == -1 indicates this is a contract */
59 59 pid_t ppid;
60 60 pid_t pgrp;
61 61 pid_t sid;
62 62 zoneid_t zoneid;
63 63 ctid_t ctid;
64 64 timestruc_t start;
65 65 char psargs[PRARGSZ];
66 66 struct ps *pp; /* parent */
67 67 struct ps *sp; /* sibling */
68 68 struct ps *cp; /* child */
69 69 } ps_t;
70 70
71 71 static ps_t **ps; /* array of ps_t's */
72 72 static unsigned psize; /* size of array */
73 73 static int nps; /* number of ps_t's */
74 74 static ps_t **ctps; /* array of contract ps_t's */
75 75 static unsigned ctsize; /* size of contract array */
76 76 static int nctps; /* number of contract ps_t's */
77 77 static ps_t *proc0; /* process 0 */
78 78 static ps_t *proc1; /* process 1 */
79 79
80 80 static char *command;
81 81
82 82 static int aflag = 0;
83 83 static int cflag = 0;
84 84 static int zflag = 0;
85 85 static zoneid_t zoneid;
86 86 static int columns = 80;
87 87
88 88 static void markprocs(ps_t *p);
89 89 static int printone(ps_t *p, int level);
90 90 static void insertchild(ps_t *, ps_t *);
91 91 static void prsort(ps_t *p);
92 92 static void printsubtree(ps_t *p, int level);
93 93 static zoneid_t getzone(char *arg);
94 94 static ps_t *fakepid0(void);
95 95
|
↓ open down ↓ |
35 lines elided |
↑ open up ↑ |
96 96 int
97 97 main(int argc, char **argv)
98 98 {
99 99 psinfo_t info; /* process information structure from /proc */
100 100 int opt;
101 101 int errflg = 0;
102 102 struct winsize winsize;
103 103 char *s;
104 104 int n;
105 105 int retc = 0;
106 + char ppath[PATH_MAX];
106 107
107 108 DIR *dirp;
108 109 struct dirent *dentp;
109 - char pname[100];
110 + char pname[PATH_MAX];
110 111 int pdlen;
111 112
112 113 ps_t *p;
113 114
114 115 if ((command = strrchr(argv[0], '/')) == NULL)
115 116 command = argv[0];
116 117 else
117 118 command++;
118 119
119 120 /* options */
120 121 while ((opt = getopt(argc, argv, "acz:")) != EOF) {
121 122 switch (opt) {
122 123 case 'a': /* include children of process 0 */
123 124 aflag = 1;
124 125 break;
125 126 case 'c': /* display contract ownership */
126 127 aflag = cflag = 1;
127 128 break;
128 129 case 'z': /* only processes in given zone */
129 130 zflag = 1;
130 131 zoneid = getzone(optarg);
131 132 break;
132 133 default:
133 134 errflg = 1;
134 135 break;
135 136 }
136 137 }
137 138
138 139 argc -= optind;
139 140 argv += optind;
140 141
141 142 if (errflg) {
142 143 (void) fprintf(stderr,
143 144 "usage:\t%s [-ac] [-z zone] [ {pid|user} ... ]\n",
144 145 command);
145 146 (void) fprintf(stderr,
146 147 " (show process trees)\n");
147 148 (void) fprintf(stderr,
148 149 " list can include process-ids and user names\n");
149 150 (void) fprintf(stderr,
150 151 " -a : include children of process 0\n");
151 152 (void) fprintf(stderr,
152 153 " -c : show contract ownership\n");
153 154 (void) fprintf(stderr,
154 155 " -z : print only processes in given zone\n");
155 156 return (2);
156 157 }
157 158
158 159 /*
159 160 * Kind of a hack to determine the width of the output...
160 161 */
161 162 if ((s = getenv("COLUMNS")) != NULL && (n = atoi(s)) > 0)
|
↓ open down ↓ |
42 lines elided |
↑ open up ↑ |
162 163 columns = n;
163 164 else if (isatty(fileno(stdout)) &&
164 165 ioctl(fileno(stdout), TIOCGWINSZ, &winsize) == 0 &&
165 166 winsize.ws_col != 0)
166 167 columns = winsize.ws_col;
167 168
168 169 nps = 0;
169 170 psize = 0;
170 171 ps = NULL;
171 172
173 + (void) proc_snprintf(ppath, sizeof (ppath), "/proc");
174 +
172 175 /*
173 176 * Search the /proc directory for all processes.
174 177 */
175 - if ((dirp = opendir("/proc")) == NULL) {
176 - (void) fprintf(stderr, "%s: cannot open /proc directory\n",
177 - command);
178 + if ((dirp = opendir(ppath)) == NULL) {
179 + (void) fprintf(stderr, "%s: cannot open %s directory\n",
180 + command, ppath);
178 181 return (1);
179 182 }
180 183
181 - (void) strcpy(pname, "/proc");
184 + (void) strcpy(pname, ppath);
182 185 pdlen = strlen(pname);
183 186 pname[pdlen++] = '/';
184 187
185 188 /* for each active process --- */
186 189 while (dentp = readdir(dirp)) {
187 190 int procfd; /* filedescriptor for /proc/nnnnn/psinfo */
188 191
189 192 if (dentp->d_name[0] == '.') /* skip . and .. */
190 193 continue;
191 194 (void) strcpy(pname + pdlen, dentp->d_name);
192 195 (void) strcpy(pname + strlen(pname), "/psinfo");
193 196 retry:
194 197 if ((procfd = open(pname, O_RDONLY)) == -1)
195 198 continue;
196 199
197 200 /*
198 201 * Get the info structure for the process and close quickly.
199 202 */
200 203 if (read(procfd, &info, sizeof (info)) != sizeof (info)) {
201 204 int saverr = errno;
202 205
203 206 (void) close(procfd);
204 207 if (saverr == EAGAIN)
205 208 goto retry;
206 209 if (saverr != ENOENT)
207 210 perror(pname);
208 211 continue;
209 212 }
210 213 (void) close(procfd);
211 214
212 215 /*
213 216 * We make sure there's always a free slot in the table
214 217 * in case we need to add a fake p0.
215 218 */
216 219 if (nps + 1 >= psize) {
217 220 if ((psize *= 2) == 0)
218 221 psize = 20;
219 222 if ((ps = realloc(ps, psize*sizeof (ps_t *))) == NULL) {
220 223 perror("realloc()");
221 224 return (1);
222 225 }
223 226 }
224 227 if ((p = malloc(sizeof (ps_t))) == NULL) {
225 228 perror("malloc()");
226 229 return (1);
227 230 }
228 231 ps[nps++] = p;
229 232 p->done = 0;
230 233 p->uid = info.pr_uid;
231 234 p->gid = info.pr_gid;
232 235 p->pid = info.pr_pid;
233 236 p->ppid = info.pr_ppid;
234 237 p->pgrp = info.pr_pgid;
235 238 p->sid = info.pr_sid;
236 239 p->zoneid = info.pr_zoneid;
237 240 p->ctid = info.pr_contract;
238 241 p->start = info.pr_start;
239 242 proc_unctrl_psinfo(&info);
240 243 if (info.pr_nlwp == 0)
241 244 (void) strcpy(p->psargs, "<defunct>");
242 245 else if (info.pr_psargs[0] == '\0')
243 246 (void) strncpy(p->psargs, info.pr_fname,
244 247 sizeof (p->psargs));
245 248 else
246 249 (void) strncpy(p->psargs, info.pr_psargs,
247 250 sizeof (p->psargs));
248 251 p->psargs[sizeof (p->psargs)-1] = '\0';
249 252 p->pp = NULL;
250 253 p->sp = NULL;
251 254 p->cp = NULL;
252 255 if (p->pid == p->ppid)
253 256 proc0 = p;
254 257 if (p->pid == 1)
255 258 proc1 = p;
256 259 }
257 260
258 261 (void) closedir(dirp);
259 262 if (proc0 == NULL)
260 263 proc0 = fakepid0();
261 264 if (proc1 == NULL)
262 265 proc1 = proc0;
263 266
264 267 for (n = 0; n < nps; n++) {
265 268 p = ps[n];
266 269 if (p->pp == NULL)
267 270 prsort(p);
268 271 }
269 272
270 273 if (cflag)
271 274 /* Parent all orphan contracts to process 0. */
272 275 for (n = 0; n < nctps; n++) {
273 276 p = ctps[n];
274 277 if (p->pp == NULL)
275 278 insertchild(proc0, p);
276 279 }
277 280
278 281 if (argc == 0) {
279 282 for (p = aflag ? proc0->cp : proc1->cp; p != NULL; p = p->sp) {
280 283 markprocs(p);
281 284 printsubtree(p, 0);
282 285 }
283 286 return (0);
284 287 }
285 288
286 289 /*
287 290 * Initially, assume we're not going to find any processes. If we do
288 291 * mark any, then set this to 0 to indicate no error.
289 292 */
290 293 errflg = 1;
291 294
292 295 while (argc-- > 0) {
293 296 char *arg;
294 297 char *next;
295 298 pid_t pid;
296 299 uid_t uid;
297 300 int n;
298 301
299 302 /* in case some silly person said 'ptree /proc/[0-9]*' */
300 303 arg = strrchr(*argv, '/');
301 304 if (arg++ == NULL)
302 305 arg = *argv;
303 306 argv++;
304 307 uid = (uid_t)-1;
305 308 errno = 0;
306 309 pid = strtoul(arg, &next, 10);
307 310 if (errno != 0 || *next != '\0') {
308 311 struct passwd *pw = getpwnam(arg);
309 312 if (pw == NULL) {
310 313 (void) fprintf(stderr,
311 314 "%s: invalid username: %s\n",
312 315 command, arg);
313 316 retc = 1;
314 317 continue;
315 318 }
316 319 uid = pw->pw_uid;
317 320 pid = -1;
318 321 }
319 322
320 323 for (n = 0; n < nps; n++) {
321 324 ps_t *p = ps[n];
322 325
323 326 /*
324 327 * A match on pid causes the subtree starting at pid
325 328 * to be printed, regardless of the -a flag.
326 329 * For uid matches, we never include pid 0 and only
327 330 * include the children of pid 0 if -a was specified.
328 331 */
329 332 if (p->pid == pid || (p->uid == uid && p->pid != 0 &&
330 333 (p->ppid != 0 || aflag))) {
331 334 errflg = 0;
332 335 markprocs(p);
333 336 if (p->pid != 0)
334 337 for (p = p->pp; p != NULL &&
335 338 p->done != 1 && p->pid != 0;
336 339 p = p->pp)
337 340 if ((p->ppid != 0 || aflag) &&
338 341 (!zflag ||
339 342 p->zoneid == zoneid))
340 343 p->done = 1;
341 344 if (uid == (uid_t)-1)
342 345 break;
343 346 }
344 347 }
345 348 }
346 349
347 350 printsubtree(proc0, 0);
348 351 /*
349 352 * retc = 1 if an invalid username was supplied.
350 353 * errflg = 1 if no matching processes were found.
351 354 */
352 355 return (retc || errflg);
353 356 }
354 357
355 358 #define PIDWIDTH 5
356 359
357 360 static int
358 361 printone(ps_t *p, int level)
359 362 {
360 363 int n, indent;
361 364
362 365 if (p->done && !FAKEDPID0(p)) {
363 366 indent = level * 2;
364 367 if ((n = columns - PIDWIDTH - indent - 2) < 0)
365 368 n = 0;
366 369 if (p->pid >= 0) {
367 370 (void) printf("%*.*s%-*d %.*s\n", indent, indent, " ",
368 371 PIDWIDTH, (int)p->pid, n, p->psargs);
369 372 } else {
370 373 assert(cflag != 0);
371 374 (void) printf("%*.*s[process contract %d]\n",
372 375 indent, indent, " ", (int)p->ctid);
373 376 }
374 377 return (1);
375 378 }
376 379 return (0);
377 380 }
378 381
379 382 static void
380 383 insertchild(ps_t *pp, ps_t *cp)
381 384 {
382 385 /* insert as child process of p */
383 386 ps_t **here;
384 387 ps_t *sp;
385 388
386 389 /* sort by start time */
387 390 for (here = &pp->cp, sp = pp->cp;
388 391 sp != NULL;
389 392 here = &sp->sp, sp = sp->sp) {
390 393 if (cp->start.tv_sec < sp->start.tv_sec)
391 394 break;
392 395 if (cp->start.tv_sec == sp->start.tv_sec &&
393 396 cp->start.tv_nsec < sp->start.tv_nsec)
394 397 break;
395 398 }
396 399 cp->pp = pp;
397 400 cp->sp = sp;
398 401 *here = cp;
399 402 }
400 403
401 404 static void
402 405 ctsort(ctid_t ctid, ps_t *p)
403 406 {
404 407 ps_t *pp;
405 408 int fd, n;
406 409 ct_stathdl_t hdl;
407 410 struct stat64 st;
408 411
409 412 for (n = 0; n < nctps; n++)
410 413 if (ctps[n]->ctid == ctid) {
411 414 insertchild(ctps[n], p);
412 415 return;
413 416 }
414 417
415 418 if ((fd = contract_open(ctid, "process", "status", O_RDONLY)) == -1)
416 419 return;
417 420 if (fstat64(fd, &st) == -1 || ct_status_read(fd, CTD_COMMON, &hdl)) {
418 421 (void) close(fd);
419 422 return;
420 423 }
421 424 (void) close(fd);
422 425
423 426 if (nctps >= ctsize) {
424 427 if ((ctsize *= 2) == 0)
425 428 ctsize = 20;
426 429 if ((ctps = realloc(ctps, ctsize * sizeof (ps_t *))) == NULL) {
427 430 perror("realloc()");
428 431 exit(1);
429 432 }
430 433 }
431 434 pp = calloc(sizeof (ps_t), 1);
432 435 if (pp == NULL) {
433 436 perror("calloc()");
434 437 exit(1);
435 438 }
436 439 ctps[nctps++] = pp;
437 440
438 441 pp->pid = -1;
439 442 pp->ctid = ctid;
440 443 pp->start.tv_sec = st.st_ctime;
441 444 insertchild(pp, p);
442 445
443 446 pp->zoneid = ct_status_get_zoneid(hdl);
444 447 /*
445 448 * In a zlogin <zonename>, the contract belongs to the
446 449 * global zone and the shell opened belongs to <zonename>.
447 450 * If the -c and -z zonename flags are used together, then
448 451 * we need to adjust the zoneid in the contract's ps_t as
449 452 * follows:
450 453 *
451 454 * ptree -c -z <zonename> --> zoneid == p->zoneid
452 455 * ptree -c -z global --> zoneid == pp->zoneid
453 456 *
454 457 * The approach assumes that no tool can create processes in
455 458 * different zones under the same contract. If this is
456 459 * possible, ptree will need to refactor how it builds
457 460 * its internal tree of ps_t's
458 461 */
459 462 if (zflag && p->zoneid != pp->zoneid &&
460 463 (zoneid == p->zoneid || zoneid == pp->zoneid))
461 464 pp->zoneid = p->zoneid;
462 465 if (ct_status_get_state(hdl) == CTS_OWNED) {
463 466 pp->ppid = ct_status_get_holder(hdl);
464 467 prsort(pp);
465 468 } else if (ct_status_get_state(hdl) == CTS_INHERITED) {
466 469 ctsort(ct_status_get_holder(hdl), pp);
467 470 }
468 471 ct_status_free(hdl);
469 472 }
470 473
471 474 static void
472 475 prsort(ps_t *p)
473 476 {
474 477 int n;
475 478 ps_t *pp;
476 479
477 480 /* If this node already has a parent, it's sorted */
478 481 if (p->pp != NULL)
479 482 return;
480 483
481 484 for (n = 0; n < nps; n++) {
482 485 pp = ps[n];
483 486
484 487 if (pp != NULL && p != pp && p->ppid == pp->pid) {
485 488 if (cflag && p->pid >= 0 &&
486 489 p->ctid != -1 && p->ctid != pp->ctid) {
487 490 ctsort(p->ctid, p);
488 491 } else {
489 492 insertchild(pp, p);
490 493 prsort(pp);
491 494 }
492 495 return;
493 496 }
494 497 }
495 498
496 499 /* File parentless processes under their contracts */
497 500 if (cflag && p->pid >= 0)
498 501 ctsort(p->ctid, p);
499 502 }
500 503
501 504 static void
502 505 printsubtree(ps_t *p, int level)
503 506 {
504 507 int printed;
505 508
506 509 printed = printone(p, level);
507 510 if (level != 0 || printed == 1)
508 511 level++;
509 512 for (p = p->cp; p != NULL; p = p->sp)
510 513 printsubtree(p, level);
511 514 }
512 515
513 516 static void
514 517 markprocs(ps_t *p)
515 518 {
516 519 if (!zflag || p->zoneid == zoneid)
517 520 p->done = 1;
518 521 for (p = p->cp; p != NULL; p = p->sp)
519 522 markprocs(p);
520 523 }
521 524
522 525 /*
523 526 * If there's no "top" process, we fake one; it will be the parent of
524 527 * all orphans.
525 528 */
526 529 static ps_t *
527 530 fakepid0(void)
528 531 {
529 532 ps_t *p0, *p;
530 533 int n;
531 534
532 535 if ((p0 = malloc(sizeof (ps_t))) == NULL) {
533 536 perror("malloc()");
534 537 exit(1);
535 538 }
536 539 (void) memset(p0, '\0', sizeof (ps_t));
537 540
538 541 /* First build all partial process trees. */
539 542 for (n = 0; n < nps; n++) {
540 543 p = ps[n];
541 544 if (p->pp == NULL)
542 545 prsort(p);
543 546 }
544 547
545 548 /* Then adopt all orphans. */
546 549 for (n = 0; n < nps; n++) {
547 550 p = ps[n];
548 551 if (p->pp == NULL)
549 552 insertchild(p0, p);
550 553 }
551 554
552 555 /* We've made sure earlier there's room for this. */
553 556 ps[nps++] = p0;
554 557 return (p0);
555 558 }
556 559
557 560 /* convert string containing zone name or id to a numeric id */
558 561 static zoneid_t
559 562 getzone(char *arg)
560 563 {
561 564 zoneid_t zoneid;
562 565
563 566 if (zone_get_id(arg, &zoneid) != 0) {
564 567 (void) fprintf(stderr, "%s: unknown zone: %s\n", command, arg);
565 568 exit(1);
566 569 }
567 570 return (zoneid);
568 571 }
|
↓ open down ↓ |
377 lines elided |
↑ open up ↑ |
XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX