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
warn(char * format,...)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
die(char * format,...)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 *
grab_proc(id_t pid)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
rele_proc(struct ps_prochandle * Pr)123 rele_proc(struct ps_prochandle *Pr)
124 {
125 if (Pr == NULL)
126 return;
127 Prelease(Pr, 0);
128 }
129
130 static void
bind_err(psetid_t pset,id_t pid,id_t lwpid,int err)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
create_out(psetid_t pset)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
assign_out(processorid_t cpu,psetid_t old,psetid_t new)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
query_out(id_t pid,id_t lwpid,psetid_t pset)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
info_out(psetid_t pset,int type,uint_t numcpus,processorid_t * cpus)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
print_out(processorid_t cpu,psetid_t pset)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
bind_out(id_t pid,id_t lwpid,psetid_t old,psetid_t new)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
bind_lwp(id_t pid,id_t lwpid,psetid_t pset)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
do_cpu(psetid_t pset,processorid_t cpu,int print,int mustexist)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
do_range(psetid_t pset,processorid_t first,processorid_t last,int print)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
do_info(psetid_t pset)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
do_destroy(psetid_t pset)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
do_intr(psetid_t pset,int flag)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
info_all(void)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
print_all(void)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
query_all_proc(psinfo_t * psinfo,lwpsinfo_t * lwpsinfo,void * arg)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
query_all_lwp(psinfo_t * psinfo,lwpsinfo_t * lwpsinfo,void * arg)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
exec_cmd(psetid_t pset,char ** argv)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
usage(void)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
do_lwps(id_t pid,const char * range,psetid_t pset)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
main(int argc,char * argv[])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