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