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