/*
* 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 2015, Joyent, Inc.
*/
#include <unistd.h>
#include <rctl.h>
#include <libproc.h>
#include <stdio.h>
#include <libintl.h>
#include <locale.h>
#include <string.h>
#include <signal.h>
#include <strings.h>
#include <ctype.h>
#include <project.h>
#include <dirent.h>
#include <errno.h>
#include <stdlib.h>
#include <priv.h>
#include <zone.h>
#include "utils.h"
/* Valid user actions */
/* Maximum string length for deferred errors */
/* allow important process values to be passed together easily */
typedef struct pr_info_handle {
char *projname;
char *zonename;
/* Structures for list of resource controls */
typedef struct prctl_value {
typedef struct prctl_list {
char *name;
} prctl_list_t;
static volatile int interrupt;
/* global variables that contain commmand line option info */
static int arg_operation = 0;
static int arg_force = 0;
/* String and type from -i */
/* -n argument */
/* -t argument value */
static int arg_priv = 0;
/* -v argument string */
/* global flags of rctl name passed to -n */
static int arg_global_flags = 0;
/* appropriate scaling variables determined by rctl unit type */
/* -v argument string converted to uint64_t */
/* if -v argument is scaled value, points to "K", "M", "G", ... */
/* -e/-d argument string */
/* Set to RCTL_LOCAL_SIGNAL|DENY based on arg_action_string */
static int arg_action = 0;
/* if -e/-d arg is signal=XXX, set to signal number of XXX */
static int arg_signal = 0;
/* -p arg if -p is specified */
/* Set to 1 if -P is specified */
static int arg_parseable_mode = 0;
/* interupt handler */
static void intr(int);
static int get_rctls(struct ps_prochandle *);
static void free_lists();
int pidin);
pr_info_handle_t *p, int, int *gret);
static void preserve_error(char *format, ...);
static void print_rctls(pr_info_handle_t *p);
"usage:\n"
" Report resource control values and actions:\n"
" prctl [-P] [-t [basic | privileged | system]\n"
" [-n name] [-i process | task | project | zone] id ...\n"
" -P space delimited output\n"
" -t privilege level of rctl values to get\n"
" -n name of resource control values to get\n"
" -i idtype of operand list\n"
" Manipulate resource control values:\n"
" prctl [-t [basic | privileged | system]\n"
" -n name [-srx] [-v value] [-p pid ] [-e | -d action]\n"
" [-i process | task | project | zone] id ...\n"
" -s set new resource control value\n"
" -r replace first rctl value of matching privilege\n"
" -x delete first rctl value of matching privilege, value, and \n"
" recipient pid\n"
" -e enable action of first rctl value of matching privilege,\n"
" value, and recipient pid\n"
" -d disable action of first rctl value of matching privilege,\n"
" value, and recipient pid\n"
" -i idtype of operand list\n";
static void
usage()
{
exit(2);
}
int
{
int flags;
char *target_id;
int search_type;
int signal;
int localaction;
int printed = 0;
int gret;
char *end;
(void) textdomain(TEXT_DOMAIN);
switch (opt) {
case 'F': /* force grabbing (no O_EXCL) */
break;
case 'i': /* id type for arguments */
else {
errflg = 1;
}
break;
case 'd':
break;
case 'e':
break;
case 'n': /* name of rctl */
strlen("process.")) == 0)
strlen("project.")) == 0)
strlen("task.")) == 0)
strlen("zone.")) == 0)
break;
case 'r':
break;
case 't': /* rctl type */
else {
errflg = 1;
}
break;
case 'v': /* value */
break;
case 's':
break;
case 'x': /* delete */
break;
case 'p':
errno = 0;
/* Stick with -1 if arg is "-" */
break;
errflg = 1;
break;
}
break;
case 'P':
arg_parseable_mode = 1;
break;
default:
errflg = 1;
break;
}
}
if (argc < 1) {
errflg = 1;
goto done_parse;
}
/* if -v is specified without -r, -x, -d, or -e, -s is implied */
if (arg_valuestring &&
ACTION_DISABLE | ACTION_ENABLE)))) {
}
/* operations require -n */
errflg = 1;
goto done_parse;
}
/* enable and disable are exclusive */
if ((arg_operation & ACTION_ENABLE) &&
(arg_operation & ACTION_DISABLE)) {
errflg = 1;
goto done_parse;
}
/* -s, -r, and -x are exclusive */
flags = arg_operation &
errflg = 1;
goto done_parse;
}
/* -e or -d makes no sense with -x */
if ((arg_operation & ACTION_DELETE) &
errflg = 1;
goto done_parse;
}
/* if -r is specified -v must be as well */
errflg = 1;
goto done_parse;
}
/* if -s is specified -v must be as well */
errflg = 1;
goto done_parse;
}
/* Specifying a recipient pid on a non-basic rctl makes no sense */
errflg = 1;
goto done_parse;
}
/* Specifying a recipient pid on a privileged rctl makes no sense */
if (arg_pid != -1 &&
arg_priv == RCPRIV_PRIVILEGED) {
errflg = 1;
goto done_parse;
}
if (arg_operation) {
/* do additional checks if there is an operation */
if (arg_parseable_mode == 1) {
"resource control values"));
errflg = 1;
goto done_parse;
}
/* get rctl global flags to determine if actions are valid */
errflg = 1;
goto done_parse;
}
errflg = 1;
goto done_parse;
}
/* get system rctl to get global flags and max value */
errflg = 1;
goto done_parse;
}
/* allow user interrupt */
if (interrupt) {
errflg = 1;
goto done_parse;
}
if (rctlblk_get_privilege(rctlblkA) ==
break;
}
}
errflg = 1;
goto done_parse;
}
/* figure out the correct scale and unit for this rctl */
if (arg_global_flags & RCTL_GLOBAL_BYTES) {
} else if (arg_global_flags & RCTL_GLOBAL_SECONDS) {
} else {
}
/* parse -v value string */
if (arg_valuestring) {
SCALED_ALL_FLAGS)) {
errflg = 1;
goto done_parse;
}
if (arg_value > arg_global_max) {
"limit for resource control: %s"),
errflg = 1;
goto done_parse;
}
}
/* parse action */
if (arg_action_string) {
char *sigchr;
char *iter;
if (arg_operation & ACTION_ENABLE) {
"signal name or number must be "
"specified with -e"));
errflg = 1;
goto done_parse;
}
arg_signal = -1;
} else if ((strncmp(arg_action_string,
sigchr++;
while (*iter) {
iter++;
}
sigchr += 3;
errflg = 1;
goto done_parse;
}
if (arg_operation & ACTION_ENABLE) {
"cannot use action 'all' with -e"));
errflg = 1;
goto done_parse;
}
arg_signal = -1;
goto done_parse;
} else {
errflg = 1;
goto done_parse;
}
}
/* cannot manipulate system rctls */
if (arg_priv == RCPRIV_SYSTEM) {
errflg = 1;
goto done_parse;
}
/* validate that the privilege is allowed */
if ((arg_priv == RCPRIV_BASIC) &&
arg_name);
errflg = 1;
goto done_parse;
}
/* validate that actions are appropriate for given rctl */
if ((arg_operation & ACTION_ENABLE) &&
(arg_action & RCTL_LOCAL_DENY) &&
"global flag 'no-deny'"));
errflg = 1;
goto done_parse;
}
if ((arg_operation & ACTION_DISABLE) &&
(arg_action & RCTL_LOCAL_DENY) &&
"global flag 'deny'"));
errflg = 1;
goto done_parse;
}
if ((arg_operation & ACTION_ENABLE) &&
(arg_action & RCTL_LOCAL_SIGNAL) &&
"global flag 'no-signal'"));
errflg = 1;
goto done_parse;
}
/* now set defaults for options not supplied */
/*
* default privilege to basic if this is a seting an rctl
* operation
*/
if (arg_operation & ACTION_SET) {
if (arg_priv == 0) {
}
}
/*
* -p is required when set a basic task,
* project or zone rctl
*/
if ((arg_pid == -1) &&
(arg_priv == RCPRIV_BASIC) &&
(arg_entity_type != RCENTITY_PROCESS) &&
(arg_operation & ACTION_SET) &&
(arg_name) &&
(arg_name_entity == RCENTITY_TASK ||
arg_name_entity == RCENTITY_ZONE)) {
"replacing task or project rctl"));
errflg = 1;
goto done_parse;
}
} else {
/* validate for list mode */
/* -p is not valid in list mode */
if (arg_pid != -1) {
errflg = 1;
goto done_parse;
}
}
((arg_entity_type == RCENTITY_TASK) ||
(arg_entity_type == RCENTITY_PROJECT))) {
"or project"));
errflg = 1;
goto done_parse;
}
(arg_entity_type == RCENTITY_PROJECT)) {
errflg = 1;
goto done_parse;
}
/* free any rctlblk's that we may have allocated */
if (rctlblkA) {
}
if (rctlblkB) {
}
if (errflg)
usage();
/* catch signals from terminal */
int intarg;
char *end;
errflg = 0;
gret = 0;
/* Store int version of arg */
errno = 0;
intarg = -1;
}
/*
* -p defaults to arg if basic and collective rctl
* and -i process is specified
*/
if ((arg_pid == -1) &&
(arg_priv == RCPRIV_BASIC) &&
(arg_entity_type == RCENTITY_PROCESS) &&
(arg_name) &&
(arg_name_entity == RCENTITY_TASK ||
arg_name_entity == RCENTITY_PROJECT)) {
errno = 0;
}
/* Specifying a recipient pid and -i pid is redundent */
errflg = 1;
continue;
}
/* use recipient pid if we have one */
if (arg_pid_string != NULL) {
} else {
}
if (arg_operation != 0) {
/*
* Mark that an error occurred so that the
* return value can be set, but continue
* on with other processes
*/
errflg = 1;
continue;
}
/*
* At this point, the victim process is held.
* Do not call any Pgrab-unsafe functions until
* the process is released via release_process().
*/
if (arg_operation & ACTION_DELETE) {
/* match by privilege, value, and pid */
if (interrupt)
goto out;
"resource control found for "
"deletion"));
errflg = 1;
goto out;
}
/*
* grab correct process. This is neccessary
* if the recipient pid does not match the
* one we grabbed
*/
if (pid < 0) {
errflg = 1;
goto out;
}
rctlblkA, RCTL_DELETE) != 0) {
errflg = 1;
goto out;
}
} else if (arg_operation & ACTION_SET) {
/* match by privilege, value, and pid */
arg_pid) == 0) {
if (interrupt)
goto out;
"control already exists"));
errflg = 1;
goto out;
}
errflg = 1;
goto out;
}
if (change_action(rctlblkB)) {
errflg = 1;
goto out;
}
rctlblkB, RCTL_INSERT) != 0) {
errflg = 1;
goto out;
}
} else if (arg_operation & ACTION_REPLACE) {
/*
* match rctl for deletion by privilege and
* pid only
*/
if (interrupt)
goto out;
"resource control to replace"));
errflg = 1;
goto out;
}
/*
* grab correct process. This is neccessary
* if the recipient pid does not match the
* one we grabbed
*/
if (pid < 0) {
errflg = 1;
goto out;
}
/*
* match by privilege, value and pid to
* check if new rctl already exists
*/
pid) < 0) {
if (interrupt)
goto out;
"Internal Error"));
errflg = 1;
goto out;
}
/*
* If rctl already exists, and it does not
* match the one that we will delete, than
* the replace will fail.
*/
"resource control already "
"exists"));
errflg = 1;
goto out;
}
/* create new rctl */
errflg = 1;
goto out;
}
signal);
if (change_action(rctlblkB)) {
errflg = 1;
goto out;
}
/* do replacement */
rctlblkB, RCTL_REPLACE) != 0) {
errflg = 1;
goto out;
}
} else if (arg_operation &
(ACTION_ENABLE | ACTION_DISABLE)) {
errflg = 1;
goto out;
}
/* match by privilege, value, and pid */
arg_pid) != 0) {
if (interrupt)
goto out;
/* if no match, just set new rctl */
if (arg_priv == 0)
if ((arg_priv == RCPRIV_BASIC) &&
(arg_entity_type !=
RCENTITY_PROCESS) &&
(arg_pid_string == NULL)) {
"-p required when setting "
"basic rctls"));
errflg = 1;
goto out;
}
if (change_action(rctlblkB)) {
errflg = 1;
goto out;
}
if (prctl_setrctl(p.pr,
RCTL_INSERT) != 0) {
errflg = 1;
goto out;
}
goto out;
}
"resource control found"));
errflg = 1;
goto out;
}
/*
* grab correct process. This is neccessary
* if the recipient pid does not match the
* one we grabbed
*/
if (pid < 0) {
errflg = 1;
goto out;
}
&signal);
signal);
if (change_action(rctlblkB)) {
errflg = 1;
goto out;
}
rctlblkB, RCTL_REPLACE) != 0) {
errflg = 1;
goto out;
}
}
out:
release_process(p.pr);
if (rctlblkA)
if (rctlblkB)
/* Print any errors that occurred */
proc_unctrl_psinfo(&(p.psinfo));
break;
}
} else {
/*
* Hack to allow the user to specify a system
* process.
*/
/*
* Print system process if user chose specifically
* to inspect a system process.
*/
if (arg_entity_type == RCENTITY_PROCESS &&
pid < 0 &&
/*
* Add blank lines between output for
* operands.
*/
if (printed) {
}
proc_unctrl_psinfo(&(p.psinfo));
(void) printf(
"process: %d: %s [ system process ]\n",
printed = 1;
continue;
} else if (pid < 0) {
/*
* Mark that an error occurred so that the
* return value can be set, but continue
* on with other processes
*/
errflg = 1;
continue;
}
release_process(p.pr);
/* handle user interrupt of getting rctls */
if (interrupt)
break;
/* add blank lines between output for operands */
if (printed) {
}
/* First print any errors */
if (errflg) {
free_lists();
break;
}
sizeof (buf))) {
} else {
p.projname = "";
}
sizeof (zonename)) > 0) {
} else {
p.zonename = "";
}
print_rctls(&p);
printed = 1;
/* Free the resource control lists */
free_lists();
}
}
if (interrupt)
errflg = 1;
/*
* return error if one occurred
*/
return (errflg);
}
static void
{
}
/*
* get_rctls(struct ps_prochandle *, const char *)
*
* If controlname is given, store only controls for that named
* resource. If controlname is NULL, store all controls for all
* resources.
*
* This function is Pgrab-safe.
*/
static int
{
int ret = 0;
ret = 1;
} else {
}
return (ret);
}
/*
* store_rctls(const char *, void *)
*
* Store resource controls for the given name in a linked list.
* Honor the user's options, and store only the ones they are
* interested in. If priv is not 0, show only controls that match
* the given privilege.
*
* This function is Pgrab-safe
*/
static int
{
return (1);
}
return (1);
}
/* Store control if it matches privilege and enity type criteria */
rblk_entity = 0;
strlen("process.")) == 0)
strlen("project.")) == 0)
strlen("task.")) == 0)
strlen("zone.")) == 0)
/* Once we know we have some controls, store the name */
return (1);
}
return (1);
}
}
/*
* in case this is stuck for some reason, allow manual
* interrupt
*/
if (interrupt) {
return (1);
}
/*
* Store control if it matches privilege and entity type
* criteria
*/
(arg_entity_string == NULL ||
rblk_entity == arg_entity_type)) {
/* May not have created the list yet. */
== NULL) {
return (1);
}
}
return (1);
}
}
}
/*
* Get the current usage for the resource control if it matched the
* privilege and entity type criteria.
*/
return (1);
}
} else {
"resource control usage for %s: %s"),
return (1);
}
}
}
return (0);
}
/*
* store_value_entry(rctlblk_t *, prctl_list_t *)
*
* Store an rblk for a given resource control into the global list.
*
* This function is Pgrab-safe.
*/
{
if (e != NULL)
free(e);
return (NULL);
}
else {
}
}
return (e);
}
/*
* store_list_entry(const char *)
*
* Store a new resource control value in the global list. No checking
* for duplicates done.
*
* This function is Pgrab-safe.
*/
{
if (e == NULL) {
return (NULL);
}
free(e);
return (NULL);
}
if (global_rctl_list_head == NULL) {
} else {
global_rctl_list_tail->next = e;
}
return (e);
}
/*
* free_lists()
*
* Free all resource control blocks and values from the global lists.
*
* This function is Pgrab-safe.
*/
void
{
}
}
}
void
{
/* print headings */
"NAME", "PRIVILEGE", "VALUE",
"FLAG", "ACTION", "RECIPIENT");
}
/*
* print_rctls()
*
* Print all resource controls from the global list that was
* previously populated by store_rctls.
*/
void
{
char *string;
int doneheading = 0;
return;
if (doneheading == 0 &&
proc_unctrl_psinfo(&(p->psinfo));
doneheading = 1;
"process: %d: %.70s\n", (int)p->pid,
if (!arg_parseable_mode)
}
if (doneheading == 0 &&
arg_entity_type == RCENTITY_TASK) {
doneheading = 1;
if (!arg_parseable_mode)
}
if (doneheading == 0 &&
if (!arg_parseable_mode && doneheading)
doneheading = 1;
"project: %d: %.70s\n", (int)p->projid,
p->projname);
if (!arg_parseable_mode)
}
if (doneheading == 0 &&
arg_entity_type == RCENTITY_ZONE) {
doneheading = 1;
"zone: %d: %.70s\n", (int)p->zoneid,
p->zonename);
if (!arg_parseable_mode)
}
/* only print name once in normal output */
if (!arg_parseable_mode)
/* if for some reason there are no values, skip */
if (iter_val == 0)
continue;
/* get the global flags the first rctl only */
if (global_flags & RCTL_GLOBAL_BYTES) {
} else if (global_flags & RCTL_GLOBAL_SECONDS) {
} else {
}
/* print the current usage for the rctl if available */
if (!arg_parseable_mode) {
} else {
}
}
/* iterate over an print all control values */
/* print name or empty name field */
if (!arg_parseable_mode)
else
if (!arg_parseable_mode)
else
if (arg_parseable_mode) {
} else {
}
if (local_flags & RCTL_LOCAL_MAXIMAL) {
if (global_flags & RCTL_GLOBAL_INFINITE) {
string = "inf";
} else {
string = "max";
}
} else {
string = "-";
}
if (arg_parseable_mode)
else
string, "");
&signal);
if (arg_parseable_mode)
"%s ");
else
"%-28s");
if (arg_parseable_mode) {
if (pid < 0) {
} else {
(int)pid);
}
} else {
if (pid < 0) {
} else {
(int)pid);
}
}
}
}
}
/*
*
* match_rctl
*
* find the first rctl with matching name, value, priv, and recipient pid
*/
int
{
return (-1);
}
/*
* For this resource name, now iterate through all
* the controls, looking for a match to the
* user-specified input.
*/
return (-1);
}
return (0);
}
/* allow user interrupt */
if (interrupt)
break;
== 1) {
return (0);
}
}
return (1);
}
/*
* int match_rctl_blk(rctlblk_t *, char *, uint64, rctl_priv_t, int pid)
*
* Input
* Must supply a valid rctl, value, privilege, and pid to match on.
* If valuestring is NULL, then valuestring and valuein will not be used
* If privilege type is 0 it will not be used.
* If pid is -1 it will not be used.
*
* Return values
* Returns 1 if a matching rctl given matches the parameters specified, and
* 0 if they do not.
*
* This function is Pgrab-safe.
*/
int
{
if (valuestringin) {
if (arg_modifier == NULL) {
} else {
}
}
if (privin != 0) {
}
if (pidin != -1) {
}
}
static int
{
int signal = 0;
int action;
if (arg_operation & ACTION_ENABLE) {
if (arg_action & RCTL_LOCAL_SIGNAL) {
signal = arg_signal;
}
/* add local action */
} else if (arg_operation & ACTION_DISABLE) {
/*
* if deleting signal and signal number is specified,
* then signal number must match
*/
if ((arg_action & RCTL_LOCAL_SIGNAL) &&
(arg_signal != -1)) {
if (arg_signal != signal) {
"does not match existing action"));
return (-1);
}
}
/* remove local action */
}
/* enable deny if it must be enabled */
if (arg_global_flags & RCTL_GLOBAL_DENY_ALWAYS) {
signal);
}
return (0);
}
/*
* prctl_setrctl
*
* Input
* This function expects that input has been validated. In the
* case of a replace operation, both old_rblk and new_rblk must
* be valid resource controls. If a resource control is being
* created, only new_rblk must be supplied. If a resource control
* is being deleted, only new_rblk must be supplied.
*
* If the privilege is a priviliged type, at this time, the process
* tries to take on superuser privileges.
*/
int
{
int ret = 0;
if (rblk_priv == RCPRIV_SYSTEM) {
return (1);
}
if (rblk_priv == RCPRIV_PRIVILEGED) {
if (new_prpriv == NULL) {
return (1);
}
/*
* We only have to change the process privileges if it doesn't
* already have PRIV_SYS_RESOURCE. In addition, we want to make
* sure that we don't leave a process with elevated privileges,
* so we make sure the process dies if we exit unexpectedly.
*/
eset = (priv_set_t *)
pset = (priv_set_t *)
/* Keep track of original privileges */
if (old_prpriv == NULL) {
"privileges for pid %d: %s"),
return (1);
}
"privileges for pid %d: %s"),
return (1);
}
}
/*
* If this is a zone.* rctl, it requires more than
* PRIV_SYS_RESOURCE: it wants the process to have global-zone
* credentials. We temporarily grant non-global zone processes
* these credentials, and make sure the process dies if we exit
* unexpectedly.
*/
if (arg_name &&
arg_name_entity == RCENTITY_ZONE &&
getzoneid() == GLOBAL_ZONEID &&
/*
* We need to give this process superuser
* ("super-zone") privileges.
*
* Must never return without setting this back!
*/
"cannot set global-zone "
"privileges for pid %d: %s"),
/*
* We couldn't set the zoneid to begin with, so
* there's no point in warning the user about
* trying to un-set it.
*/
ret = 1;
goto bail;
}
}
}
/* Now, actually populate the rctlblk in the kernel */
if (flags == RCTL_REPLACE) {
/*
* Replace should be a delete followed by an insert. This
* allows us to replace rctl value blocks which match in
* privilege and value, but have updated actions, etc.
* setrctl() doesn't allow a direct replace, but we
* should do the right thing for the user in the command.
*/
old_rblk, RCTL_DELETE)) {
"control %s for pid %d: %s"), name,
ret = 1;
goto bail;
}
new_rblk, RCTL_INSERT)) {
"control %s for pid %d: %s"), name,
ret = 1;
goto bail;
}
} else if (flags == RCTL_INSERT) {
new_rblk, RCTL_INSERT)) {
"control %s for pid %d: %s"), name,
ret = 1;
goto bail;
}
} else if (flags == RCTL_DELETE) {
new_rblk, RCTL_DELETE)) {
"control %s for pid %d: %s"), name,
ret = 1;
goto bail;
}
}
bail:
if (oldzoneid != GLOBAL_ZONEID) {
}
if (old_prpriv != NULL) {
}
if (relinquish_failed) {
/*
* If this failed, we can't leave a process hanging
* around with elevated privileges, so we'll have to
* release the process from libproc, knowing that it
* will be killed (since we set PR_KLC).
*/
"for pid %d. The process was killed."),
} else {
"for pid %d. The process was killed."),
}
if (new_prpriv != NULL)
return (ret);
}
void
{
switch (local_priv) {
case RCPRIV_BASIC:
break;
case RCPRIV_PRIVILEGED:
break;
case RCPRIV_SYSTEM:
break;
default:
break;
}
/* LINTED */
}
void
{
int set = 0;
astring[0] = '\0';
if (action == RCTL_LOCAL_NOACTION) {
set++;
}
if (action & RCTL_LOCAL_DENY) {
set++;
}
if ((action & RCTL_LOCAL_DENY) &&
(action & RCTL_LOCAL_SIGNAL)) {
}
if (action & RCTL_LOCAL_SIGNAL) {
"signal=%d", *signalp);
else
"signal=%s", sig);
set++;
}
if (set)
/* LINTED */
else
/* LINTED */
}
/*
* This function is used to grab the process matching the recipient pid
*/
{
gret = 0;
if (pid == -1)
return (p->pid);
return (p->pid);
release_process(p->pr);
(void) memset(p, 0, sizeof (*p));
return (grab_process_by_id(
}
/*
* int grab_process_by_id(char *, rctl_entity_t, pr_info_handle_t *, int, int *)
*
* Input
* Supply a non-NULL string containing:
* RCENTITY_PROJECT or RCENTITY_ZONE
* - task number if type is RCENTITY_TYPE
* - a pid if type is RCENTITY_PID
* Also supply an un-allocated prochandle, and an allocated info_handle.
* This function assumes that the type is set.
* If priv is not RCPRIV_BASIC, the grabbed process is required to have
* PRIV_SYS_RESOURCE in it's limit set.
*
* Return Values
* Returns 0 on success and 1 on failure. If there is a process
* running under the specified id, success is returned, and
* Pr is pointed to the process. Success will be returned and Pr
* set to NULL if the matching process is our own.
* If success is returned, psinfo will be valid, and pid will
* be the process number. The process will also be held at the
* end, so release_process should be used by the caller.
*
* This function assumes that signals are caught already so that libproc
* can be safely used.
*
* Return Values
* pid - Process found and grabbed
* -1 - Error
*/
{
int found = 0;
int pid_self;
int ret;
int gret_in;
int intidname;
char *end;
/* get our pid se we do not try to operate on self */
/* Store integer version of id */
intidname = -1;
}
/*
* get our zoneid so we don't try to operate on a project in
* another zone
*/
return (-1);
}
/*
* Set up zoneid, projid or taskid, as appropriate, so that comparisons
* can be done later with the input.
*/
if (type == RCENTITY_ZONE) {
return (-1);
}
} else if (type == RCENTITY_PROJECT) {
== NULL) {
PROJECT_BUFSZ) == NULL) {
idname);
return (-1);
}
}
} else if (type == RCENTITY_TASK) {
}
/*
* Projects and tasks need to search through /proc for
* a parent process.
*/
type == RCENTITY_TASK) {
idname);
return (-1);
}
/*
* Look through all processes in /proc. For each process,
* check if the pr_projid in their psinfo matches the
* specified id.
*/
/* Skip self */
continue;
continue;
/* Skip process if it is not what we are looking for */
if (type == RCENTITY_ZONE &&
continue;
} else if (type == RCENTITY_PROJECT &&
continue;
} else if (type == RCENTITY_TASK &&
continue;
}
/* attempt to grab process */
if (grab_process(p, gret) != 0)
continue;
/*
* Re-confirm that this process is still running as
* part of the specified project or task. If it
* doesn't match, release the process and return an
* error. This should only be done if the Pr struct is
* not NULL.
*/
if (type == RCENTITY_PROJECT) {
release_process(p->pr);
continue;
}
} else if (type == RCENTITY_TASK) {
release_process(p->pr);
continue;
}
} else if (type == RCENTITY_ZONE) {
release_process(p->pr);
continue;
}
}
/*
* If we are setting a privileged resource control,
* verify that process has PRIV_SYS_RESOURCE in it's
* limit set. If it does not, then we will not be
* able to give this process the privilege it needs
* to set the resource control.
*/
if (priv != RCPRIV_BASIC) {
release_process(p->pr);
continue;
}
prset = (priv_set_t *)
release_process(p->pr);
continue;
}
}
found = 1;
break;
}
if (found == 0) {
"task, project, or zone.\n"), idname);
return (-1);
}
return (p->pid);
} else if (type == RCENTITY_PROCESS) {
/* fail if self */
return (-1);
}
/*
* Process types need to be set up with the correct pid
* and psinfo structure.
*/
Pgrab_error(*gret));
return (-1);
}
/* grab process */
if (ret == 1) {
/* Don't print error if G_SYS is allowed */
return (-1);
} else {
Pgrab_error(*gret));
return (-1);
}
} else if (ret == 2) {
return (-1);
}
return (p->pid);
} else {
type);
return (-1);
}
}
/*
* Do the work required to manipulate a process through libproc.
* If grab_process() returns no errors (0), then release_process()
* must eventually be called.
*
* Return values:
* 0 Successful creation of agent thread
* 1 Error grabbing
* 2 Error creating agent
*/
int
{
return (1);
}
if (Pcreate_agent(p->pr) == 0) {
return (0);
} else {
return (2);
}
} else {
return (1);
}
}
/*
* Release the specified process. This destroys the agent
* and releases the process. If the process is NULL, nothing
* is done. This function should only be called if grab_process()
* has previously been called and returned success.
*
* This function is Pgrab-safe.
*/
void
{
return;
}
/*
* preserve_error(char *, ...)
*
* preserve_error() should be called rather than warn() by any
* function that is called while the victim process is held by Pgrab.
* It will save the error until the process has been un-controlled
* and output is reasonable again.
*
* Note that multiple errors are not stored. Any error in these
* sections should be critical and return immediately.
*
* This function is Pgrab-safe.
*
* Since this function may copy untrusted command line arguments to
* global_error, security practices require that global_error never be
* printed directly. Use printf("%s\n", global_error) or equivalent.
*/
/*PRINTFLIKE1*/
void
{
/*
* GLOBAL_ERR_SZ is pretty big. If the error is longer
* than that, just truncate it, rather than chance missing
* the error altogether.
*/
}