Print this page
11691 ptree could show service FMRIs
Reviewed by: Jerry Jelinek <jerry.jelinek@joyent.com>
Reviewed by: Jason King <jason.king@joyent.com>
Reviewed by: Andy Fiddaman <andy@omniosce.org>

*** 1,6 **** ! /* * CDDL HEADER START * * The contents of this file are subject to the terms of the * Common Development and Distribution License (the "License"). * You may not use this file except in compliance with the License. --- 1,6 ---- ! /* * CDDL HEADER START * * The contents of this file are subject to the terms of the * Common Development and Distribution License (the "License"). * You may not use this file except in compliance with the License.
*** 19,36 **** * CDDL HEADER END */ /* * Copyright 2007 Sun Microsystems, Inc. All rights reserved. * Use is subject to license terms. */ /* * ptree -- print family tree of processes */ - #pragma ident "%Z%%M% %I% %E% SMI" - #include <assert.h> #include <stdio.h> #include <string.h> #include <errno.h> #include <fcntl.h> --- 19,35 ---- * CDDL HEADER END */ /* * Copyright 2007 Sun Microsystems, Inc. All rights reserved. * Use is subject to license terms. + * Copyright 2019 Joyent, Inc. */ /* * ptree -- print family tree of processes */ #include <assert.h> #include <stdio.h> #include <string.h> #include <errno.h> #include <fcntl.h>
*** 46,55 **** --- 45,55 ---- #include <libcontract.h> #include <sys/contract.h> #include <sys/ctfs.h> #include <libcontract_priv.h> #include <sys/stat.h> + #include <stdbool.h> #define FAKEDPID0(p) (p->pid == 0 && p->psargs[0] == '\0') typedef struct ps { int done;
*** 59,68 **** --- 59,69 ---- pid_t ppid; pid_t pgrp; pid_t sid; zoneid_t zoneid; ctid_t ctid; + char *svc_fmri; timestruc_t start; char psargs[PRARGSZ]; struct ps *pp; /* parent */ struct ps *sp; /* sibling */ struct ps *cp; /* child */
*** 79,98 **** static char *command; static int aflag = 0; static int cflag = 0; static int zflag = 0; static zoneid_t zoneid; static int columns = 80; ! static void markprocs(ps_t *p); ! static int printone(ps_t *p, int level); static void insertchild(ps_t *, ps_t *); ! static void prsort(ps_t *p); ! static void printsubtree(ps_t *p, int level); ! static zoneid_t getzone(char *arg); static ps_t *fakepid0(void); int main(int argc, char **argv) { --- 80,105 ---- static char *command; static int aflag = 0; static int cflag = 0; + static int sflag = 0; static int zflag = 0; static zoneid_t zoneid; + static char *match_svc; + static char *match_inst; static int columns = 80; ! static bool match_proc(ps_t *); ! static void markprocs(ps_t *); ! static int printone(ps_t *, int); static void insertchild(ps_t *, ps_t *); ! static void prsort(ps_t *); ! static void printsubtree(ps_t *, int); ! static void p_get_svc_fmri(ps_t *, ct_stathdl_t); ! static char *parse_svc(const char *, char **); ! static zoneid_t getzone(const char *); static ps_t *fakepid0(void); int main(int argc, char **argv) {
*** 115,132 **** command = argv[0]; else command++; /* options */ ! while ((opt = getopt(argc, argv, "acz:")) != EOF) { switch (opt) { case 'a': /* include children of process 0 */ aflag = 1; break; case 'c': /* display contract ownership */ aflag = cflag = 1; break; case 'z': /* only processes in given zone */ zflag = 1; zoneid = getzone(optarg); break; default: --- 122,143 ---- command = argv[0]; else command++; /* options */ ! while ((opt = getopt(argc, argv, "acs:z:")) != EOF) { switch (opt) { case 'a': /* include children of process 0 */ aflag = 1; break; case 'c': /* display contract ownership */ aflag = cflag = 1; break; + case 's': + sflag = 1; + match_svc = parse_svc(optarg, &match_inst); + break; case 'z': /* only processes in given zone */ zflag = 1; zoneid = getzone(optarg); break; default:
*** 138,158 **** argc -= optind; argv += optind; if (errflg) { (void) fprintf(stderr, ! "usage:\t%s [-ac] [-z zone] [ {pid|user} ... ]\n", command); (void) fprintf(stderr, " (show process trees)\n"); (void) fprintf(stderr, " list can include process-ids and user names\n"); (void) fprintf(stderr, " -a : include children of process 0\n"); (void) fprintf(stderr, ! " -c : show contract ownership\n"); (void) fprintf(stderr, " -z : print only processes in given zone\n"); return (2); } /* --- 149,171 ---- argc -= optind; argv += optind; if (errflg) { (void) fprintf(stderr, ! "usage:\t%s [-ac] [-s svc] [-z zone] [ {pid|user} ... ]\n", command); (void) fprintf(stderr, " (show process trees)\n"); (void) fprintf(stderr, " list can include process-ids and user names\n"); (void) fprintf(stderr, " -a : include children of process 0\n"); (void) fprintf(stderr, ! " -c : show contracts\n"); (void) fprintf(stderr, + " -s : print only processes with given service FMRI\n"); + (void) fprintf(stderr, " -z : print only processes in given zone\n"); return (2); } /*
*** 219,230 **** if ((ps = realloc(ps, psize*sizeof (ps_t *))) == NULL) { perror("realloc()"); return (1); } } ! if ((p = malloc(sizeof (ps_t))) == NULL) { ! perror("malloc()"); return (1); } ps[nps++] = p; p->done = 0; p->uid = info.pr_uid; --- 232,243 ---- if ((ps = realloc(ps, psize*sizeof (ps_t *))) == NULL) { perror("realloc()"); return (1); } } ! if ((p = calloc(1, sizeof (ps_t))) == NULL) { ! perror("calloc()"); return (1); } ps[nps++] = p; p->done = 0; p->uid = info.pr_uid;
*** 247,256 **** --- 260,273 ---- sizeof (p->psargs)); p->psargs[sizeof (p->psargs)-1] = '\0'; p->pp = NULL; p->sp = NULL; p->cp = NULL; + + if (sflag) + p_get_svc_fmri(p, NULL); + if (p->pid == p->ppid) proc0 = p; if (p->pid == 1) proc1 = p; }
*** 333,344 **** if (p->pid != 0) for (p = p->pp; p != NULL && p->done != 1 && p->pid != 0; p = p->pp) if ((p->ppid != 0 || aflag) && ! (!zflag || ! p->zoneid == zoneid)) p->done = 1; if (uid == (uid_t)-1) break; } } --- 350,360 ---- if (p->pid != 0) for (p = p->pp; p != NULL && p->done != 1 && p->pid != 0; p = p->pp) if ((p->ppid != 0 || aflag) && ! match_proc(p)) p->done = 1; if (uid == (uid_t)-1) break; } }
*** 366,377 **** if (p->pid >= 0) { (void) printf("%*.*s%-*d %.*s\n", indent, indent, " ", PIDWIDTH, (int)p->pid, n, p->psargs); } else { assert(cflag != 0); ! (void) printf("%*.*s[process contract %d]\n", ! indent, indent, " ", (int)p->ctid); } return (1); } return (0); } --- 382,394 ---- if (p->pid >= 0) { (void) printf("%*.*s%-*d %.*s\n", indent, indent, " ", PIDWIDTH, (int)p->pid, n, p->psargs); } else { assert(cflag != 0); ! (void) printf("%*.*s[process contract %d: %s]\n", ! indent, indent, " ", (int)p->ctid, ! p->svc_fmri == NULL ? "?" : p->svc_fmri); } return (1); } return (0); }
*** 396,426 **** cp->pp = pp; cp->sp = sp; *here = cp; } static void ctsort(ctid_t ctid, ps_t *p) { ps_t *pp; ! int fd, n; ct_stathdl_t hdl; struct stat64 st; for (n = 0; n < nctps; n++) if (ctps[n]->ctid == ctid) { insertchild(ctps[n], p); return; } ! if ((fd = contract_open(ctid, "process", "status", O_RDONLY)) == -1) return; - if (fstat64(fd, &st) == -1 || ct_status_read(fd, CTD_COMMON, &hdl)) { - (void) close(fd); - return; - } - (void) close(fd); if (nctps >= ctsize) { if ((ctsize *= 2) == 0) ctsize = 20; if ((ctps = realloc(ctps, ctsize * sizeof (ps_t *))) == NULL) { --- 413,477 ---- cp->pp = pp; cp->sp = sp; *here = cp; } + static ct_stathdl_t + ct_status_open(ctid_t ctid, struct stat64 *stp) + { + ct_stathdl_t hdl; + int fd; + + if ((fd = contract_open(ctid, "process", "status", O_RDONLY)) == -1) + return (NULL); + + if (fstat64(fd, stp) == -1 || ct_status_read(fd, CTD_FIXED, &hdl)) { + (void) close(fd); + return (NULL); + } + + (void) close(fd); + + return (hdl); + } + + /* + * strdup() failure is OK - better to report something than fail totally. + */ static void + p_get_svc_fmri(ps_t *p, ct_stathdl_t inhdl) + { + ct_stathdl_t hdl = inhdl; + struct stat64 st; + char *fmri; + + if (hdl == NULL && (hdl = ct_status_open(p->ctid, &st)) == NULL) + return; + + if (ct_pr_status_get_svc_fmri(hdl, &fmri) == 0) + p->svc_fmri = strdup(fmri); + + if (inhdl == NULL) + ct_status_free(hdl); + } + + static void ctsort(ctid_t ctid, ps_t *p) { ps_t *pp; ! int n; ct_stathdl_t hdl; struct stat64 st; for (n = 0; n < nctps; n++) if (ctps[n]->ctid == ctid) { insertchild(ctps[n], p); return; } ! if ((hdl = ct_status_open(ctid, &st)) == NULL) return; if (nctps >= ctsize) { if ((ctsize *= 2) == 0) ctsize = 20; if ((ctps = realloc(ctps, ctsize * sizeof (ps_t *))) == NULL) {
*** 435,448 **** --- 486,503 ---- } ctps[nctps++] = pp; pp->pid = -1; pp->ctid = ctid; + + p_get_svc_fmri(pp, hdl); + pp->start.tv_sec = st.st_ctime; insertchild(pp, p); pp->zoneid = ct_status_get_zoneid(hdl); + /* * In a zlogin <zonename>, the contract belongs to the * global zone and the shell opened belongs to <zonename>. * If the -c and -z zonename flags are used together, then * we need to adjust the zoneid in the contract's ps_t as
*** 508,522 **** level++; for (p = p->cp; p != NULL; p = p->sp) printsubtree(p, level); } static void markprocs(ps_t *p) { ! if (!zflag || p->zoneid == zoneid) p->done = 1; for (p = p->cp; p != NULL; p = p->sp) markprocs(p); } /* --- 563,617 ---- level++; for (p = p->cp; p != NULL; p = p->sp) printsubtree(p, level); } + /* + * Match against the service name (and just the final component), and any + * specified instance name. + */ + static bool + match_proc(ps_t *p) + { + bool matched = false; + const char *cp; + char *p_inst; + char *p_svc; + + if (zflag && p->zoneid != zoneid) + return (false); + + if (!sflag) + return (true); + + if (p->svc_fmri == NULL) + return (false); + + p_svc = parse_svc(p->svc_fmri, &p_inst); + + if (strcmp(p_svc, match_svc) != 0 && + ((cp = strrchr(p_svc, '/')) == NULL || + strcmp(cp + 1, match_svc) != 0)) { + goto out; + } + + if (strlen(match_inst) == 0 || + strcmp(p_inst, match_inst) == 0) + matched = true; + + out: + free(p_svc); + free(p_inst); + return (matched); + } + static void markprocs(ps_t *p) { ! if (match_proc(p)) p->done = 1; + for (p = p->cp; p != NULL; p = p->sp) markprocs(p); } /*
*** 527,538 **** fakepid0(void) { ps_t *p0, *p; int n; ! if ((p0 = malloc(sizeof (ps_t))) == NULL) { ! perror("malloc()"); exit(1); } (void) memset(p0, '\0', sizeof (ps_t)); /* First build all partial process trees. */ --- 622,633 ---- fakepid0(void) { ps_t *p0, *p; int n; ! if ((p0 = calloc(1, sizeof (ps_t))) == NULL) { ! perror("calloc()"); exit(1); } (void) memset(p0, '\0', sizeof (ps_t)); /* First build all partial process trees. */
*** 554,568 **** return (p0); } /* convert string containing zone name or id to a numeric id */ static zoneid_t ! getzone(char *arg) { zoneid_t zoneid; if (zone_get_id(arg, &zoneid) != 0) { (void) fprintf(stderr, "%s: unknown zone: %s\n", command, arg); exit(1); } return (zoneid); } --- 649,694 ---- return (p0); } /* convert string containing zone name or id to a numeric id */ static zoneid_t ! getzone(const char *arg) { zoneid_t zoneid; if (zone_get_id(arg, &zoneid) != 0) { (void) fprintf(stderr, "%s: unknown zone: %s\n", command, arg); exit(1); } return (zoneid); + } + + /* svc:/mysvc:default -> mysvc, default */ + static char * + parse_svc(const char *arg, char **instp) + { + const char *p = arg; + char *ret; + char *cp; + + if (strncmp(p, "svc:/", strlen("svc:/")) == 0) + p += strlen("svc:/"); + + if ((ret = strdup(p)) == NULL) { + perror("strdup()"); + exit(1); + } + + if ((cp = strrchr(ret, ':')) != NULL) { + *cp = '\0'; + cp++; + } else { + cp = ""; + } + + if ((*instp = strdup(cp)) == NULL) { + perror("strdup()"); + exit(1); + } + + return (ret); }