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