/*
* 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.
*
* You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
* See the License for the specific language governing permissions
* and limitations under the License.
*
* When distributing Covered Code, include this CDDL HEADER in each
* file and include the License file at usr/src/OPENSOLARIS.LICENSE.
* If applicable, add the following below this CDDL HEADER, with the
* fields enclosed by brackets "[]" replaced with your own identifying
* information: Portions Copyright [yyyy] [name of copyright owner]
*
* 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>
#include <unistd.h>
#include <stdlib.h>
#include <dirent.h>
#include <pwd.h>
#include <libproc.h>
#include <libzonecfg.h>
#include <limits.h>
#include <libcontract.h>
#include <sys/contract.h>
#include <libcontract_priv.h>
typedef struct ps {
int done;
} ps_t;
static char *command;
static int aflag = 0;
static int cflag = 0;
static int zflag = 0;
int
{
int opt;
int errflg = 0;
char *s;
int n;
int retc = 0;
int pdlen;
ps_t *p;
else
command++;
/* options */
switch (opt) {
case 'a': /* include children of process 0 */
aflag = 1;
break;
case 'c': /* display contract ownership */
break;
case 'z': /* only processes in given zone */
zflag = 1;
break;
default:
errflg = 1;
break;
}
}
if (errflg) {
"usage:\t%s [-ac] [-z zone] [ {pid|user} ... ]\n",
command);
" (show process trees)\n");
" list can include process-ids and user names\n");
" -a : include children of process 0\n");
" -c : show contract ownership\n");
" -z : print only processes in given zone\n");
return (2);
}
/*
* Kind of a hack to determine the width of the output...
*/
columns = n;
nps = 0;
psize = 0;
/*
* Search the /proc directory for all processes.
*/
command);
return (1);
}
/* for each active process --- */
continue;
continue;
/*
* Get the info structure for the process and close quickly.
*/
goto retry;
continue;
}
/*
* We make sure there's always a free slot in the table
* in case we need to add a fake p0.
*/
if ((psize *= 2) == 0)
psize = 20;
perror("realloc()");
return (1);
}
}
perror("malloc()");
return (1);
}
p->done = 0;
sizeof (p->psargs));
else
sizeof (p->psargs));
proc0 = p;
if (p->pid == 1)
proc1 = p;
}
for (n = 0; n < nps; n++) {
p = ps[n];
prsort(p);
}
if (cflag)
/* Parent all orphan contracts to process 0. */
for (n = 0; n < nctps; n++) {
p = ctps[n];
insertchild(proc0, p);
}
if (argc == 0) {
markprocs(p);
printsubtree(p, 0);
}
return (0);
}
/*
* Initially, assume we're not going to find any processes. If we do
* mark any, then set this to 0 to indicate no error.
*/
errflg = 1;
while (argc-- > 0) {
char *arg;
char *next;
int n;
/* in case some silly person said 'ptree /proc/[0-9]*' */
argv++;
errno = 0;
"%s: invalid username: %s\n",
retc = 1;
continue;
}
pid = -1;
}
for (n = 0; n < nps; n++) {
/*
* A match on pid causes the subtree starting at pid
* to be printed, regardless of the -a flag.
* For uid matches, we never include pid 0 and only
* include the children of pid 0 if -a was specified.
*/
errflg = 0;
markprocs(p);
if (p->pid != 0)
p = p->pp)
(!zflag ||
p->done = 1;
break;
}
}
}
printsubtree(proc0, 0);
/*
* retc = 1 if an invalid username was supplied.
* errflg = 1 if no matching processes were found.
*/
}
static int
{
int n, indent;
n = 0;
if (p->pid >= 0) {
} else {
(void) printf("%*.*s[process contract %d]\n",
}
return (1);
}
return (0);
}
static void
{
/* insert as child process of p */
/* sort by start time */
break;
break;
}
}
static void
{
int fd, n;
for (n = 0; n < nctps; n++)
insertchild(ctps[n], p);
return;
}
return;
return;
}
if ((ctsize *= 2) == 0)
ctsize = 20;
perror("realloc()");
exit(1);
}
}
perror("calloc()");
exit(1);
}
insertchild(pp, p);
/*
* 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
* follows:
*
* ptree -c -z <zonename> --> zoneid == p->zoneid
* ptree -c -z global --> zoneid == pp->zoneid
*
* The approach assumes that no tool can create processes in
* different zones under the same contract. If this is
* possible, ptree will need to refactor how it builds
* its internal tree of ps_t's
*/
}
}
static void
{
int n;
/* If this node already has a parent, it's sorted */
return;
for (n = 0; n < nps; n++) {
} else {
insertchild(pp, p);
}
return;
}
}
/* File parentless processes under their contracts */
}
static void
{
int printed;
level++;
printsubtree(p, level);
}
static void
{
p->done = 1;
markprocs(p);
}
/*
* If there's no "top" process, we fake one; it will be the parent of
* all orphans.
*/
static ps_t *
fakepid0(void)
{
int n;
perror("malloc()");
exit(1);
}
/* First build all partial process trees. */
for (n = 0; n < nps; n++) {
p = ps[n];
prsort(p);
}
/* Then adopt all orphans. */
for (n = 0; n < nps; n++) {
p = ps[n];
insertchild(p0, p);
}
/* We've made sure earlier there's room for this. */
return (p0);
}
/* convert string containing zone name or id to a numeric id */
static zoneid_t
{
exit(1);
}
return (zoneid);
}