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 +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,18 +19,17 @@
* 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
*/
-#pragma ident "%Z%%M% %I% %E% SMI"
-
#include <assert.h>
#include <stdio.h>
#include <string.h>
#include <errno.h>
#include <fcntl.h>
@@ -46,10 +45,11 @@
#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,10 +59,11 @@
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,20 +80,26 @@
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 void markprocs(ps_t *p);
-static int printone(ps_t *p, int level);
+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 *p);
-static void printsubtree(ps_t *p, int level);
-static zoneid_t getzone(char *arg);
+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,18 +122,22 @@
command = argv[0];
else
command++;
/* options */
- while ((opt = getopt(argc, argv, "acz:")) != EOF) {
+ 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,21 +149,23 @@
argc -= optind;
argv += optind;
if (errflg) {
(void) fprintf(stderr,
- "usage:\t%s [-ac] [-z zone] [ {pid|user} ... ]\n",
+ "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 contract ownership\n");
+ " -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,12 +232,12 @@
if ((ps = realloc(ps, psize*sizeof (ps_t *))) == NULL) {
perror("realloc()");
return (1);
}
}
- if ((p = malloc(sizeof (ps_t))) == NULL) {
- perror("malloc()");
+ if ((p = calloc(1, sizeof (ps_t))) == NULL) {
+ perror("calloc()");
return (1);
}
ps[nps++] = p;
p->done = 0;
p->uid = info.pr_uid;
@@ -247,10 +260,14 @@
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,12 +350,11 @@
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))
+ match_proc(p))
p->done = 1;
if (uid == (uid_t)-1)
break;
}
}
@@ -366,12 +382,13 @@
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);
+ (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,31 +413,65 @@
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 fd, n;
+ 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 ((fd = contract_open(ctid, "process", "status", O_RDONLY)) == -1)
+ if ((hdl = ct_status_open(ctid, &st)) == NULL)
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) {
@@ -435,14 +486,18 @@
}
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,15 +563,55 @@
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 (!zflag || p->zoneid == zoneid)
+ if (match_proc(p))
p->done = 1;
+
for (p = p->cp; p != NULL; p = p->sp)
markprocs(p);
}
/*
@@ -527,12 +622,12 @@
fakepid0(void)
{
ps_t *p0, *p;
int n;
- if ((p0 = malloc(sizeof (ps_t))) == NULL) {
- perror("malloc()");
+ 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,15 +649,46 @@
return (p0);
}
/* convert string containing zone name or id to a numeric id */
static zoneid_t
-getzone(char *arg)
+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);
}