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);
}