1/*
2 * CDDL HEADER START
3 *
4 * The contents of this file are subject to the terms of the
5 * Common Development and Distribution License (the "License").
6 * You may not use this file except in compliance with the License.
7 *
8 * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
9 * or http://www.opensolaris.org/os/licensing.
10 * See the License for the specific language governing permissions
11 * and limitations under the License.
12 *
13 * When distributing Covered Code, include this CDDL HEADER in each
14 * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
15 * If applicable, add the following below this CDDL HEADER, with the
16 * fields enclosed by brackets "[]" replaced with your own identifying
17 * information: Portions Copyright [yyyy] [name of copyright owner]
18 *
19 * CDDL HEADER END
20 */
21/*
22 * Copyright 2009 Sun Microsystems, Inc.  All rights reserved.
23 * Use is subject to license terms.
24 */
25/*
26 * Copyright (c) 2013, Joyent, Inc.  All rights reserved.
27 */
28
29/*
30 * psrset - create and manage processor sets
31 */
32
33#include <sys/types.h>
34#include <sys/procset.h>
35#include <sys/processor.h>
36#include <sys/pset.h>
37#include <fcntl.h>
38#include <stdio.h>
39#include <errno.h>
40#include <dirent.h>
41#include <locale.h>
42#include <string.h>
43#include <limits.h>
44#include <procfs.h>
45#include <libproc.h>
46#include <stdarg.h>
47#include <zone.h>
48
49#if !defined(TEXT_DOMAIN)		/* should be defined by cc -D */
50#define	TEXT_DOMAIN 	"SYS_TEST"	/* Use this only if it wasn't */
51#endif
52
53#define	MAX_PROCFS_PATH	80
54
55#define	ERR_OK		0		/* exit status for success */
56#define	ERR_FAIL	1		/* exit status for errors */
57#define	ERR_USAGE	2		/* exit status for usage errors */
58
59static char *progname;
60static int errors;
61static char cflag;
62static char dflag;
63static char aflag;
64static char rflag;
65static char iflag;
66static char bflag;
67static char uflag;
68static char Uflag;
69static char qflag;
70static char Qflag;
71static char pflag;
72static char nflag;
73static char fflag;
74static char Fflag;
75static char eflag;
76static char zflag;
77static const char *zname;
78
79extern int pset_assign_forced(psetid_t, processorid_t, psetid_t *);
80
81/*PRINTFLIKE1*/
82static void
83warn(char *format, ...)
84{
85	int err = errno;
86	va_list alist;
87
88	(void) fprintf(stderr, "%s: ", progname);
89	va_start(alist, format);
90	(void) vfprintf(stderr, format, alist);
91	va_end(alist);
92	if (strchr(format, '\n') == NULL)
93		(void) fprintf(stderr, ": %s\n", strerror(err));
94}
95
96/*PRINTFLIKE1*/
97static void
98die(char *format, ...)
99{
100	int err = errno;
101	va_list alist;
102
103	(void) fprintf(stderr, "%s: ", progname);
104	va_start(alist, format);
105	(void) vfprintf(stderr, format, alist);
106	va_end(alist);
107	if (strchr(format, '\n') == NULL)
108		(void) fprintf(stderr, ": %s\n", strerror(err));
109	exit(ERR_FAIL);
110}
111
112static struct ps_prochandle *
113grab_proc(id_t pid)
114{
115	int ret;
116	struct ps_prochandle *Pr;
117
118	if ((Pr = Pgrab(pid, 0, &ret)) == NULL) {
119		warn(gettext("cannot control process %d: %s\n"),
120		    (int)pid, Pgrab_error(ret));
121		errors = ERR_FAIL;
122		return (NULL);
123	}
124
125	return (Pr);
126}
127
128static void
129rele_proc(struct ps_prochandle *Pr)
130{
131	if (Pr == NULL)
132		return;
133	Prelease(Pr, 0);
134}
135
136static void
137bind_err(psetid_t pset, const char *zname, id_t pid, id_t lwpid, int err)
138{
139	char    *msg;
140
141	switch (pset) {
142	case PS_NONE:
143		msg = gettext("unbind");
144		break;
145	case PS_QUERY:
146		msg = gettext("query");
147		break;
148	default:
149		msg = gettext("bind");
150		break;
151	}
152
153	errno = err;
154	if (zname != NULL)
155		warn(gettext("cannot %s zone %s"), msg, zname);
156	else if (lwpid == -1)
157		warn(gettext("cannot %s pid %d"), msg, pid);
158	else
159		warn(gettext("cannot %s lwpid %d/%d"), msg, pid, lwpid);
160}
161
162/*
163 * Output for create.
164 */
165static void
166create_out(psetid_t pset)
167{
168	(void) printf("%s %d\n", gettext("created processor set"), pset);
169}
170
171/*
172 * Output for assign.
173 */
174static void
175assign_out(processorid_t cpu, psetid_t old, psetid_t new)
176{
177	if (old == PS_NONE) {
178		if (new == PS_NONE)
179			(void) printf(gettext("processor %d: was not assigned,"
180			    " now not assigned\n"), cpu);
181		else
182			(void) printf(gettext("processor %d: was not assigned,"
183			    " now %d\n"), cpu, new);
184	} else {
185		if (new == PS_NONE)
186			(void) printf(gettext("processor %d: was %d, "
187			    "now not assigned\n"), cpu, old);
188		else
189			(void) printf(gettext("processor %d: was %d, "
190			    "now %d\n"), cpu, old, new);
191	}
192}
193
194/*
195 * Output for query.
196 */
197static void
198query_out(id_t pid, id_t lwpid, psetid_t pset)
199{
200	char *proclwp;
201	char pidstr[21];
202
203	if (lwpid == -1) {
204		(void) snprintf(pidstr, 20, "%d", pid);
205		proclwp = "process";
206	} else {
207		(void) snprintf(pidstr, 20, "%d/%d", pid, lwpid);
208		proclwp = "lwp";
209	}
210
211	if (pset == PS_NONE)
212		(void) printf(gettext("%s id %s: not bound\n"),
213		    proclwp, pidstr);
214	else
215		(void) printf(gettext("%s id %s: %d\n"), proclwp, pidstr, pset);
216}
217
218/*
219 * Output for info.
220 */
221static void
222info_out(psetid_t pset, int type, uint_t numcpus, processorid_t *cpus)
223{
224	int i;
225	if (type == PS_SYSTEM)
226		(void) printf(gettext("system processor set %d:"), pset);
227	else
228		(void) printf(gettext("user processor set %d:"), pset);
229	if (numcpus == 0)
230		(void) printf(gettext(" empty"));
231	else if (numcpus > 1)
232		(void) printf(gettext(" processors"));
233	else
234		(void) printf(gettext(" processor"));
235	for (i = 0; i < numcpus; i++)
236		(void) printf(" %d", cpus[i]);
237	(void) printf("\n");
238}
239
240/*
241 * Output for print.
242 */
243static void
244print_out(processorid_t cpu, psetid_t pset)
245{
246	if (pset == PS_NONE)
247		(void) printf(gettext("processor %d: not assigned\n"), cpu);
248	else
249		(void) printf(gettext("processor %d: %d\n"), cpu, pset);
250}
251
252/*
253 * Output for bind.
254 */
255static void
256bind_out(id_t pid, id_t lwpid, psetid_t old, psetid_t new)
257{
258	char *proclwp;
259	char pidstr[21];
260
261	if (lwpid == -1) {
262		(void) snprintf(pidstr, 20, "%d", pid);
263		proclwp = "process";
264	} else {
265		(void) snprintf(pidstr, 20, "%d/%d", pid, lwpid);
266		proclwp = "lwp";
267	}
268
269	if (old == PS_NONE) {
270		if (new == PS_NONE)
271			(void) printf(gettext("%s id %s: was not bound, "
272			    "now not bound\n"), proclwp, pidstr);
273		else
274			(void) printf(gettext("%s id %s: was not bound, "
275			    "now %d\n"), proclwp, pidstr, new);
276	} else {
277		if (new == PS_NONE)
278			(void) printf(gettext("%s id %s: was %d, "
279			    "now not bound\n"), proclwp, pidstr, old);
280		else
281			(void) printf(gettext("%s id %s: was %d, "
282			    "now %d\n"), proclwp, pidstr, old, new);
283	}
284}
285
286static void
287bind_lwp(id_t pid, id_t lwpid, psetid_t pset)
288{
289	psetid_t old_pset;
290
291	if (pset_bind_lwp(pset, lwpid, pid, &old_pset) != 0) {
292		bind_err(pset, NULL, pid, lwpid, errno);
293		errors = ERR_FAIL;
294	}
295	if (errors != ERR_FAIL) {
296		if (qflag)
297			query_out(pid, lwpid, old_pset);
298		else
299			bind_out(pid, lwpid, old_pset, pset);
300	}
301}
302
303static int
304do_cpu(psetid_t pset, processorid_t cpu, int print, int mustexist)
305{
306	psetid_t old_pset;
307	int err;
308
309	if ((!Fflag && pset_assign(pset, cpu, &old_pset) != 0) ||
310	    (Fflag && pset_assign_forced(pset, cpu, &old_pset) != 0)) {
311		if (errno == EINVAL && !mustexist)
312			return (EINVAL);
313		err = errno;
314
315		switch (pset) {
316		case PS_NONE:
317			warn(gettext("cannot remove processor %d"), cpu);
318			break;
319		case PS_QUERY:
320			warn(gettext("cannot query processor %d"), cpu);
321			break;
322		default:
323			warn(gettext("cannot assign processor %d"), cpu);
324			break;
325		}
326		return (err);
327	}
328	if (print)
329		print_out(cpu, old_pset);
330	else
331		assign_out(cpu, old_pset, pset);
332	return (0);
333}
334
335static int
336do_range(psetid_t pset, processorid_t first, processorid_t last, int print)
337{
338	processorid_t cpu;
339	int error = ERR_OK;
340	int err;
341	int found_one = 0;
342
343	for (cpu = first; cpu <= last; cpu++) {
344		if ((err = do_cpu(pset, cpu, print, 0)) == 0)
345			found_one = 1;
346		else if (err != EINVAL)
347			error = ERR_FAIL;
348	}
349	if (!found_one && error == ERR_OK) {
350		warn(gettext("no processors in range %d-%d\n"), first, last);
351		error = ERR_FAIL;
352	}
353	return (error);
354}
355
356static int
357do_info(psetid_t pset)
358{
359	int	type;
360	uint_t	numcpus;
361	processorid_t	*cpus;
362
363	numcpus = (uint_t)sysconf(_SC_NPROCESSORS_MAX);
364	cpus = (processorid_t *)
365	    malloc(numcpus * sizeof (processorid_t));
366	if (cpus == NULL) {
367		warn(gettext("memory allocation failed"));
368		return (ERR_FAIL);
369	}
370	if (pset_info(pset, &type, &numcpus, cpus) != 0) {
371		warn(gettext("cannot get info for processor set %d"), pset);
372		free(cpus);
373		return (ERR_FAIL);
374	}
375	info_out(pset, type, numcpus, cpus);
376	free(cpus);
377	return (ERR_OK);
378}
379
380static int
381do_destroy(psetid_t pset)
382{
383	if (pset_destroy(pset) != 0) {
384		warn(gettext("could not remove processor set %d"), pset);
385		return (ERR_FAIL);
386	}
387	(void) printf(gettext("removed processor set %d\n"), pset);
388	return (ERR_OK);
389}
390
391static int
392do_intr(psetid_t pset, int flag)
393{
394	uint_t i, numcpus;
395	processorid_t *cpus;
396	int error = ERR_OK;
397
398	numcpus = (uint_t)sysconf(_SC_NPROCESSORS_MAX);
399	cpus = (processorid_t *)
400	    malloc(numcpus * sizeof (processorid_t));
401	if (cpus == NULL) {
402		warn(gettext("memory allocation failed"));
403		return (ERR_FAIL);
404	}
405	if (pset_info(pset, NULL, &numcpus, cpus) != 0) {
406		warn(gettext(
407		    "cannot set interrupt status for processor set %d"), pset);
408		free(cpus);
409		return (ERR_FAIL);
410	}
411	for (i = 0; i < numcpus; i++) {
412		int status = p_online(cpus[i], P_STATUS);
413		if (status != P_OFFLINE && status != P_POWEROFF &&
414		    status != flag) {
415			if (p_online(cpus[i], flag) == -1) {
416				warn(gettext("processor %d"), cpus[i]);
417				error = ERR_FAIL;
418			}
419		}
420	}
421	free(cpus);
422	return (error);
423}
424
425/*
426 * Query the type and CPUs for all active processor sets in the system.
427 */
428static int
429info_all(void)
430{
431	psetid_t *psetlist;
432	uint_t	npsets, oldnpsets;
433	int	i;
434	int	errors = ERR_OK;
435
436	if (pset_list(NULL, &npsets) != 0) {
437		warn(gettext("cannot get number of processor sets"));
438		return (1);
439	}
440	for (;;) {
441		psetlist = malloc(sizeof (psetid_t) * npsets);
442		if (psetlist == NULL) {
443			warn(gettext("memory allocation failed"));
444			return (ERR_FAIL);
445		}
446		oldnpsets = npsets;
447		if (pset_list(psetlist, &npsets) != 0) {
448			warn(gettext("cannot get list of processor sets"));
449			free(psetlist);
450			return (ERR_FAIL);
451		}
452		if (npsets <= oldnpsets)
453			break;
454		free(psetlist);
455	}
456
457	for (i = 0; i < npsets; i++) {
458		if (do_info(psetlist[i]))
459			errors = ERR_FAIL;
460	}
461	free(psetlist);
462	return (errors);
463}
464
465/*
466 * Query the processor set assignments for all CPUs in the system.
467 */
468static int
469print_all(void)
470{
471	psetid_t	pset;
472	processorid_t cpuid, max_cpuid;
473	int	errors = ERR_OK;
474
475	max_cpuid = (processorid_t)sysconf(_SC_CPUID_MAX);
476	for (cpuid = 0; cpuid <= max_cpuid; cpuid++) {
477		if (pset_assign(PS_QUERY, cpuid, &pset) == 0) {
478			if (pset != PS_NONE)
479				print_out(cpuid, pset);
480		} else if (errno != EINVAL) {
481			warn(gettext("cannot query processor %d"), cpuid);
482			errors = ERR_FAIL;
483		}
484	}
485	return (errors);
486}
487
488/*ARGSUSED*/
489static int
490query_all_proc(psinfo_t *psinfo, lwpsinfo_t *lwpsinfo, void *arg)
491{
492	id_t pid = psinfo->pr_pid;
493	psetid_t binding;
494
495	if (pset_bind(PS_QUERY, P_PID, pid, &binding) < 0) {
496		/*
497		 * Ignore search errors.  The process may have exited
498		 * since we read the directory.
499		 */
500		if (errno == ESRCH)
501			return (0);
502		bind_err(PS_QUERY, NULL, pid, -1, errno);
503		errors = ERR_FAIL;
504		return (0);
505	}
506	if (binding != PS_NONE)
507		query_out(pid, -1, binding);
508	return (0);
509}
510
511static int
512query_all_lwp(psinfo_t *psinfo, lwpsinfo_t *lwpsinfo, void *arg)
513{
514	id_t pid = psinfo->pr_pid;
515	id_t lwpid = lwpsinfo->pr_lwpid;
516	psetid_t *cpuid = arg;
517	psetid_t binding = lwpsinfo->pr_bindpset;
518
519	if (psinfo->pr_nlwp == 1)
520		lwpid = -1;	/* report process bindings if only 1 lwp */
521	if ((cpuid != NULL && *cpuid == binding) ||
522	    (cpuid == NULL && binding != PBIND_NONE))
523		query_out(pid, lwpid, binding);
524	return (0);
525}
526
527void
528exec_cmd(psetid_t pset, char **argv)
529{
530	if (pset_bind(pset, P_PID, P_MYID, NULL) != 0) {
531		warn(gettext("cannot exec in processor set %d"), pset);
532		return;
533	}
534
535	(void) execvp(argv[0], argv);
536	warn(gettext("cannot exec command %s"), argv[0]);
537}
538
539int
540usage(void)
541{
542	(void) fprintf(stderr, gettext(
543	    "usage: \n"
544	    "\t%1$s -c [-F] [processor_id ...]\n"
545	    "\t%1$s -d processor_set_id ...\n"
546	    "\t%1$s -n processor_set_id\n"
547	    "\t%1$s -f processor_set_id\n"
548	    "\t%1$s -e processor_set_id command [argument(s)...]\n"
549	    "\t%1$s -a [-F] processor_set_id processor_id ...\n"
550	    "\t%1$s -r [-F] processor_id ...\n"
551	    "\t%1$s -p [processorid ...]\n"
552	    "\t%1$s -b processor_set_id pid[/lwpids] ...\n"
553	    "\t%1$s -b -z zonename processor_set_id\n"
554	    "\t%1$s -u pid[/lwpids] ...\n"
555	    "\t%1$s -q [pid[/lwpids] ...]\n"
556	    "\t%1$s -U [processor_set_id] ...\n"
557	    "\t%1$s -Q [processor_set_id] ...\n"
558	    "\t%1$s [-i] [processor_set_id ...]\n"),
559	    progname);
560	return (ERR_USAGE);
561}
562
563/*
564 * Query, set, or clear bindings for the range of LWPs in the given process.
565 */
566static int
567do_lwps(id_t pid, const char *range, psetid_t pset)
568{
569	char procfile[MAX_PROCFS_PATH];
570	struct ps_prochandle *Pr;
571	struct prheader header;
572	struct lwpsinfo *lwp;
573	char *lpsinfo, *ptr;
574	psetid_t binding;
575	int nent, size;
576	int i, fd, found;
577
578	/*
579	 * Report bindings for LWPs in process 'pid'.
580	 */
581	(void) snprintf(procfile, MAX_PROCFS_PATH,
582	    "/proc/%d/lpsinfo", (int)pid);
583	if ((fd = open(procfile, O_RDONLY)) < 0) {
584		if (errno == ENOENT)
585			errno = ESRCH;
586		bind_err(pset, NULL, pid, -1, errno);
587		return (ERR_FAIL);
588	}
589	if (pread(fd, &header, sizeof (header), 0) != sizeof (header)) {
590		(void) close(fd);
591		bind_err(pset, NULL, pid, -1, errno);
592		return (ERR_FAIL);
593	}
594	nent = header.pr_nent;
595	size = header.pr_entsize * nent;
596	ptr = lpsinfo = malloc(size);
597	if (lpsinfo == NULL) {
598		bind_err(pset, NULL, pid, -1, errno);
599		return (ERR_FAIL);
600	}
601	if (pread(fd, lpsinfo, size, sizeof (header)) != size) {
602		bind_err(pset, NULL, pid, -1, errno);
603		free(lpsinfo);
604		(void) close(fd);
605		return (ERR_FAIL);
606	}
607
608	if ((bflag || uflag) && (Pr = grab_proc(pid)) == NULL) {
609		free(lpsinfo);
610		(void) close(fd);
611		return (ERR_FAIL);
612	}
613	found = 0;
614	for (i = 0; i < nent; i++, ptr += header.pr_entsize) {
615		/*LINTED ALIGNMENT*/
616		lwp = (lwpsinfo_t *)ptr;
617		binding = lwp->pr_bindpset;
618		if (!proc_lwp_in_set(range, lwp->pr_lwpid))
619			continue;
620		found++;
621		if (bflag || uflag)
622			bind_lwp(pid, lwp->pr_lwpid, pset);
623		else if (binding != PBIND_NONE)
624			query_out(pid, lwp->pr_lwpid, binding);
625	}
626	if (bflag || uflag)
627		rele_proc(Pr);
628	free(lpsinfo);
629	(void) close(fd);
630	if (found == 0) {
631		warn(gettext("cannot %s lwpid %d/%s: "
632		    "No matching LWPs found\n"),
633		    bflag ? "bind" : "query", pid, range);
634		return (ERR_FAIL);
635	}
636	return (ERR_OK);
637}
638
639int
640main(int argc, char *argv[])
641{
642	extern int optind;
643	int	c;
644	id_t	pid;
645	processorid_t	cpu;
646	psetid_t	pset, old_pset;
647	zoneid_t	zid;
648	char	*errptr;
649
650	progname = argv[0];	/* put actual command name in messages */
651
652	(void) setlocale(LC_ALL, "");	/* setup localization */
653	(void) textdomain(TEXT_DOMAIN);
654
655	while ((c = getopt(argc, argv, "cdFarpibqQuUnfez:")) != EOF) {
656		switch (c) {
657		case 'c':
658			cflag = 1;
659			break;
660		case 'd':
661			dflag = 1;
662			break;
663		case 'e':
664			eflag = 1;
665			break;
666		case 'a':
667			aflag = 1;
668			break;
669		case 'r':
670			rflag = 1;
671			pset = PS_NONE;
672			break;
673		case 'p':
674			pflag = 1;
675			pset = PS_QUERY;
676			break;
677		case 'i':
678			iflag = 1;
679			break;
680		case 'b':
681			bflag = 1;
682			break;
683		case 'u':
684			uflag = 1;
685			pset = PS_NONE;
686			break;
687		case 'U':
688			Uflag = 1;
689			break;
690		case 'q':
691			qflag = 1;
692			pset = PS_QUERY;
693			break;
694		case 'Q':
695			Qflag = 1;
696			break;
697		case 'f':
698			fflag = 1;
699			break;
700		case 'F':
701			Fflag = 1;
702			break;
703		case 'n':
704			nflag = 1;
705			break;
706		case 'z':
707			if (!bflag) {
708				warn(gettext("-z can only be used after -b\n"));
709				return (usage());
710			}
711			if (zflag) {
712				warn(gettext("-z can only be specified "
713				    "once\n"));
714				return (usage());
715			}
716			zflag = 1;
717			zname = optarg;
718			break;
719		default:
720			return (usage());
721		}
722	}
723
724	/*
725	 * Make sure that at most one of the options was specified.
726	 */
727	c = cflag + dflag + aflag + rflag + pflag +
728	    iflag + bflag + uflag + Uflag +
729	    qflag + Qflag + fflag + nflag + eflag;
730	if (c < 1) {				/* nothing specified */
731		iflag = 1;			/* default is to get info */
732	} else if (c > 1) {
733		warn(gettext("options are mutually exclusive\n"));
734		return (usage());
735	}
736
737	if (Fflag && (cflag + aflag + rflag == 0))
738		return (usage());
739
740	errors = 0;
741	argc -= optind;
742	argv += optind;
743
744	if (argc == 0) {
745		/*
746		 * Handle single option cases.
747		 */
748		if (qflag) {
749			(void) proc_walk(query_all_proc, NULL, PR_WALK_PROC);
750			return (errors);
751		}
752		if (Qflag) {
753			(void) proc_walk(query_all_lwp, NULL, PR_WALK_LWP);
754			return (errors);
755		}
756		if (Uflag) {
757			if (pset_bind(PS_NONE, P_ALL, 0, &old_pset) != 0)
758				die(gettext("failed to unbind all LWPs"));
759		}
760		if (pflag)
761			return (print_all());
762		if (iflag)
763			return (info_all());
764	}
765
766	/*
767	 * Get processor set id.
768	 */
769	if (aflag || bflag || fflag || nflag || eflag) {
770		if (argc < 1) {
771			/* must specify processor set */
772			warn(gettext("must specify processor set\n"));
773			return (usage());
774		}
775		pset = strtol(*argv, &errptr, 10);
776		if (errptr != NULL && *errptr != '\0' || pset < 0) {
777			warn(gettext("invalid processor set ID %s\n"), *argv);
778			return (ERR_FAIL);
779		}
780		argv++;
781		argc--;
782	}
783
784	if (cflag) {
785		if (pset_create(&pset) != 0) {
786			warn(gettext("could not create processor set"));
787			return (ERR_FAIL);
788		} else {
789			create_out(pset);
790			if (argc == 0)
791				return (ERR_OK);
792		}
793	} else if (iflag || dflag) {
794		if (argc == 0) {
795			warn(gettext("must specify at least one "
796			    "processor set\n"));
797			return (usage());
798		}
799		/*
800		 * Go through listed processor sets.
801		 */
802		for (; argc > 0; argv++, argc--) {
803			pset = (psetid_t)strtol(*argv, &errptr, 10);
804			if (errptr != NULL && *errptr != '\0') {
805				warn(gettext("invalid processor set ID %s\n"),
806				    *argv);
807				errors = ERR_FAIL;
808				continue;
809			}
810			if (iflag) {
811				errors = do_info(pset);
812			} else {
813				errors = do_destroy(pset);
814			}
815		}
816	} else if (nflag) {
817		errors = do_intr(pset, P_ONLINE);
818	} else if (fflag) {
819		errors = do_intr(pset, P_NOINTR);
820	} else if (eflag) {
821		if (argc == 0) {
822			warn(gettext("must specify command\n"));
823			return (usage());
824		}
825		exec_cmd(pset, argv);
826		/* if returning, must have had an error */
827		return (ERR_USAGE);
828	}
829
830	if (cflag || aflag || rflag || pflag) {
831		/*
832		 * Perform function for each processor specified.
833		 */
834		if (argc == 0) {
835			warn(gettext("must specify at least one processor\n"));
836			return (usage());
837		}
838
839		/*
840		 * Go through listed processors.
841		 */
842		for (; argc > 0; argv++, argc--) {
843			if (strchr(*argv, '-') == NULL) {
844				/* individual processor id */
845				cpu = (processorid_t)strtol(*argv, &errptr, 10);
846				if (errptr != NULL && *errptr != '\0') {
847					warn(gettext("invalid processor "
848					    "ID %s\n"), *argv);
849					errors = ERR_FAIL;
850					continue;
851				}
852				if (do_cpu(pset, cpu, pflag, 1))
853					errors = ERR_FAIL;
854			} else {
855				/* range of processors */
856				processorid_t first, last;
857
858				first = (processorid_t)
859				    strtol(*argv, &errptr, 10);
860				if (*errptr++ != '-') {
861					warn(gettext(
862					    "invalid processor range %s\n"),
863					    *argv);
864					errors = ERR_USAGE;
865					continue;
866				}
867				last = (processorid_t)
868				    strtol(errptr, &errptr, 10);
869				if ((errptr != NULL && *errptr != '\0') ||
870				    last < first || first < 0) {
871					warn(gettext(
872					    "invalid processor range %s\n"),
873					    *argv);
874					errors = ERR_USAGE;
875					continue;
876				}
877				if (do_range(pset, first, last, pflag))
878					errors = ERR_FAIL;
879			}
880		}
881	} else if (bflag || uflag || qflag) {
882		/*
883		 * Perform function for each pid/lwpid specified.
884		 */
885		if (argc == 0 && !zflag) {
886			warn(gettext("must specify at least one pid\n"));
887			return (usage());
888		} else if (argc > 0 && zflag) {
889			warn(gettext("cannot specify extra pids with -z\n"));
890			return (usage());
891		}
892
893		if (zflag) {
894			zid = getzoneidbyname(zname);
895			if (zid < 0) {
896				warn(gettext("invalid zone name: %s\n"),
897				    zname);
898				errors = ERR_FAIL;
899			} else if (pset_bind(pset, P_ZONEID, zid,
900			    &old_pset) < 0) {
901				bind_err(pset, zname, -1, -1, errno);
902				errors = ERR_FAIL;
903			} else {
904				(void) printf(gettext("zone %s: bound to %d\n"),
905				    zname, pset);
906			}
907		}
908
909		/*
910		 * Go through listed processes/lwp_ranges.
911		 */
912		for (; argc > 0; argv++, argc--) {
913			pid = (id_t)strtol(*argv, &errptr, 10);
914			if (errno != 0 ||
915			    (errptr != NULL && *errptr != '\0' &&
916			    *errptr != '/')) {
917				warn(gettext("invalid process ID: %s\n"),
918				    *argv);
919				continue;
920			}
921			if (errptr != NULL && *errptr == '/') {
922				int ret;
923				/*
924				 * Handle lwp range case
925				 */
926				const char *lwps = (const char *)(++errptr);
927				if (*lwps == '\0' ||
928				    proc_lwp_range_valid(lwps) != 0) {
929					warn(gettext("invalid lwp range "
930					    "for pid %d\n"), (int)pid);
931					errors = ERR_FAIL;
932					continue;
933				}
934				if (!qflag)
935					(void) proc_initstdio();
936				ret = do_lwps(pid, lwps, pset);
937				if (!qflag)
938					(void) proc_finistdio();
939				if (ret != ERR_OK)
940					errors = ret;
941			} else {
942				/*
943				 * Handle whole process case.
944				 */
945				if (pset_bind(pset, P_PID, pid,
946				    &old_pset) < 0) {
947					bind_err(pset, NULL, pid, -1, errno);
948					errors = ERR_FAIL;
949					continue;
950				}
951				if (qflag)
952					query_out(pid, -1, old_pset);
953				else
954					bind_out(pid, -1, old_pset, pset);
955			}
956		}
957	}
958
959	if (Qflag || Uflag) {
960		/*
961		 * Go through listed processor set IDs.
962		 */
963		for (; argc > 0; argv++, argc--) {
964			errno = 0;
965			pset = (id_t)strtol(*argv, &errptr, 10);
966			if (errno != 0 ||
967			    (errptr != NULL && *errptr != '\0')) {
968				warn(gettext("invalid processor set ID\n"));
969				continue;
970			}
971			if (Qflag) {
972				(void) proc_walk(query_all_lwp,
973				    &pset, PR_WALK_LWP);
974				continue;
975			}
976			if (Uflag) {
977				if (pset_bind(PS_NONE, P_PSETID, pset,
978				    &old_pset) != 0) {
979					warn(gettext("failed to unbind from "
980					    "processor set %d"), (int)pset);
981					errors = ERR_FAIL;
982				}
983				continue;
984			}
985		}
986	}
987
988	return (errors);
989}
990