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