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