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 2004 Sun Microsystems, Inc. All rights reserved. 24 * Use is subject to license terms. 25 */ 26 27 /* Copyright (c) 1984, 1986, 1987, 1988, 1989 AT&T */ 28 /* All Rights Reserved */ 29 30 31 #include <stdio.h> 32 #include <stdlib.h> 33 #include <string.h> 34 #include <wait.h> 35 #include <search.h> 36 #include <unistd.h> 37 #include <sys/types.h> 38 #include <dirent.h> 39 #include <fcntl.h> 40 #include <sys/param.h> 41 #include <sys/procset.h> 42 #include <sys/priocntl.h> 43 #include <procfs.h> 44 #include <macros.h> 45 #include <libgen.h> 46 #include <limits.h> 47 #include <errno.h> 48 49 #include "priocntl.h" 50 51 /* 52 * This file contains the code implementing the class independent part 53 * of the priocntl command. Most of the useful work for the priocntl 54 * command is done by the class specific sub-commands, the code for 55 * which is elsewhere. The class independent part of the command is 56 * responsible for executing the appropriate class specific sub-commands 57 * and providing any necessary input to the sub-commands. 58 * Code in this file should never assume any knowledge of any specific 59 * scheduler class (other than the SYS class). 60 */ 61 62 #define CLASSPATH "/usr/lib/class" 63 64 typedef struct classpids { 65 char clp_clname[PC_CLNMSZ]; 66 pid_t *clp_pidlist; 67 int clp_pidlistsz; 68 int clp_npids; 69 } classpids_t; 70 71 static char usage[] = 72 "usage: priocntl -l\n\ 73 priocntl -d [-i idtype] [idlist]\n\ 74 priocntl -s [-c class] [c.s.o.] [-i idtype] [idlist]\n\ 75 priocntl -e [-c class] [c.s.o.] command [argument(s)]\n"; 76 77 static char basenm[BASENMSZ]; 78 static char cmdpath[MAXPATHLEN]; 79 80 static char *procdir = "/proc"; 81 82 static int print_classlist(void); 83 static void set_procs(char *, idtype_t, int, char **, char **); 84 static void exec_cmd(char *, char **); 85 static int print_procs(idtype_t, int, char *[]); 86 static void ids2pids(idtype_t, id_t *, int, classpids_t *, int); 87 static void add_pid_tolist(classpids_t *, int, char *, pid_t); 88 static void increase_pidlist(classpids_t *); 89 static boolean_t idmatch(char *, char *, int, char **); 90 91 /* 92 * These variables are defined to be used in prio_getopt() below. 93 */ 94 static int prio_getopt(); 95 /* LINTED static unused */ 96 static int prio_optopt = 0; 97 static char *prio_optarg = 0; 98 static int prio_optind = 1; 99 static int prio_sp = 1; 100 101 int 102 main(int argc, char *argv[]) 103 { 104 int c; 105 int lflag, dflag, sflag, eflag, cflag, iflag, csoptsflag; 106 char *clname; 107 char *idtypnm; 108 idtype_t idtype; 109 int idargc; 110 char **idargv; 111 112 (void) strlcpy(cmdpath, argv[0], MAXPATHLEN); 113 (void) strlcpy(basenm, basename(argv[0]), BASENMSZ); 114 lflag = dflag = sflag = eflag = cflag = iflag = csoptsflag = 0; 115 while ((c = prio_getopt(argc, argv, "ldsec:i:")) != -1) { 116 117 switch (c) { 118 119 case 'l': 120 lflag++; 121 break; 122 123 case 'd': 124 dflag++; 125 break; 126 127 case 's': 128 sflag++; 129 break; 130 131 case 'e': 132 eflag++; 133 break; 134 135 case 'c': 136 cflag++; 137 clname = prio_optarg; 138 break; 139 140 case 'i': 141 iflag++; 142 idtypnm = prio_optarg; 143 break; 144 145 case '?': 146 if (strcmp(argv[prio_optind - 1], "-c") == 0 || 147 strcmp(argv[prio_optind - 1], "-i") == 0) { 148 149 /* 150 * getopt() will return ? if either 151 * of these appear without an argument. 152 */ 153 fatalerr(usage); 154 } 155 156 /* 157 * We assume for now that any option that 158 * getopt() doesn't recognize (with the 159 * exception of c and i) is intended for a 160 * class specific subcommand. For now we also 161 * require that all class specific options 162 * take an argument (until we can get smarter 163 * about parsing our options). 164 */ 165 csoptsflag++; 166 prio_optind++; 167 prio_sp = 1; 168 break; 169 170 default: 171 break; 172 } 173 } 174 175 if (lflag) { 176 if (dflag || sflag || eflag || cflag || iflag || csoptsflag) 177 fatalerr(usage); 178 179 return (print_classlist()); 180 181 } else if (dflag) { 182 if (lflag || sflag || eflag || cflag || csoptsflag) 183 fatalerr(usage); 184 if (iflag) { 185 if (str2idtyp(idtypnm, &idtype) == -1) 186 fatalerr("%s: bad idtype %s\n", cmdpath, 187 idtypnm); 188 } else { 189 idtype = P_PID; 190 } 191 192 if (prio_optind < argc) { 193 idargc = argc - prio_optind; 194 idargv = &argv[prio_optind]; 195 } else { 196 idargc = 0; 197 } 198 199 return (print_procs(idtype, idargc, idargv)); 200 201 } else if (sflag) { 202 if (lflag || dflag || eflag) 203 fatalerr(usage); 204 if (iflag) { 205 if (str2idtyp(idtypnm, &idtype) == -1) 206 fatalerr("%s: bad idtype %s\n", cmdpath, 207 idtypnm); 208 } else { 209 idtype = P_PID; 210 } 211 212 if (cflag == 0) 213 clname = NULL; 214 215 if (prio_optind < argc) { 216 idargc = argc - prio_optind; 217 idargv = &argv[prio_optind]; 218 } else { 219 idargc = 0; 220 } 221 222 set_procs(clname, idtype, idargc, idargv, argv); 223 224 } else if (eflag) { 225 if (lflag || dflag || sflag || iflag) 226 fatalerr(usage); 227 228 if (cflag == 0) 229 clname = NULL; 230 231 if (prio_optind >= argc) 232 fatalerr(usage); 233 234 exec_cmd(clname, argv); 235 236 } else { 237 fatalerr(usage); 238 } 239 240 return (0); 241 } 242 243 244 /* 245 * Print the heading for the class list and execute the class 246 * specific sub-command with the -l option for each configured class. 247 */ 248 static int 249 print_classlist(void) 250 { 251 id_t cid; 252 int nclass; 253 pcinfo_t pcinfo; 254 static char subcmdpath[128]; 255 int status; 256 pid_t pid; 257 int error = 0; 258 259 /* 260 * No special privileges required for this operation. 261 * Set the effective UID back to the real UID. 262 */ 263 if (setuid(getuid()) == -1) 264 fatalerr("%s: Can't set effective UID back to real UID\n", 265 cmdpath); 266 267 if ((nclass = priocntl(0, 0, PC_GETCLINFO, NULL)) == -1) 268 fatalerr("%s: Can't get number of configured classes, priocntl" 269 " system call failed with errno %d\n", cmdpath, errno); 270 271 (void) printf("CONFIGURED CLASSES\n==================\n\n"); 272 (void) printf("SYS (System Class)\n"); 273 for (cid = 1; cid < nclass; cid++) { 274 (void) printf("\n"); 275 (void) fflush(stdout); 276 pcinfo.pc_cid = cid; 277 if (priocntl(0, 0, PC_GETCLINFO, (caddr_t)&pcinfo) == -1) 278 fatalerr("%s: can't get class name (class ID = %ld)\n", 279 cmdpath, cid); 280 if (snprintf(subcmdpath, sizeof (subcmdpath), "%s/%s/%s%s", 281 CLASSPATH, pcinfo.pc_clname, pcinfo.pc_clname, basenm) >= 282 sizeof (subcmdpath)) 283 fatalerr("%s: can't generate %s specific subcommand\n", 284 cmdpath, pcinfo.pc_clname); 285 if ((pid = fork()) == 0) { 286 (void) execl(subcmdpath, subcmdpath, "-l", (char *)0); 287 (void) printf("%s\n", pcinfo.pc_clname); 288 fatalerr("\tCan't execute %s specific subcommand\n", 289 pcinfo.pc_clname); 290 } else if (pid == (pid_t)-1) { 291 (void) printf("%s\n", pcinfo.pc_clname); 292 (void) fprintf(stderr, 293 "Can't execute %s specific subcommand)\n", 294 pcinfo.pc_clname); 295 error = 1; 296 } else { 297 (void) wait(&status); 298 if (status) 299 error = 1; 300 } 301 } 302 303 return (error); 304 } 305 306 307 /* 308 * For each class represented within the set of processes specified by 309 * idtype/idargv, print_procs() executes the class specific sub-command 310 * with the -d option. We pipe to each sub-command a list of pids in 311 * the set belonging to that class. 312 */ 313 static int 314 print_procs(idtype_t idtype, int idargc, char *idargv[]) 315 { 316 int i; 317 id_t id; 318 id_t idlist[NIDS]; 319 int nids; 320 classpids_t *clpids; 321 int nclass; 322 id_t cid; 323 pcinfo_t pcinfo; 324 int pidexists; 325 FILE *pipe_to_subcmd; 326 char subcmd[128]; 327 int error = 0; 328 329 330 /* 331 * Build a list of ids eliminating any duplicates in idargv. 332 */ 333 if (idtype == P_ALL) { 334 /* 335 * No idlist should be specified. If one is specified, 336 * it is ignored. 337 */ 338 nids = 0; 339 } else if (idargc == 0) { 340 341 /* 342 * No ids supplied by user; use current id. 343 */ 344 if (getmyid(idtype, &idlist[0]) == -1) 345 fatalerr("%s: Can't get ID for current process," 346 " idtype = %d\n", cmdpath, idtype); 347 nids = 1; 348 } else { 349 nids = 0; 350 for (i = 0; i < idargc && nids < NIDS; i++) { 351 if (idtype == P_CID) { 352 if ((id = clname2cid(idargv[i])) == -1) { 353 (void) fprintf(stderr, "%s: Invalid or" 354 " unconfigured class %s in idlist" 355 " - ignored\n", cmdpath, idargv[i]); 356 error = 1; 357 } 358 } else { 359 id = (id_t)str2num(idargv[i], INT_MIN, INT_MAX); 360 if (errno) { 361 (void) fprintf(stderr, 362 "%s: Invalid id \"%s\"\n", 363 cmdpath, idargv[i]); 364 error = 1; 365 id = BADPID; 366 } 367 } 368 369 /* 370 * lsearch(3C) adds ids to the idlist, 371 * eliminating duplicates. 372 */ 373 (void) lsearch((void *)&id, (void *)idlist, 374 (size_t *)&nids, sizeof (id), (int (*)())idcompar); 375 } 376 } 377 378 if ((nclass = priocntl(0, 0, PC_GETCLINFO, NULL)) == -1) 379 fatalerr("%s: Can't get number of configured classes, priocntl" 380 " system call failed with errno %d\n", cmdpath, errno); 381 382 if ((clpids = (classpids_t *)malloc(sizeof (classpids_t) * nclass)) == 383 NULL) 384 fatalerr("%s: Can't allocate memory for clpids.\n", cmdpath); 385 386 for (cid = 1; cid < nclass; cid++) { 387 pcinfo.pc_cid = cid; 388 if (priocntl(0, 0, PC_GETCLINFO, (caddr_t)&pcinfo) == -1) 389 fatalerr("%s: Can't get class name, cid = %ld\n", 390 cmdpath, cid); 391 392 (void) strncpy(clpids[cid].clp_clname, pcinfo.pc_clname, 393 PC_CLNMSZ); 394 395 /* 396 * The memory allocation for the pidlist uses realloc(). 397 * A realloc() call is required, when "clp_npids" is 398 * equal to "clp_pidlistsz". 399 */ 400 clpids[cid].clp_pidlist = (pid_t *)NULL; 401 clpids[cid].clp_pidlistsz = 0; 402 clpids[cid].clp_npids = 0; 403 } 404 405 /* 406 * Build the pidlist. 407 */ 408 ids2pids(idtype, idlist, nids, clpids, nclass); 409 410 /* 411 * No need for special privileges any more. 412 * Set the effective UID back to the real UID. 413 */ 414 if (setuid(getuid()) == -1) 415 fatalerr("%s: Can't set effective UID back to real UID\n", 416 cmdpath); 417 418 pidexists = 0; 419 for (cid = 1; cid < nclass; cid++) { 420 if (clpids[cid].clp_npids == 0) 421 continue; 422 423 pidexists = 1; 424 if (snprintf(subcmd, sizeof (subcmd), "%s/%s/%s%s -d", 425 CLASSPATH, clpids[cid].clp_clname, clpids[cid].clp_clname, 426 basenm) >= sizeof (subcmd)) { 427 (void) fprintf(stderr, 428 "Can't generate %s specific subcommand\n", 429 clpids[cid].clp_clname); 430 error = 1; 431 free(clpids[cid].clp_pidlist); 432 continue; 433 } 434 if ((pipe_to_subcmd = popen(subcmd, "w")) == NULL) { 435 (void) printf("%s\n", clpids[cid].clp_clname); 436 (void) fprintf(stderr, 437 "Can't execute %s specific subcommand\n", 438 clpids[cid].clp_clname); 439 error = 1; 440 free(clpids[cid].clp_pidlist); 441 continue; 442 } 443 (void) fwrite(clpids[cid].clp_pidlist, sizeof (pid_t), 444 clpids[cid].clp_npids, pipe_to_subcmd); 445 if (pclose(pipe_to_subcmd)) 446 error = 1; 447 448 free(clpids[cid].clp_pidlist); 449 } 450 451 free(clpids); 452 453 if (pidexists == 0) 454 fatalerr("%s: Process(es) not found.\n", cmdpath); 455 456 return (error); 457 } 458 459 460 /* 461 * Execute the appropriate class specific sub-command with the arguments 462 * pointed to by subcmdargv. If the user specified a class we simply 463 * exec the sub-command for that class. If no class was specified we 464 * verify that the processes in the set specified by idtype/idargv are 465 * all in the same class and then execute the sub-command for that class. 466 */ 467 static void 468 set_procs(char *clname, idtype_t idtype, int idargc, char **idargv, 469 char **subcmdargv) 470 { 471 char idstr[PC_IDTYPNMSZ]; 472 char myidstr[PC_IDTYPNMSZ]; 473 char clnmbuf[PC_CLNMSZ]; 474 pcinfo_t pcinfo; 475 static psinfo_t prinfo; 476 static prcred_t prcred; 477 DIR *dirp; 478 struct dirent *dentp; 479 static char pname[100]; 480 char *fname; 481 int procfd; 482 int saverr; 483 static char subcmdpath[128]; 484 boolean_t procinset; 485 id_t id; 486 size_t len; 487 488 if (clname == NULL && idtype == P_PID && idargc <= 1) { 489 490 /* 491 * No class specified by user but only one process 492 * in specified set. Get the class the easy way. 493 */ 494 if (idargc == 0) { 495 if (priocntl(P_PID, P_MYID, PC_GETXPARMS, NULL, 496 PC_KY_CLNAME, clnmbuf, 0) == -1) 497 if (errno == ESRCH) 498 fatalerr("%s: Process not found.\n", 499 cmdpath); 500 else 501 fatalerr("%s: Can't get class of" 502 " current process\npriocntl" 503 " system call failed with" 504 " errno %d\n", cmdpath, errno); 505 } else { 506 /* idargc == 1 */ 507 id = (id_t)str2num(idargv[0], INT_MIN, INT_MAX); 508 if (errno) 509 fatalerr("%s: Invalid id \"%s\"\n", cmdpath, 510 idargv[0]); 511 512 if (priocntl(P_PID, id, PC_GETXPARMS, 513 NULL, PC_KY_CLNAME, clnmbuf, 0) == -1) 514 if (errno == ESRCH) 515 fatalerr("%s: Process not found.\n", 516 cmdpath); 517 else 518 fatalerr("%s: Can't get class of " 519 " specified process\npriocntl" 520 " system call failed with" 521 " errno %d\n", cmdpath, errno); 522 } 523 524 clname = clnmbuf; 525 } else if (clname == NULL) { 526 527 /* 528 * No class specified by user and potentially more 529 * than one process in specified set. Verify that 530 * all procs in set are in the same class. 531 */ 532 if (idargc == 0 && idtype != P_ALL) { 533 534 /* 535 * No ids supplied by user; use current id. 536 */ 537 if (getmyidstr(idtype, myidstr) == -1) 538 fatalerr("%s: Can't get ID string for current" 539 " process, idtype = %d\n", cmdpath, idtype); 540 } 541 if ((dirp = opendir(procdir)) == NULL) 542 fatalerr("%s: Can't open PROC directory %s\n", 543 cmdpath, procdir); 544 545 while ((dentp = readdir(dirp)) != NULL) { 546 if (dentp->d_name[0] == '.') /* skip . and .. */ 547 continue; 548 549 len = snprintf(pname, sizeof (pname), "%s/%s/", 550 procdir, dentp->d_name); 551 /* Really max(sizeof ("psinfo"), sizeof ("cred")) */ 552 if (len + sizeof ("psinfo") > sizeof (pname)) { 553 (void) fprintf(stderr, 554 "%s: skipping %s, name too long.\n", 555 cmdpath, dentp->d_name); 556 continue; 557 } 558 fname = pname + len; 559 retry: 560 (void) strcpy(fname, "psinfo"); 561 if ((procfd = open(pname, O_RDONLY)) < 0) 562 continue; 563 564 if (read(procfd, &prinfo, sizeof (prinfo)) != 565 sizeof (prinfo)) { 566 saverr = errno; 567 (void) close(procfd); 568 if (saverr == EAGAIN) 569 goto retry; 570 if (saverr != ENOENT) { 571 (void) fprintf(stderr, 572 "%s: Can't get process info for" 573 " %s\n", cmdpath, pname); 574 } 575 continue; 576 } 577 (void) close(procfd); 578 579 if (idtype == P_UID || idtype == P_GID) { 580 (void) strcpy(fname, "cred"); 581 if ((procfd = open(pname, O_RDONLY)) < 0 || 582 read(procfd, &prcred, sizeof (prcred)) != 583 sizeof (prcred)) { 584 saverr = errno; 585 if (procfd >= 0) 586 (void) close(procfd); 587 if (saverr == EAGAIN) 588 goto retry; 589 if (saverr != ENOENT) { 590 (void) fprintf(stderr, 591 "%s: Can't get process" 592 " credentials for %s\n", 593 cmdpath, pname); 594 } 595 continue; 596 } 597 (void) close(procfd); 598 } 599 600 if (prinfo.pr_lwp.pr_state == 0 || prinfo.pr_nlwp == 0) 601 continue; 602 603 604 switch (idtype) { 605 606 case P_PID: 607 itoa((long)prinfo.pr_pid, idstr); 608 procinset = idmatch(idstr, myidstr, 609 idargc, idargv); 610 break; 611 612 case P_PPID: 613 itoa((long)prinfo.pr_ppid, idstr); 614 procinset = idmatch(idstr, myidstr, 615 idargc, idargv); 616 break; 617 618 case P_PGID: 619 itoa((long)prinfo.pr_pgid, idstr); 620 procinset = idmatch(idstr, myidstr, 621 idargc, idargv); 622 break; 623 624 case P_SID: 625 itoa((long)prinfo.pr_sid, idstr); 626 procinset = idmatch(idstr, myidstr, 627 idargc, idargv); 628 break; 629 630 case P_CID: 631 procinset = idmatch(prinfo.pr_lwp.pr_clname, 632 myidstr, idargc, idargv); 633 break; 634 635 case P_UID: 636 itoa((long)prcred.pr_euid, idstr); 637 procinset = idmatch(idstr, myidstr, 638 idargc, idargv); 639 break; 640 641 case P_GID: 642 itoa((long)prcred.pr_egid, idstr); 643 procinset = idmatch(idstr, myidstr, 644 idargc, idargv); 645 break; 646 647 case P_PROJID: 648 itoa((long)prinfo.pr_projid, idstr); 649 procinset = idmatch(idstr, myidstr, 650 idargc, idargv); 651 break; 652 653 case P_TASKID: 654 itoa((long)prinfo.pr_taskid, idstr); 655 procinset = idmatch(idstr, myidstr, 656 idargc, idargv); 657 break; 658 659 case P_ZONEID: 660 itoa((long)prinfo.pr_zoneid, idstr); 661 procinset = idmatch(idstr, myidstr, 662 idargc, idargv); 663 break; 664 665 case P_CTID: 666 itoa((long)prinfo.pr_contract, idstr); 667 procinset = idmatch(idstr, myidstr, 668 idargc, idargv); 669 break; 670 671 case P_ALL: 672 procinset = B_TRUE; 673 break; 674 675 default: 676 fatalerr("%s: Bad idtype %d in set_procs()\n", 677 cmdpath, idtype); 678 } 679 if (procinset == B_TRUE) { 680 if (clname == NULL) { 681 682 /* 683 * First proc found in set. 684 */ 685 (void) strcpy(clnmbuf, 686 prinfo.pr_lwp.pr_clname); 687 clname = clnmbuf; 688 } else if (strcmp(clname, 689 prinfo.pr_lwp.pr_clname) != 0) { 690 fatalerr("%s: Specified processes" 691 " from different classes.\n", 692 cmdpath); 693 } 694 } 695 } 696 (void) closedir(dirp); 697 if (clname == NULL) 698 fatalerr("%s: Process(es) not found.\n", cmdpath); 699 } else { 700 701 /* 702 * User specified class. Check it for validity. 703 */ 704 (void) strcpy(pcinfo.pc_clname, clname); 705 if (priocntl(0, 0, PC_GETCID, (caddr_t)&pcinfo) == -1) 706 fatalerr("%s: Invalid or unconfigured class %s\n", 707 cmdpath, clname); 708 } 709 710 /* 711 * No need for special privileges any more. 712 * Set the effective UID back to the real UID. 713 */ 714 if (setuid(getuid()) == -1) 715 fatalerr("%s: Can't set effective UID back to real UID\n", 716 cmdpath); 717 718 if (snprintf(subcmdpath, sizeof (subcmdpath), "%s/%s/%s%s", 719 CLASSPATH, clname, clname, basenm) >= sizeof (subcmdpath)) 720 fatalerr("%s: can't generate %s specific subcommand\n", 721 cmdpath, clname); 722 723 subcmdargv[0] = subcmdpath; 724 (void) execv(subcmdpath, subcmdargv); 725 fatalerr("%s: Can't execute %s sub-command\n", cmdpath, clname); 726 } 727 728 729 /* 730 * Execute the appropriate class specific sub-command with the arguments 731 * pointed to by subcmdargv. If the user specified a class we simply 732 * exec the sub-command for that class. If no class was specified we 733 * execute the sub-command for our own current class. 734 */ 735 static void 736 exec_cmd(char *clname, char **subcmdargv) 737 { 738 pcinfo_t pcinfo; 739 char clnmbuf[PC_CLNMSZ]; 740 char subcmdpath[128]; 741 742 /* 743 * No special privileges required for this operation. 744 * Set the effective UID back to the real UID. 745 */ 746 if (setuid(getuid()) == -1) 747 fatalerr("%s: Can't set effective UID back to real UID\n", 748 cmdpath); 749 750 if (clname == NULL) { 751 if (priocntl(P_PID, P_MYID, PC_GETXPARMS, NULL, 752 PC_KY_CLNAME, clnmbuf, 0) == -1) 753 fatalerr("%s: Can't get class name of current process\n" 754 "priocntl system call failed with errno %d\n", 755 cmdpath, errno); 756 757 clname = clnmbuf; 758 } else { 759 760 /* 761 * User specified class. Check it for validity. 762 */ 763 (void) strcpy(pcinfo.pc_clname, clname); 764 if (priocntl(0, 0, PC_GETCID, (caddr_t)&pcinfo) == -1) 765 fatalerr("%s: Invalid or unconfigured class %s\n", 766 cmdpath, clname); 767 } 768 769 if (snprintf(subcmdpath, sizeof (subcmdpath), "%s/%s/%s%s", 770 CLASSPATH, clname, clname, basenm) >= sizeof (subcmdpath)) 771 fatalerr("%s: can't generate %s specific subcommand\n", 772 cmdpath, clname); 773 subcmdargv[0] = subcmdpath; 774 (void) execv(subcmdpath, subcmdargv); 775 fatalerr("%s: Can't execute %s sub-command\n", cmdpath, clname); 776 } 777 778 779 /* 780 * Fill in the classpids structures in the array pointed to by clpids 781 * with pids for the processes in the set specified by idtype/idlist. 782 * We read the /proc/<pid>/psinfo file to get the necessary process 783 * information. 784 */ 785 static void 786 ids2pids(idtype_t idtype, id_t *idlist, int nids, classpids_t *clpids, 787 int nclass) 788 { 789 static psinfo_t prinfo; 790 static prcred_t prcred; 791 DIR *dirp; 792 struct dirent *dentp; 793 char pname[100]; 794 char *fname; 795 int procfd; 796 int saverr; 797 int i; 798 char *clname; 799 size_t len; 800 801 if ((dirp = opendir(procdir)) == NULL) 802 fatalerr("%s: Can't open PROC directory %s\n", 803 cmdpath, procdir); 804 805 while ((dentp = readdir(dirp)) != NULL) { 806 if (dentp->d_name[0] == '.') /* skip . and .. */ 807 continue; 808 809 len = snprintf(pname, sizeof (pname), "%s/%s/", 810 procdir, dentp->d_name); 811 /* Really max(sizeof ("psinfo"), sizeof ("cred")) */ 812 if (len + sizeof ("psinfo") > sizeof (pname)) { 813 (void) fprintf(stderr, 814 "%s: skipping %s, name too long.\n", 815 cmdpath, dentp->d_name); 816 continue; 817 } 818 fname = pname + len; 819 retry: 820 (void) strcpy(fname, "psinfo"); 821 if ((procfd = open(pname, O_RDONLY)) < 0) 822 continue; 823 if (read(procfd, &prinfo, sizeof (prinfo)) != sizeof (prinfo)) { 824 saverr = errno; 825 (void) close(procfd); 826 if (saverr == EAGAIN) 827 goto retry; 828 if (saverr != ENOENT) { 829 (void) fprintf(stderr, 830 "%s: Can't get process info for %s\n", 831 cmdpath, pname); 832 } 833 continue; 834 } 835 (void) close(procfd); 836 837 if (idtype == P_UID || idtype == P_GID) { 838 (void) strcpy(fname, "cred"); 839 if ((procfd = open(pname, O_RDONLY)) < 0 || 840 read(procfd, &prcred, sizeof (prcred)) != 841 sizeof (prcred)) { 842 saverr = errno; 843 (void) close(procfd); 844 if (saverr == EAGAIN) 845 goto retry; 846 if (saverr != ENOENT) { 847 (void) fprintf(stderr, 848 "%s: Can't get process credentials" 849 " for %s\n", 850 cmdpath, pname); 851 } 852 continue; 853 } 854 (void) close(procfd); 855 } 856 857 if (prinfo.pr_lwp.pr_state == 0 || prinfo.pr_nlwp == 0) 858 continue; 859 860 switch (idtype) { 861 862 case P_PID: 863 for (i = 0; i < nids; i++) { 864 if (idlist[i] == (id_t)prinfo.pr_pid) 865 add_pid_tolist(clpids, nclass, 866 prinfo.pr_lwp.pr_clname, 867 prinfo.pr_pid); 868 } 869 break; 870 871 case P_PPID: 872 for (i = 0; i < nids; i++) { 873 if (idlist[i] == (id_t)prinfo.pr_ppid) 874 add_pid_tolist(clpids, nclass, 875 prinfo.pr_lwp.pr_clname, 876 prinfo.pr_pid); 877 } 878 break; 879 880 case P_PGID: 881 for (i = 0; i < nids; i++) { 882 if (idlist[i] == (id_t)prinfo.pr_pgid) 883 add_pid_tolist(clpids, nclass, 884 prinfo.pr_lwp.pr_clname, 885 prinfo.pr_pid); 886 } 887 break; 888 889 case P_SID: 890 for (i = 0; i < nids; i++) { 891 if (idlist[i] == (id_t)prinfo.pr_sid) 892 add_pid_tolist(clpids, nclass, 893 prinfo.pr_lwp.pr_clname, 894 prinfo.pr_pid); 895 } 896 break; 897 898 case P_CID: 899 for (i = 0; i < nids; i++) { 900 clname = clpids[idlist[i]].clp_clname; 901 if (strcmp(clname, 902 prinfo.pr_lwp.pr_clname) == 0) 903 add_pid_tolist(clpids, nclass, 904 prinfo.pr_lwp.pr_clname, 905 prinfo.pr_pid); 906 } 907 break; 908 909 case P_UID: 910 for (i = 0; i < nids; i++) { 911 if (idlist[i] == (id_t)prcred.pr_euid) 912 add_pid_tolist(clpids, nclass, 913 prinfo.pr_lwp.pr_clname, 914 prinfo.pr_pid); 915 } 916 break; 917 918 case P_GID: 919 for (i = 0; i < nids; i++) { 920 if (idlist[i] == (id_t)prcred.pr_egid) 921 add_pid_tolist(clpids, nclass, 922 prinfo.pr_lwp.pr_clname, 923 prinfo.pr_pid); 924 } 925 break; 926 927 case P_PROJID: 928 for (i = 0; i < nids; i++) { 929 if (idlist[i] == (id_t)prinfo.pr_projid) 930 add_pid_tolist(clpids, nclass, 931 prinfo.pr_lwp.pr_clname, 932 prinfo.pr_pid); 933 } 934 break; 935 936 case P_TASKID: 937 for (i = 0; i < nids; i++) { 938 if (idlist[i] == (id_t)prinfo.pr_taskid) 939 add_pid_tolist(clpids, nclass, 940 prinfo.pr_lwp.pr_clname, 941 prinfo.pr_pid); 942 } 943 break; 944 945 case P_ZONEID: 946 for (i = 0; i < nids; i++) { 947 if (idlist[i] == (id_t)prinfo.pr_zoneid) 948 add_pid_tolist(clpids, nclass, 949 prinfo.pr_lwp.pr_clname, 950 prinfo.pr_pid); 951 } 952 break; 953 954 case P_CTID: 955 for (i = 0; i < nids; i++) { 956 if (idlist[i] == (id_t)prinfo.pr_contract) 957 add_pid_tolist(clpids, nclass, 958 prinfo.pr_lwp.pr_clname, 959 prinfo.pr_pid); 960 } 961 break; 962 963 case P_ALL: 964 add_pid_tolist(clpids, nclass, prinfo.pr_lwp.pr_clname, 965 prinfo.pr_pid); 966 break; 967 968 default: 969 fatalerr("%s: Bad idtype %d in ids2pids()\n", 970 cmdpath, idtype); 971 } 972 } 973 (void) closedir(dirp); 974 } 975 976 977 /* 978 * Search the array pointed to by clpids for the classpids 979 * structure corresponding to clname and add pid to its 980 * pidlist. 981 */ 982 static void 983 add_pid_tolist(classpids_t *clpids, int nclass, char *clname, pid_t pid) 984 { 985 classpids_t *clp; 986 987 for (clp = clpids; clp != &clpids[nclass]; clp++) { 988 if (strcmp(clp->clp_clname, clname) == 0) { 989 if (clp->clp_npids == clp->clp_pidlistsz) 990 increase_pidlist(clp); 991 992 (clp->clp_pidlist)[clp->clp_npids] = pid; 993 clp->clp_npids++; 994 return; 995 } 996 } 997 } 998 999 1000 static void 1001 increase_pidlist(classpids_t *clp) 1002 { 1003 if ((clp->clp_pidlist = realloc(clp->clp_pidlist, 1004 (clp->clp_pidlistsz + NPIDS) * sizeof (pid_t))) == NULL) 1005 /* 1006 * The pidlist is filled up and we cannot increase the size. 1007 */ 1008 fatalerr("%s: Can't allocate memory for pidlist.\n", cmdpath); 1009 1010 clp->clp_pidlistsz += NPIDS; 1011 } 1012 1013 1014 /* 1015 * Compare id strings for equality. If idargv contains ids 1016 * (idargc > 0) compare idstr to each id in idargv, otherwise 1017 * just compare to curidstr. 1018 */ 1019 static boolean_t 1020 idmatch(char *idstr, char *curidstr, int idargc, char **idargv) 1021 { 1022 int i; 1023 1024 if (idargc == 0) { 1025 if (strcmp(curidstr, idstr) == 0) 1026 return (B_TRUE); 1027 } else { 1028 for (i = 0; i < idargc; i++) { 1029 if (strcmp(idargv[i], idstr) == 0) 1030 return (B_TRUE); 1031 } 1032 } 1033 return (B_FALSE); 1034 } 1035 1036 /* 1037 * This is a copy of the getopt() function found in libc:getopt.c. A separate 1038 * copy is required to fix the bug id #1114636. To fix the problem we need to 1039 * reset the _sp to 1. Since _sp in libc:getopt() is not exposed, a copy of 1040 * the getopt() is kept so that prio_sp can be reset to 1. 1041 */ 1042 1043 static int 1044 prio_getopt(int argc, char * const *argv, char *opts) 1045 { 1046 char c; 1047 char *cp; 1048 1049 if (prio_sp == 1) 1050 if (prio_optind >= argc || 1051 argv[prio_optind][0] != '-' || argv[prio_optind][1] == '\0') 1052 return (EOF); 1053 else if (strcmp(argv[prio_optind], "--") == 0) { 1054 prio_optind++; 1055 return (EOF); 1056 } 1057 prio_optopt = c = (unsigned char)argv[prio_optind][prio_sp]; 1058 if (c == ':' || (cp = strchr(opts, c)) == NULL) { 1059 if (argv[prio_optind][++prio_sp] == '\0') { 1060 prio_optind++; 1061 prio_sp = 1; 1062 } 1063 return ('?'); 1064 } 1065 if (*++cp == ':') { 1066 if (argv[prio_optind][prio_sp+1] != '\0') 1067 prio_optarg = &argv[prio_optind++][prio_sp+1]; 1068 else if (++prio_optind >= argc) { 1069 prio_sp = 1; 1070 return ('?'); 1071 } else 1072 prio_optarg = argv[prio_optind++]; 1073 prio_sp = 1; 1074 } else { 1075 if (argv[prio_optind][++prio_sp] == '\0') { 1076 prio_sp = 1; 1077 prio_optind++; 1078 } 1079 prio_optarg = NULL; 1080 } 1081 return (c); 1082 } 1083