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