xref: /illumos-gate/usr/src/cmd/psrset/psrset.c (revision 0cc80ade)
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 
59 static char *progname;
60 static int errors;
61 static char cflag;
62 static char dflag;
63 static char aflag;
64 static char rflag;
65 static char iflag;
66 static char bflag;
67 static char uflag;
68 static char Uflag;
69 static char qflag;
70 static char Qflag;
71 static char pflag;
72 static char nflag;
73 static char fflag;
74 static char Fflag;
75 static char eflag;
76 static char zflag;
77 static const char *zname;
78 
79 extern int pset_assign_forced(psetid_t, processorid_t, psetid_t *);
80 
81 /*PRINTFLIKE1*/
82 static void
warn(char * format,...)83 warn(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*/
97 static void
die(char * format,...)98 die(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 
112 static struct ps_prochandle *
grab_proc(id_t pid)113 grab_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 
128 static void
rele_proc(struct ps_prochandle * Pr)129 rele_proc(struct ps_prochandle *Pr)
130 {
131 	if (Pr == NULL)
132 		return;
133 	Prelease(Pr, 0);
134 }
135 
136 static void
bind_err(psetid_t pset,const char * zname,id_t pid,id_t lwpid,int err)137 bind_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  */
165 static void
create_out(psetid_t pset)166 create_out(psetid_t pset)
167 {
168 	(void) printf("%s %d\n", gettext("created processor set"), pset);
169 }
170 
171 /*
172  * Output for assign.
173  */
174 static void
assign_out(processorid_t cpu,psetid_t old,psetid_t new)175 assign_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  */
197 static void
query_out(id_t pid,id_t lwpid,psetid_t pset)198 query_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  */
221 static void
info_out(psetid_t pset,int type,uint_t numcpus,processorid_t * cpus)222 info_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  */
243 static void
print_out(processorid_t cpu,psetid_t pset)244 print_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  */
255 static void
bind_out(id_t pid,id_t lwpid,psetid_t old,psetid_t new)256 bind_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 
286 static void
bind_lwp(id_t pid,id_t lwpid,psetid_t pset)287 bind_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 
303 static int
do_cpu(psetid_t pset,processorid_t cpu,int print,int mustexist)304 do_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 
335 static int
do_range(psetid_t pset,processorid_t first,processorid_t last,int print)336 do_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 
356 static int
do_info(psetid_t pset)357 do_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 
380 static int
do_destroy(psetid_t pset)381 do_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 
391 static int
do_intr(psetid_t pset,int flag)392 do_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  */
428 static int
info_all(void)429 info_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  */
468 static int
print_all(void)469 print_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*/
489 static int
query_all_proc(psinfo_t * psinfo,lwpsinfo_t * lwpsinfo,void * arg)490 query_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 
511 static int
query_all_lwp(psinfo_t * psinfo,lwpsinfo_t * lwpsinfo,void * arg)512 query_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 
527 void
exec_cmd(psetid_t pset,char ** argv)528 exec_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 
539 int
usage(void)540 usage(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  */
566 static int
do_lwps(id_t pid,const char * range,psetid_t pset)567 do_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 
639 int
main(int argc,char * argv[])640 main(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