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