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
main(int argc,char * argv[])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
print_classlist(void)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
print_procs(idtype_t idtype,int idargc,char * idargv[])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
set_procs(char * clname,idtype_t idtype,int idargc,char ** idargv,char ** subcmdargv)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
exec_cmd(char * clname,char ** subcmdargv)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
ids2pids(idtype_t idtype,id_t * idlist,int nids,classpids_t * clpids,int nclass)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
add_pid_tolist(classpids_t * clpids,int nclass,char * clname,pid_t pid)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
increase_pidlist(classpids_t * clp)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
idmatch(char * idstr,char * curidstr,int idargc,char ** idargv)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
prio_getopt(int argc,char * const * argv,char * opts)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