psrset.c revision 7c478bd95313f5f23a4c958a745db2134aa03244
/*
* CDDL HEADER START
*
* The contents of this file are subject to the terms of the
* Common Development and Distribution License, Version 1.0 only
* (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
* or http://www.opensolaris.org/os/licensing.
* 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 2005 Sun Microsystems, Inc. All rights reserved.
* Use is subject to license terms.
*/
#pragma ident "%Z%%M% %I% %E% SMI"
/*
* psrset - create and manage processor sets
*/
#include <sys/types.h>
#include <sys/procset.h>
#include <sys/processor.h>
#include <sys/pset.h>
#include <fcntl.h>
#include <stdio.h>
#include <errno.h>
#include <dirent.h>
#include <locale.h>
#include <string.h>
#include <limits.h>
#include <procfs.h>
#include <libproc.h>
#include <stdarg.h>
#include <priv.h>
#if !defined(TEXT_DOMAIN) /* should be defined by cc -D */
#define TEXT_DOMAIN "SYS_TEST" /* Use this only if it wasn't */
#endif
#define MAX_PROCFS_PATH 80
#define ERR_OK 0 /* exit status for success */
#define ERR_FAIL 1 /* exit status for errors */
#define ERR_USAGE 2 /* exit status for usage errors */
static char *progname;
static int errors;
static char cflag;
static char dflag;
static char aflag;
static char rflag;
static char iflag;
static char bflag;
static char uflag;
static char Uflag;
static char qflag;
static char Qflag;
static char pflag;
static char nflag;
static char fflag;
static char Fflag;
static char eflag;
extern int pset_assign_forced(psetid_t, processorid_t, psetid_t *);
/*PRINTFLIKE1*/
static void
warn(char *format, ...)
{
int err = errno;
va_list alist;
(void) fprintf(stderr, "%s: ", progname);
va_start(alist, format);
(void) vfprintf(stderr, format, alist);
va_end(alist);
if (strchr(format, '\n') == NULL)
(void) fprintf(stderr, ": %s\n", strerror(err));
}
/*PRINTFLIKE1*/
static void
die(char *format, ...)
{
int err = errno;
va_list alist;
(void) fprintf(stderr, "%s: ", progname);
va_start(alist, format);
(void) vfprintf(stderr, format, alist);
va_end(alist);
if (strchr(format, '\n') == NULL)
(void) fprintf(stderr, ": %s\n", strerror(err));
exit(ERR_FAIL);
}
static prpriv_t *orig_priv;
static struct ps_prochandle *
grab_proc(id_t pid)
{
int ret;
prpriv_t *new_priv;
priv_set_t *eff_set, *perm_set;
struct ps_prochandle *Pr;
if ((Pr = Pgrab(pid, 0, &ret)) == NULL) {
warn(gettext("cannot control process %d: %s\n"),
(int)pid, Pgrab_error(ret));
errors = ERR_FAIL;
return (NULL);
}
/*
* If target process does not have required PRIV_SYS_RES_CONFIG
* privilege, assign it temporarily to that process' effective
* and permitted sets so that it can call pset_bind(2).
*/
if ((new_priv = proc_get_priv(pid)) == NULL) {
warn(gettext("unable to get privileges for process %d: %s\n"),
pid, strerror(errno));
errors = ERR_FAIL;
Prelease(Pr, 0);
return (NULL);
}
if (Pcreate_agent(Pr) != 0) {
warn(gettext("cannot control process %d\n"), (int)pid);
errors = ERR_FAIL;
Prelease(Pr, 0);
free(new_priv);
return (NULL);
}
eff_set = (priv_set_t *)&new_priv->pr_sets[new_priv->pr_setsize *
priv_getsetbyname(PRIV_EFFECTIVE)];
perm_set = (priv_set_t *)&new_priv->pr_sets[new_priv->pr_setsize *
priv_getsetbyname(PRIV_PERMITTED)];
if (!priv_ismember(eff_set, PRIV_SYS_RES_CONFIG)) {
/*
* Save original privileges
*/
if ((orig_priv = proc_get_priv(pid)) == NULL) {
warn(gettext("unable to get privileges for "
"process %d: %s\n"), pid, strerror(errno));
errors = ERR_FAIL;
Pdestroy_agent(Pr);
Prelease(Pr, 0);
free(new_priv);
return (NULL);
}
(void) priv_addset(eff_set, PRIV_SYS_RES_CONFIG);
(void) priv_addset(perm_set, PRIV_SYS_RES_CONFIG);
/*
* We don't want to leave a process with elevated privileges,
* so make sure the process dies if we exit unexpectedly.
*/
if (Psetflags(Pr, PR_KLC) != 0 ||
Psetpriv(Pr, new_priv) != 0) {
warn(gettext("unable to set process privileges for "
"process %d: %s\n"), pid, strerror(errno));
(void) Punsetflags(Pr, PR_KLC);
free(new_priv);
free(orig_priv);
Pdestroy_agent(Pr);
Prelease(Pr, 0);
orig_priv = NULL;
errors = ERR_FAIL;
return (NULL);
}
}
free(new_priv);
return (Pr);
}
static void
rele_proc(struct ps_prochandle *Pr)
{
if (Pr == NULL)
return;
if (orig_priv != NULL) {
if (Psetpriv(Pr, orig_priv) != 0) {
/*
* If this fails, we can't leave a process with
* elevated privileges, so we have to release the
* process from libproc, knowing that it will
* be killed (since we set the PR_KLC flag).
*/
Pdestroy_agent(Pr);
warn(gettext("cannot relinquish privileges for "
"process %d. The process was killed\n"),
Ppsinfo(Pr)->pr_pid);
errors = ERR_FAIL;
} else {
(void) Punsetflags(Pr, PR_KLC);
Pdestroy_agent(Pr);
}
free(orig_priv);
orig_priv = NULL;
} else {
Pdestroy_agent(Pr);
}
Prelease(Pr, 0);
}
static void
bind_err(psetid_t pset, id_t pid, id_t lwpid, int err)
{
char *msg;
switch (pset) {
case PS_NONE:
msg = gettext("unbind");
break;
case PS_QUERY:
msg = gettext("query");
break;
default:
msg = gettext("bind");
break;
}
errno = err;
if (lwpid == -1)
warn(gettext("cannot %s pid %d"), msg, pid);
else
warn(gettext("cannot %s lwpid %d/%d"), msg, pid, lwpid);
}
/*
* Output for create.
*/
static void
create_out(psetid_t pset)
{
(void) printf("%s %d\n", gettext("created processor set"), pset);
}
/*
* Output for assign.
*/
static void
assign_out(processorid_t cpu, psetid_t old, psetid_t new)
{
if (old == PS_NONE) {
if (new == PS_NONE)
(void) printf(gettext("processor %d: was not assigned,"
" now not assigned\n"), cpu);
else
(void) printf(gettext("processor %d: was not assigned,"
" now %d\n"), cpu, new);
} else {
if (new == PS_NONE)
(void) printf(gettext("processor %d: was %d, "
"now not assigned\n"), cpu, old);
else
(void) printf(gettext("processor %d: was %d, "
"now %d\n"), cpu, old, new);
}
}
/*
* Output for query.
*/
static void
query_out(id_t pid, id_t lwpid, psetid_t pset)
{
char *proclwp;
char pidstr[21];
if (lwpid == -1) {
(void) snprintf(pidstr, 20, "%d", pid);
proclwp = "process";
} else {
(void) snprintf(pidstr, 20, "%d/%d", pid, lwpid);
proclwp = "lwp";
}
if (pset == PS_NONE)
(void) printf(gettext("%s id %s: not bound\n"),
proclwp, pidstr);
else
(void) printf(gettext("%s id %s: %d\n"), proclwp, pidstr, pset);
}
/*
* Output for info.
*/
static void
info_out(psetid_t pset, int type, uint_t numcpus, processorid_t *cpus)
{
int i;
if (type == PS_SYSTEM)
(void) printf(gettext("system processor set %d:"), pset);
else
(void) printf(gettext("user processor set %d:"), pset);
if (numcpus == 0)
(void) printf(gettext(" empty"));
else if (numcpus > 1)
(void) printf(gettext(" processors"));
else
(void) printf(gettext(" processor"));
for (i = 0; i < numcpus; i++)
(void) printf(" %d", cpus[i]);
(void) printf("\n");
}
/*
* Output for print.
*/
static void
print_out(processorid_t cpu, psetid_t pset)
{
if (pset == PS_NONE)
(void) printf(gettext("processor %d: not assigned\n"), cpu);
else
(void) printf(gettext("processor %d: %d\n"), cpu, pset);
}
/*
* Output for bind.
*/
static void
bind_out(id_t pid, id_t lwpid, psetid_t old, psetid_t new)
{
char *proclwp;
char pidstr[21];
if (lwpid == -1) {
(void) snprintf(pidstr, 20, "%d", pid);
proclwp = "process";
} else {
(void) snprintf(pidstr, 20, "%d/%d", pid, lwpid);
proclwp = "lwp";
}
if (old == PS_NONE) {
if (new == PS_NONE)
(void) printf(gettext("%s id %s: was not bound, "
"now not bound\n"), proclwp, pidstr);
else
(void) printf(gettext("%s id %s: was not bound, "
"now %d\n"), proclwp, pidstr, new);
} else {
if (new == PS_NONE)
(void) printf(gettext("%s id %s: was %d, "
"now not bound\n"), proclwp, pidstr, old);
else
(void) printf(gettext("%s id %s: was %d, "
"now %d\n"), proclwp, pidstr, old, new);
}
}
static void
bind_lwp(struct ps_prochandle *Pr, id_t pid, id_t lwpid, psetid_t pset)
{
psetid_t old_pset;
if (pr_pset_bind(Pr, pset, P_LWPID, lwpid, &old_pset) < 0) {
bind_err(pset, pid, lwpid, errno);
errors = ERR_FAIL;
} else {
if (qflag)
query_out(pid, lwpid, old_pset);
else
bind_out(pid, lwpid, old_pset, pset);
}
}
static int
do_cpu(psetid_t pset, processorid_t cpu, int print, int mustexist)
{
psetid_t old_pset;
int err;
if ((!Fflag && pset_assign(pset, cpu, &old_pset) != 0) ||
(Fflag && pset_assign_forced(pset, cpu, &old_pset) != 0)) {
if (errno == EINVAL && !mustexist)
return (EINVAL);
err = errno;
switch (pset) {
case PS_NONE:
warn(gettext("cannot remove processor %d"), cpu);
break;
case PS_QUERY:
warn(gettext("cannot query processor %d"), cpu);
break;
default:
warn(gettext("cannot assign processor %d"), cpu);
break;
}
return (err);
}
if (print)
print_out(cpu, old_pset);
else
assign_out(cpu, old_pset, pset);
return (0);
}
static int
do_range(psetid_t pset, processorid_t first, processorid_t last, int print)
{
processorid_t cpu;
int error = ERR_OK;
int err;
int found_one = 0;
for (cpu = first; cpu <= last; cpu++) {
if ((err = do_cpu(pset, cpu, print, 0)) == 0)
found_one = 1;
else if (err != EINVAL)
error = ERR_FAIL;
}
if (!found_one && error == ERR_OK) {
warn(gettext("no processors in range %d-%d\n"), first, last);
error = ERR_FAIL;
}
return (error);
}
static int
do_info(psetid_t pset)
{
int type;
uint_t numcpus;
processorid_t *cpus;
numcpus = (uint_t)sysconf(_SC_NPROCESSORS_MAX);
cpus = (processorid_t *)
malloc(numcpus * sizeof (processorid_t));
if (cpus == NULL) {
warn(gettext("memory allocation failed"));
return (ERR_FAIL);
}
if (pset_info(pset, &type, &numcpus, cpus) != 0) {
warn(gettext("cannot get info for processor set %d"), pset);
free(cpus);
return (ERR_FAIL);
}
info_out(pset, type, numcpus, cpus);
free(cpus);
return (ERR_OK);
}
static int
do_destroy(psetid_t pset)
{
if (pset_destroy(pset) != 0) {
warn(gettext("could not remove processor set %d"), pset);
return (ERR_FAIL);
}
(void) printf(gettext("removed processor set %d\n"), pset);
return (ERR_OK);
}
static int
do_intr(psetid_t pset, int flag)
{
uint_t i, numcpus;
processorid_t *cpus;
int error = ERR_OK;
numcpus = (uint_t)sysconf(_SC_NPROCESSORS_MAX);
cpus = (processorid_t *)
malloc(numcpus * sizeof (processorid_t));
if (cpus == NULL) {
warn(gettext("memory allocation failed"));
return (ERR_FAIL);
}
if (pset_info(pset, NULL, &numcpus, cpus) != 0) {
warn(gettext(
"cannot set interrupt status for processor set %d"), pset);
free(cpus);
return (ERR_FAIL);
}
for (i = 0; i < numcpus; i++) {
int status = p_online(cpus[i], P_STATUS);
if (status != P_OFFLINE && status != P_POWEROFF &&
status != flag) {
if (p_online(cpus[i], flag) == -1) {
warn(gettext("processor %d"), cpus[i]);
error = ERR_FAIL;
}
}
}
free(cpus);
return (error);
}
/*
* Query the type and CPUs for all active processor sets in the system.
*/
static int
info_all(void)
{
psetid_t *psetlist;
uint_t npsets, oldnpsets;
int i;
int errors = ERR_OK;
if (pset_list(NULL, &npsets) != 0) {
warn(gettext("cannot get number of processor sets"));
return (1);
}
for (;;) {
psetlist = malloc(sizeof (psetid_t) * npsets);
if (psetlist == NULL) {
warn(gettext("memory allocation failed"));
return (ERR_FAIL);
}
oldnpsets = npsets;
if (pset_list(psetlist, &npsets) != 0) {
warn(gettext("cannot get list of processor sets"));
free(psetlist);
return (ERR_FAIL);
}
if (npsets <= oldnpsets)
break;
free(psetlist);
}
for (i = 0; i < npsets; i++) {
if (do_info(psetlist[i]))
errors = ERR_FAIL;
}
free(psetlist);
return (errors);
}
/*
* Query the processor set assignments for all CPUs in the system.
*/
static int
print_all(void)
{
psetid_t pset;
processorid_t cpuid, max_cpuid;
int errors = ERR_OK;
max_cpuid = (processorid_t)sysconf(_SC_CPUID_MAX);
for (cpuid = 0; cpuid <= max_cpuid; cpuid++) {
if (pset_assign(PS_QUERY, cpuid, &pset) == 0) {
if (pset != PS_NONE)
print_out(cpuid, pset);
} else if (errno != EINVAL) {
warn(gettext("cannot query processor %d"), cpuid);
errors = ERR_FAIL;
}
}
return (errors);
}
/*ARGSUSED*/
static int
query_all_proc(psinfo_t *psinfo, lwpsinfo_t *lwpsinfo, void *arg)
{
id_t pid = psinfo->pr_pid;
psetid_t binding;
if (pset_bind(PS_QUERY, P_PID, pid, &binding) < 0) {
/*
* Ignore search errors. The process may have exited
* since we read the directory.
*/
if (errno == ESRCH)
return (0);
bind_err(PS_QUERY, pid, -1, errno);
errors = ERR_FAIL;
return (0);
}
if (binding != PS_NONE)
query_out(pid, -1, binding);
return (0);
}
static int
query_all_lwp(psinfo_t *psinfo, lwpsinfo_t *lwpsinfo, void *arg)
{
id_t pid = psinfo->pr_pid;
id_t lwpid = lwpsinfo->pr_lwpid;
psetid_t *cpuid = arg;
psetid_t binding = lwpsinfo->pr_bindpset;
if (psinfo->pr_nlwp == 1)
lwpid = -1; /* report process bindings if only 1 lwp */
if ((cpuid != NULL && *cpuid == binding) ||
(cpuid == NULL && binding != PBIND_NONE))
query_out(pid, lwpid, binding);
return (0);
}
void
exec_cmd(psetid_t pset, char **argv)
{
if (pset_bind(pset, P_PID, P_MYID, NULL) != 0) {
warn(gettext("cannot exec in processor set %d"), pset);
return;
}
(void) execvp(argv[0], argv);
warn(gettext("cannot exec command %s"), argv[0]);
}
int
usage(void)
{
(void) fprintf(stderr, gettext(
"usage: \n"
"\t%1$s -c [-F] [processor_id ...]\n"
"\t%1$s -d processor_set_id ...\n"
"\t%1$s -n processor_set_id\n"
"\t%1$s -f processor_set_id\n"
"\t%1$s -e processor_set_id command [argument(s)...]\n"
"\t%1$s -a [-F] processor_set_id processor_id ...\n"
"\t%1$s -r [-F] processor_id ...\n"
"\t%1$s -p [processorid ...]\n"
"\t%1$s -b processor_set_id pid[/lwpids] ...\n"
"\t%1$s -u pid[/lwpids] ...\n"
"\t%1$s -q [pid[/lwpids] ...]\n"
"\t%1$s -U [processor_set_id] ...\n"
"\t%1$s -Q [processor_set_id] ...\n"
"\t%1$s [-i] [processor_set_id ...]\n"),
progname);
return (ERR_USAGE);
}
/*
* Query, set, or clear bindings for the range of LWPs in the given process.
*/
static int
do_lwps(id_t pid, const char *range, psetid_t pset)
{
char procfile[MAX_PROCFS_PATH];
struct ps_prochandle *Pr;
struct prheader header;
struct lwpsinfo *lwp;
char *lpsinfo, *ptr;
psetid_t binding;
int nent, size;
int i, fd, found;
/*
* Report bindings for LWPs in process 'pid'.
*/
(void) snprintf(procfile, MAX_PROCFS_PATH,
"/proc/%d/lpsinfo", (int)pid);
if ((fd = open(procfile, O_RDONLY)) < 0) {
if (errno == ENOENT)
errno = ESRCH;
bind_err(pset, pid, -1, errno);
return (ERR_FAIL);
}
if (pread(fd, &header, sizeof (header), 0) != sizeof (header)) {
(void) close(fd);
bind_err(pset, pid, -1, errno);
return (ERR_FAIL);
}
nent = header.pr_nent;
size = header.pr_entsize * nent;
ptr = lpsinfo = malloc(size);
if (lpsinfo == NULL) {
bind_err(pset, pid, -1, errno);
return (ERR_FAIL);
}
if (pread(fd, lpsinfo, size, sizeof (header)) != size) {
bind_err(pset, pid, -1, errno);
free(lpsinfo);
(void) close(fd);
return (ERR_FAIL);
}
if ((bflag || uflag) && (Pr = grab_proc(pid)) == NULL) {
free(lpsinfo);
(void) close(fd);
return (ERR_FAIL);
}
found = 0;
for (i = 0; i < nent; i++, ptr += header.pr_entsize) {
/*LINTED ALIGNMENT*/
lwp = (lwpsinfo_t *)ptr;
binding = lwp->pr_bindpset;
if (!proc_lwp_in_set(range, lwp->pr_lwpid))
continue;
found++;
if (bflag || uflag)
bind_lwp(Pr, pid, lwp->pr_lwpid, pset);
else if (binding != PBIND_NONE)
query_out(pid, lwp->pr_lwpid, binding);
}
if (bflag || uflag)
rele_proc(Pr);
free(lpsinfo);
(void) close(fd);
if (found == 0) {
warn(gettext("cannot %s lwpid %d/%s: "
"No matching LWPs found\n"),
bflag ? "bind" : "query", pid, range);
return (ERR_FAIL);
}
return (ERR_OK);
}
int
main(int argc, char *argv[])
{
extern int optind;
int c;
id_t pid;
processorid_t cpu;
psetid_t pset, old_pset;
char *errptr;
progname = argv[0]; /* put actual command name in messages */
(void) setlocale(LC_ALL, ""); /* setup localization */
(void) textdomain(TEXT_DOMAIN);
while ((c = getopt(argc, argv, "cdFarpibqQuUnfe")) != EOF) {
switch (c) {
case 'c':
cflag = 1;
break;
case 'd':
dflag = 1;
break;
case 'e':
eflag = 1;
break;
case 'a':
aflag = 1;
break;
case 'r':
rflag = 1;
pset = PS_NONE;
break;
case 'p':
pflag = 1;
pset = PS_QUERY;
break;
case 'i':
iflag = 1;
break;
case 'b':
bflag = 1;
break;
case 'u':
uflag = 1;
pset = PS_NONE;
break;
case 'U':
Uflag = 1;
break;
case 'q':
qflag = 1;
pset = PS_QUERY;
break;
case 'Q':
Qflag = 1;
break;
case 'f':
fflag = 1;
break;
case 'F':
Fflag = 1;
break;
case 'n':
nflag = 1;
break;
default:
return (usage());
}
}
/*
* Make sure that at most one of the options was specified.
*/
c = cflag + dflag + aflag + rflag + pflag +
iflag + bflag + uflag + Uflag +
qflag + Qflag + fflag + nflag + eflag;
if (c < 1) { /* nothing specified */
iflag = 1; /* default is to get info */
} else if (c > 1) {
warn(gettext("options are mutually exclusive\n"));
return (usage());
}
if (Fflag && (cflag + aflag + rflag == 0))
return (usage());
errors = 0;
argc -= optind;
argv += optind;
if (argc == 0) {
/*
* Handle single option cases.
*/
if (qflag) {
(void) proc_walk(query_all_proc, NULL, PR_WALK_PROC);
return (errors);
}
if (Qflag) {
(void) proc_walk(query_all_lwp, NULL, PR_WALK_LWP);
return (errors);
}
if (Uflag) {
if (pset_bind(PS_NONE, P_ALL, 0, &old_pset) != 0)
die(gettext("failed to unbind all LWPs"));
}
if (pflag)
return (print_all());
if (iflag)
return (info_all());
}
/*
* Get processor set id.
*/
if (aflag || bflag || fflag || nflag || eflag) {
if (argc < 1) {
/* must specify processor set */
warn(gettext("must specify processor set\n"));
return (usage());
}
pset = strtol(*argv, &errptr, 10);
if (errptr != NULL && *errptr != '\0' || pset < 0) {
warn(gettext("invalid processor set ID %s\n"), *argv);
return (ERR_FAIL);
}
argv++;
argc--;
}
if (cflag) {
if (pset_create(&pset) != 0) {
warn(gettext("could not create processor set"));
return (ERR_FAIL);
} else {
create_out(pset);
if (argc == 0)
return (ERR_OK);
}
} else if (iflag || dflag) {
if (argc == 0) {
warn(gettext("must specify at least one "
"processor set\n"));
return (usage());
}
/*
* Go through listed processor sets.
*/
for (; argc > 0; argv++, argc--) {
pset = (psetid_t)strtol(*argv, &errptr, 10);
if (errptr != NULL && *errptr != '\0') {
warn(gettext("invalid processor set ID %s\n"),
*argv);
errors = ERR_FAIL;
continue;
}
if (iflag) {
errors = do_info(pset);
} else {
errors = do_destroy(pset);
}
}
} else if (nflag) {
errors = do_intr(pset, P_ONLINE);
} else if (fflag) {
errors = do_intr(pset, P_NOINTR);
} else if (eflag) {
if (argc == 0) {
warn(gettext("must specify command\n"));
return (usage());
}
exec_cmd(pset, argv);
/* if returning, must have had an error */
return (ERR_USAGE);
}
if (cflag || aflag || rflag || pflag) {
/*
* Perform function for each processor specified.
*/
if (argc == 0) {
warn(gettext("must specify at least one processor\n"));
return (usage());
}
/*
* Go through listed processors.
*/
for (; argc > 0; argv++, argc--) {
if (strchr(*argv, '-') == NULL) {
/* individual processor id */
cpu = (processorid_t)strtol(*argv, &errptr, 10);
if (errptr != NULL && *errptr != '\0') {
warn(gettext("invalid processor "
"ID %s\n"), *argv);
errors = ERR_FAIL;
continue;
}
if (do_cpu(pset, cpu, pflag, 1))
errors = ERR_FAIL;
} else {
/* range of processors */
processorid_t first, last;
first = (processorid_t)
strtol(*argv, &errptr, 10);
if (*errptr++ != '-') {
warn(gettext(
"invalid processor range %s\n"),
*argv);
errors = ERR_USAGE;
continue;
}
last = (processorid_t)
strtol(errptr, &errptr, 10);
if ((errptr != NULL && *errptr != '\0') ||
last < first || first < 0) {
warn(gettext(
"invalid processor range %s\n"),
*argv);
errors = ERR_USAGE;
continue;
}
if (do_range(pset, first, last, pflag))
errors = ERR_FAIL;
}
}
} else if (bflag || uflag || qflag) {
/*
* Perform function for each pid/lwpid specified.
*/
if (argc == 0) {
warn(gettext("must specify at least one pid\n"));
return (usage());
}
/*
* Go through listed processes/lwp_ranges.
*/
for (; argc > 0; argv++, argc--) {
pid = (id_t)strtol(*argv, &errptr, 10);
if (errno != 0 ||
(errptr != NULL && *errptr != '\0' &&
*errptr != '/')) {
warn(gettext("invalid process ID: %s\n"),
*argv);
continue;
}
if (errptr != NULL && *errptr == '/') {
int ret;
/*
* Handle lwp range case
*/
const char *lwps = (const char *)(++errptr);
if (*lwps == '\0' ||
proc_lwp_range_valid(lwps) != 0) {
warn(gettext("invalid lwp range "
"for pid %d\n"), (int)pid);
errors = ERR_FAIL;
continue;
}
if (!qflag)
(void) proc_initstdio();
ret = do_lwps(pid, lwps, pset);
if (!qflag)
(void) proc_finistdio();
if (ret != ERR_OK)
errors = ret;
} else {
/*
* Handle whole process case.
*/
if (pset_bind(pset, P_PID, pid,
&old_pset) < 0) {
bind_err(pset, pid, -1, errno);
errors = ERR_FAIL;
continue;
}
if (qflag)
query_out(pid, -1, old_pset);
else
bind_out(pid, -1, old_pset, pset);
}
}
}
if (Qflag || Uflag) {
/*
* Go through listed processor set IDs.
*/
for (; argc > 0; argv++, argc--) {
errno = 0;
pset = (id_t)strtol(*argv, &errptr, 10);
if (errno != 0 ||
(errptr != NULL && *errptr != '\0')) {
warn(gettext("invalid processor set ID\n"));
continue;
}
if (Qflag) {
(void) proc_walk(query_all_lwp,
&pset, PR_WALK_LWP);
continue;
}
if (Uflag) {
if (pset_bind(PS_NONE, P_PSETID, pset,
&old_pset) != 0) {
warn(gettext("failed to unbind from "
"processor set %d"), (int)pset);
errors = ERR_FAIL;
}
continue;
}
}
}
return (errors);
}