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 <string.h>
35 #include <strings.h>
36 #include <stdlib.h>
37 #include <unistd.h>
38 #include <sys/types.h>
39 #include <limits.h>
40 #include <dirent.h>
41 #include <fcntl.h>
42 #include <sys/time.h>
43 #include <sys/procset.h>
44 #include <sys/priocntl.h>
45 #include <sys/task.h>
46 #include <procfs.h>
47 #include <project.h>
48 #include <errno.h>
49 #include <zone.h>
50 #include <libcontract_priv.h>
51
52 #include "priocntl.h"
53
54 /*LINTLIBRARY*/
55
56 /*
57 * Utility functions for priocntl command.
58 */
59
60 static char *procdir = "/proc";
61
62 /*PRINTFLIKE1*/
63 void
fatalerr(format,a1,a2,a3,a4,a5)64 fatalerr(format, a1, a2, a3, a4, a5)
65 char *format;
66 int a1, a2, a3, a4, a5;
67 {
68 (void) fprintf(stderr, format, a1, a2, a3, a4, a5);
69 exit(1);
70 }
71
72
73 /*
74 * Structure defining idtypes known to the priocntl command
75 * along with the corresponding names and a liberal guess
76 * of the max number of procs sharing any given ID of that type.
77 * The idtype values themselves are defined in <sys/procset.h>.
78 */
79 static struct idtypes {
80 idtype_t idtype;
81 char *idtypnm;
82 } idtypes [] = {
83 { P_PID, "pid" },
84 { P_PPID, "ppid" },
85 { P_PGID, "pgid" },
86 { P_SID, "sid" },
87 { P_CID, "class" },
88 { P_UID, "uid" },
89 { P_GID, "gid" },
90 { P_PROJID, "projid" },
91 { P_TASKID, "taskid" },
92 { P_ZONEID, "zoneid" },
93 { P_CTID, "ctid" },
94 { P_ALL, "all" }
95 };
96
97 #define IDCNT (sizeof (idtypes) / sizeof (struct idtypes))
98
99
100 int
str2idtyp(idtypnm,idtypep)101 str2idtyp(idtypnm, idtypep)
102 char *idtypnm;
103 idtype_t *idtypep;
104 {
105 register struct idtypes *curp;
106 register struct idtypes *endp;
107
108 for (curp = idtypes, endp = &idtypes[IDCNT]; curp < endp; curp++) {
109 if (strcmp(curp->idtypnm, idtypnm) == 0) {
110 *idtypep = curp->idtype;
111 return (0);
112 }
113 }
114 return (-1);
115 }
116
117
118 int
idtyp2str(idtype,idtypnm)119 idtyp2str(idtype, idtypnm)
120 idtype_t idtype;
121 char *idtypnm;
122 {
123 register struct idtypes *curp;
124 register struct idtypes *endp;
125
126 for (curp = idtypes, endp = &idtypes[IDCNT]; curp < endp; curp++) {
127 if (idtype == curp->idtype) {
128 (void) strncpy(idtypnm, curp->idtypnm, PC_IDTYPNMSZ);
129 return (0);
130 }
131 }
132 return (-1);
133 }
134
135
136 /*
137 * Compare two IDs for equality.
138 */
139 int
idcompar(id1p,id2p)140 idcompar(id1p, id2p)
141 id_t *id1p;
142 id_t *id2p;
143 {
144 if (*id1p == *id2p)
145 return (0);
146 else
147 return (-1);
148 }
149
150
151 id_t
clname2cid(clname)152 clname2cid(clname)
153 char *clname;
154 {
155 pcinfo_t pcinfo;
156
157 (void) strncpy(pcinfo.pc_clname, clname, PC_CLNMSZ);
158 if (priocntl(0, 0, PC_GETCID, (caddr_t)&pcinfo) == -1)
159 return ((id_t)-1);
160 return (pcinfo.pc_cid);
161 }
162
163
164 int
getmyid(idtype,idptr)165 getmyid(idtype, idptr)
166 idtype_t idtype;
167 id_t *idptr;
168 {
169 pcinfo_t pcinfo;
170
171 switch (idtype) {
172
173 case P_PID:
174 *idptr = (id_t)getpid();
175 break;
176
177 case P_PPID:
178 *idptr = (id_t)getppid();
179 break;
180
181 case P_PGID:
182 *idptr = (id_t)getpgrp();
183 break;
184
185 case P_SID:
186 *idptr = (id_t)getsid(getpid());
187 break;
188
189 case P_CID:
190 if (priocntl(P_PID, P_MYID, PC_GETXPARMS, NULL,
191 PC_KY_CLNAME, pcinfo.pc_clname, 0) == -1 ||
192 priocntl(0, 0, PC_GETCID, (caddr_t)&pcinfo) == -1)
193 return (-1);
194
195 *idptr = pcinfo.pc_cid;
196 break;
197
198 case P_UID:
199 *idptr = (id_t)getuid();
200 break;
201
202 case P_GID:
203 *idptr = (id_t)getgid();
204 break;
205
206 case P_PROJID:
207 *idptr = (id_t)getprojid();
208 break;
209
210 case P_TASKID:
211 *idptr = (id_t)gettaskid();
212 break;
213
214 case P_ZONEID:
215 *idptr = (id_t)getzoneid();
216 break;
217
218 case P_CTID: {
219 ctid_t id = getctid();
220 if (id == -1)
221 return (-1);
222 *idptr = id;
223 break;
224 }
225
226 default:
227 return (-1);
228 }
229 return (0);
230 }
231
232
233 int
getmyidstr(idtype,idstr)234 getmyidstr(idtype, idstr)
235 idtype_t idtype;
236 char *idstr;
237 {
238 char clname[PC_CLNMSZ];
239
240 switch (idtype) {
241
242 case P_PID:
243 itoa((long)getpid(), idstr);
244 break;
245
246 case P_PPID:
247 itoa((long)getppid(), idstr);
248 break;
249
250 case P_PGID:
251 itoa((long)getpgrp(), idstr);
252 break;
253 case P_SID:
254 itoa((long)getsid(getpid()), idstr);
255 break;
256
257 case P_CID:
258 if (priocntl(P_PID, P_MYID, PC_GETXPARMS, NULL,
259 PC_KY_CLNAME, clname, 0) == -1)
260 return (-1);
261 (void) strncpy(idstr, clname, PC_CLNMSZ);
262 break;
263
264 case P_UID:
265 itoa((long)getuid(), idstr);
266 break;
267
268 case P_GID:
269 itoa((long)getgid(), idstr);
270 break;
271
272 case P_PROJID:
273 itoa((long)getprojid(), idstr);
274 break;
275
276 case P_TASKID:
277 itoa((long)gettaskid(), idstr);
278 break;
279
280 case P_ZONEID:
281 itoa((long)getzoneid(), idstr);
282 break;
283
284 case P_CTID: {
285 id_t id;
286 if ((id = getctid()) == -1)
287 return (-1);
288 itoa((long)id, idstr);
289 break;
290 }
291
292 default:
293 return (-1);
294 }
295 return (0);
296 }
297
298 /*
299 * Look for pids with "upri > uprilim" in the set specified by idtype/id.
300 * If upri exceeds uprilim then print a warning.
301 */
302 int
verifyupri(idtype_t idtype,id_t id,char * clname,int key,pri_t upri,char * basenm)303 verifyupri(idtype_t idtype, id_t id, char *clname, int key,
304 pri_t upri, char *basenm)
305 {
306 psinfo_t prinfo;
307 prcred_t prcred;
308 DIR *dirp;
309 struct dirent *dentp;
310 char pname[MAXNAMLEN];
311 char *fname;
312 int procfd;
313 int saverr;
314 pri_t uprilim;
315 int verify;
316 int error = 0;
317
318 if (idtype == P_PID) {
319 if (priocntl(P_PID, id, PC_GETXPARMS, clname, key,
320 &uprilim, 0) == -1)
321 error = -1;
322 else if (upri > uprilim)
323 (void) fprintf(stderr,
324 "%s: Specified user priority %d exceeds"
325 " limit %d; set to %d (pid %d)\n",
326 basenm, upri, uprilim, uprilim, (int)id);
327
328 return (error);
329 }
330
331 /*
332 * Look for the processes in the set specified by idtype/id.
333 * We read the /proc/<pid>/psinfo file to get the necessary
334 * process information.
335 */
336
337 if ((dirp = opendir(procdir)) == NULL)
338 fatalerr("%s: Can't open PROC directory %s\n",
339 basenm, procdir);
340
341 while ((dentp = readdir(dirp)) != NULL) {
342 if (dentp->d_name[0] == '.') /* skip . and .. */
343 continue;
344
345 (void) snprintf(pname, MAXNAMLEN, "%s/%s/",
346 procdir, dentp->d_name);
347 fname = pname + strlen(pname);
348 retry:
349 (void) strncpy(fname, "psinfo", strlen("psinfo") + 1);
350 if ((procfd = open(pname, O_RDONLY)) < 0)
351 continue;
352 if (read(procfd, &prinfo, sizeof (prinfo)) != sizeof (prinfo)) {
353 saverr = errno;
354 (void) close(procfd);
355 if (saverr == EAGAIN)
356 goto retry;
357 continue;
358 }
359 (void) close(procfd);
360
361 if (idtype == P_UID || idtype == P_GID) {
362 (void) strncpy(fname, "cred", strlen("cred") + 1);
363 if ((procfd = open(pname, O_RDONLY)) < 0 ||
364 read(procfd, &prcred, sizeof (prcred)) !=
365 sizeof (prcred)) {
366 saverr = errno;
367 (void) close(procfd);
368 if (saverr == EAGAIN)
369 goto retry;
370 continue;
371 }
372 (void) close(procfd);
373 }
374
375 if (prinfo.pr_lwp.pr_state == 0 || prinfo.pr_nlwp == 0)
376 continue;
377
378 /*
379 * The lwp must be in the correct class.
380 */
381 if (strncmp(clname, prinfo.pr_lwp.pr_clname, PC_CLNMSZ) != 0)
382 continue;
383
384 verify = 0;
385 switch (idtype) {
386
387 case P_PPID:
388 if (id == (id_t)prinfo.pr_ppid)
389 verify++;
390 break;
391
392 case P_PGID:
393 if (id == (id_t)prinfo.pr_pgid)
394 verify++;
395 break;
396
397 case P_SID:
398 if (id == (id_t)prinfo.pr_sid)
399 verify++;
400 break;
401
402 case P_UID:
403 if (id == (id_t)prcred.pr_euid)
404 verify++;
405 break;
406
407 case P_GID:
408 if (id == (id_t)prcred.pr_egid)
409 verify++;
410 break;
411
412 case P_PROJID:
413 if (id == (id_t)prinfo.pr_projid)
414 verify++;
415 break;
416
417 case P_TASKID:
418 if (id == (id_t)prinfo.pr_taskid)
419 verify++;
420 break;
421
422 case P_ZONEID:
423 if (id == (id_t)prinfo.pr_zoneid)
424 verify++;
425 break;
426
427 case P_CTID:
428 if (id == (id_t)prinfo.pr_contract)
429 verify++;
430 break;
431
432 case P_CID:
433 case P_ALL:
434 verify++;
435 break;
436
437 default:
438 fatalerr("%s: Bad idtype %d in verifyupri()\n",
439 basenm, idtype);
440 }
441
442 if (verify) {
443 if (priocntl(P_PID, prinfo.pr_pid, PC_GETXPARMS,
444 clname, key, &uprilim, 0) == -1)
445 error = -1;
446 else if (upri > uprilim)
447 (void) fprintf(stderr,
448 "%s: Specified user priority %d exceeds"
449 " limit %d; set to %d (pid %d)\n",
450 basenm, upri, uprilim, uprilim,
451 (int)prinfo.pr_pid);
452 }
453 }
454 (void) closedir(dirp);
455
456 return (error);
457 }
458
459
460 /*
461 * Read a list of pids from a stream.
462 */
463 pid_t *
read_pidlist(size_t * npidsp,FILE * filep)464 read_pidlist(size_t *npidsp, FILE *filep)
465 {
466 size_t nitems;
467 pid_t *pidlist = NULL;
468
469 *npidsp = 0;
470
471 do {
472 if ((pidlist = (pid_t *)realloc(pidlist,
473 (*npidsp + NPIDS) * sizeof (pid_t))) == NULL)
474 return (NULL);
475
476 nitems = fread(pidlist + *npidsp, sizeof (pid_t), NPIDS, filep);
477 if (ferror(filep))
478 return (NULL);
479
480 *npidsp += nitems;
481 } while (nitems == NPIDS);
482
483 return (pidlist);
484 }
485
486
487 void
free_pidlist(pid_t * pidlist)488 free_pidlist(pid_t *pidlist)
489 {
490 free(pidlist);
491 }
492
493
494 long
str2num(char * p,long min,long max)495 str2num(char *p, long min, long max)
496 {
497 long val;
498 char *q;
499 errno = 0;
500
501 val = strtol(p, &q, 10);
502 if (errno != 0 || q == p || *q != '\0' || val < min || val > max)
503 errno = EINVAL;
504
505 return (val);
506 }
507
508
509 /*
510 * itoa() and reverse() taken almost verbatim from K & R Chapter 3.
511 */
512 static void reverse();
513
514 /*
515 * itoa(): Convert n to characters in s.
516 */
517 void
itoa(n,s)518 itoa(n, s)
519 long n;
520 char *s;
521 {
522 long i, sign;
523
524 if ((sign = n) < 0) /* record sign */
525 n = -n; /* make sign positive */
526 i = 0;
527 do { /* generate digits in reverse order */
528 s[i++] = n % 10 + '0'; /* get next digit */
529 } while ((n /= 10) > 0); /* delete it */
530 if (sign < 0)
531 s[i++] = '-';
532 s[i] = '\0';
533 reverse(s);
534 }
535
536
537 /*
538 * reverse(): Reverse string s in place.
539 */
540 static void
reverse(s)541 reverse(s)
542 char *s;
543 {
544 int c, i, j;
545
546 for (i = 0, j = strlen(s) - 1; i < j; i++, j--) {
547 c = s[i];
548 s[i] = s[j];
549 s[j] = (char)c;
550 }
551 }
552
553
554 /*
555 * The following routine was removed from libc (libc/port/gen/hrtnewres.c).
556 * It has also been added to disadmin, so if you fix it here, you should
557 * also probably fix it there. In the long term, this should be recoded to
558 * not be hrt'ish.
559 */
560
561 /*
562 * Convert interval expressed in htp->hrt_res to new_res.
563 *
564 * Calculate: (interval * new_res) / htp->hrt_res rounding off as
565 * specified by round.
566 *
567 * Note: All args are assumed to be positive. If
568 * the last divide results in something bigger than
569 * a long, then -1 is returned instead.
570 */
571
572 int
_hrtnewres(htp,new_res,round)573 _hrtnewres(htp, new_res, round)
574 register hrtimer_t *htp;
575 register ulong_t new_res;
576 long round;
577 {
578 register long interval;
579 longlong_t dint;
580 longlong_t dto_res;
581 longlong_t drem;
582 longlong_t dfrom_res;
583 longlong_t prod;
584 longlong_t quot;
585 register long numerator;
586 register long result;
587 ulong_t modulus;
588 ulong_t twomodulus;
589 long temp;
590
591 if (new_res > NANOSEC || htp->hrt_rem < 0)
592 return (-1);
593
594 if (htp->hrt_rem >= htp->hrt_res) {
595 htp->hrt_secs += htp->hrt_rem / htp->hrt_res;
596 htp->hrt_rem = htp->hrt_rem % htp->hrt_res;
597 }
598
599 interval = htp->hrt_rem;
600 if (interval == 0) {
601 htp->hrt_res = new_res;
602 return (0);
603 }
604
605 /*
606 * Try to do the calculations in single precision first
607 * (for speed). If they overflow, use double precision.
608 * What we want to compute is:
609 *
610 * (interval * new_res) / hrt->hrt_res
611 */
612
613 numerator = interval * new_res;
614
615 if (numerator / new_res == interval) {
616
617 /*
618 * The above multiply didn't give overflow since
619 * the division got back the original number. Go
620 * ahead and compute the result.
621 */
622
623 result = numerator / htp->hrt_res;
624
625 /*
626 * For HRT_RND, compute the value of:
627 *
628 * (interval * new_res) % htp->hrt_res
629 *
630 * If it is greater than half of the htp->hrt_res,
631 * then rounding increases the result by 1.
632 *
633 * For HRT_RNDUP, we increase the result by 1 if:
634 *
635 * result * htp->hrt_res != numerator
636 *
637 * because this tells us we truncated when calculating
638 * result above.
639 *
640 * We also check for overflow when incrementing result
641 * although this is extremely rare.
642 */
643
644 if (round == HRT_RND) {
645 modulus = numerator - result * htp->hrt_res;
646 if ((twomodulus = 2 * modulus) / 2 == modulus) {
647
648 /*
649 * No overflow (if we overflow in calculation
650 * of twomodulus we fall through and use
651 * double precision).
652 */
653 if (twomodulus >= htp->hrt_res) {
654 temp = result + 1;
655 if (temp - 1 == result)
656 result++;
657 else
658 return (-1);
659 }
660 htp->hrt_res = new_res;
661 htp->hrt_rem = result;
662 return (0);
663 }
664 } else if (round == HRT_RNDUP) {
665 if (result * htp->hrt_res != numerator) {
666 temp = result + 1;
667 if (temp - 1 == result)
668 result++;
669 else
670 return (-1);
671 }
672 htp->hrt_res = new_res;
673 htp->hrt_rem = result;
674 return (0);
675 } else { /* round == HRT_TRUNC */
676 htp->hrt_res = new_res;
677 htp->hrt_rem = result;
678 return (0);
679 }
680 }
681
682 /*
683 * We would get overflow doing the calculation is
684 * single precision so do it the slow but careful way.
685 *
686 * Compute the interval times the resolution we are
687 * going to.
688 */
689
690 dint = interval;
691 dto_res = new_res;
692 prod = dint * dto_res;
693
694 /*
695 * For HRT_RND the result will be equal to:
696 *
697 * ((interval * new_res) + htp->hrt_res / 2) / htp->hrt_res
698 *
699 * and for HRT_RNDUP we use:
700 *
701 * ((interval * new_res) + htp->hrt_res - 1) / htp->hrt_res
702 *
703 * This is a different but equivalent way of rounding.
704 */
705
706 if (round == HRT_RND) {
707 drem = htp->hrt_res / 2;
708 prod = prod + drem;
709 } else if (round == HRT_RNDUP) {
710 drem = htp->hrt_res - 1;
711 prod = prod + drem;
712 }
713
714 dfrom_res = htp->hrt_res;
715 quot = prod / dfrom_res;
716
717 /*
718 * If the quotient won't fit in a long, then we have
719 * overflow. Otherwise, return the result.
720 */
721
722 if (quot > UINT_MAX) {
723 return (-1);
724 } else {
725 htp->hrt_res = new_res;
726 htp->hrt_rem = (int)quot;
727 return (0);
728 }
729 }
730