9804 hal-set-property should support --direct option
[unleashed.git] / usr / src / cmd / priocntl / subr.c
blobfa03ad921fdc83488c8d17498c22eaa5f7d3b9c1
1 /*
2 * CDDL HEADER START
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.
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.
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]
20 * CDDL HEADER END
23 * Copyright 2004 Sun Microsystems, Inc. All rights reserved.
24 * Use is subject to license terms.
27 /* Copyright (c) 1984, 1986, 1987, 1988, 1989 AT&T */
28 /* All Rights Reserved */
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>
50 #include "priocntl.h"
52 /*LINTLIBRARY*/
55 * Utility functions for priocntl command.
58 static char *procdir = "/proc";
60 /*PRINTFLIKE1*/
61 void
62 fatalerr(format, a1, a2, a3, a4, a5)
63 char *format;
64 int a1, a2, a3, a4, a5;
66 (void) fprintf(stderr, format, a1, a2, a3, a4, a5);
67 exit(1);
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>.
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" }
94 #define IDCNT (sizeof (idtypes) / sizeof (struct idtypes))
97 int
98 str2idtyp(idtypnm, idtypep)
99 char *idtypnm;
100 idtype_t *idtypep;
102 register struct idtypes *curp;
103 register struct idtypes *endp;
105 for (curp = idtypes, endp = &idtypes[IDCNT]; curp < endp; curp++) {
106 if (strcmp(curp->idtypnm, idtypnm) == 0) {
107 *idtypep = curp->idtype;
108 return (0);
111 return (-1);
116 idtyp2str(idtype, idtypnm)
117 idtype_t idtype;
118 char *idtypnm;
120 register struct idtypes *curp;
121 register struct idtypes *endp;
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);
129 return (-1);
134 * Compare two IDs for equality.
137 idcompar(id1p, id2p)
138 id_t *id1p;
139 id_t *id2p;
141 if (*id1p == *id2p)
142 return (0);
143 else
144 return (-1);
148 id_t
149 clname2cid(clname)
150 char *clname;
152 pcinfo_t pcinfo;
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);
162 getmyid(idtype, idptr)
163 idtype_t idtype;
164 id_t *idptr;
166 pcinfo_t pcinfo;
168 switch (idtype) {
170 case P_PID:
171 *idptr = (id_t)getpid();
172 break;
174 case P_PPID:
175 *idptr = (id_t)getppid();
176 break;
178 case P_PGID:
179 *idptr = (id_t)getpgrp();
180 break;
182 case P_SID:
183 *idptr = (id_t)getsid(getpid());
184 break;
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);
192 *idptr = pcinfo.pc_cid;
193 break;
195 case P_UID:
196 *idptr = (id_t)getuid();
197 break;
199 case P_GID:
200 *idptr = (id_t)getgid();
201 break;
203 case P_PROJID:
204 *idptr = (id_t)getprojid();
205 break;
207 case P_TASKID:
208 *idptr = (id_t)gettaskid();
209 break;
211 case P_ZONEID:
212 *idptr = (id_t)getzoneid();
213 break;
215 case P_CTID: {
216 ctid_t id = getctid();
217 if (id == -1)
218 return (-1);
219 *idptr = id;
220 break;
223 default:
224 return (-1);
226 return (0);
231 getmyidstr(idtype, idstr)
232 idtype_t idtype;
233 char *idstr;
235 char clname[PC_CLNMSZ];
237 switch (idtype) {
239 case P_PID:
240 itoa((long)getpid(), idstr);
241 break;
243 case P_PPID:
244 itoa((long)getppid(), idstr);
245 break;
247 case P_PGID:
248 itoa((long)getpgrp(), idstr);
249 break;
250 case P_SID:
251 itoa((long)getsid(getpid()), idstr);
252 break;
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;
261 case P_UID:
262 itoa((long)getuid(), idstr);
263 break;
265 case P_GID:
266 itoa((long)getgid(), idstr);
267 break;
269 case P_PROJID:
270 itoa((long)getprojid(), idstr);
271 break;
273 case P_TASKID:
274 itoa((long)gettaskid(), idstr);
275 break;
277 case P_ZONEID:
278 itoa((long)getzoneid(), idstr);
279 break;
281 case P_CTID: {
282 id_t id;
283 if ((id = getctid()) == -1)
284 return (-1);
285 itoa((long)id, idstr);
286 break;
289 default:
290 return (-1);
292 return (0);
296 * Look for pids with "upri > uprilim" in the set specified by idtype/id.
297 * If upri exceeds uprilim then print a warning.
300 verifyupri(idtype_t idtype, id_t id, char *clname, int key,
301 pri_t upri, char *basenm)
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;
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);
325 return (error);
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.
334 if ((dirp = opendir(procdir)) == NULL)
335 fatalerr("%s: Can't open PROC directory %s\n",
336 basenm, procdir);
338 while ((dentp = readdir(dirp)) != NULL) {
339 if (dentp->d_name[0] == '.') /* skip . and .. */
340 continue;
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;
356 (void) close(procfd);
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;
369 (void) close(procfd);
372 if (prinfo.pr_lwp.pr_state == 0 || prinfo.pr_nlwp == 0)
373 continue;
376 * The lwp must be in the correct class.
378 if (strncmp(clname, prinfo.pr_lwp.pr_clname, PC_CLNMSZ) != 0)
379 continue;
381 verify = 0;
382 switch (idtype) {
384 case P_PPID:
385 if (id == (id_t)prinfo.pr_ppid)
386 verify++;
387 break;
389 case P_PGID:
390 if (id == (id_t)prinfo.pr_pgid)
391 verify++;
392 break;
394 case P_SID:
395 if (id == (id_t)prinfo.pr_sid)
396 verify++;
397 break;
399 case P_UID:
400 if (id == (id_t)prcred.pr_euid)
401 verify++;
402 break;
404 case P_GID:
405 if (id == (id_t)prcred.pr_egid)
406 verify++;
407 break;
409 case P_PROJID:
410 if (id == (id_t)prinfo.pr_projid)
411 verify++;
412 break;
414 case P_TASKID:
415 if (id == (id_t)prinfo.pr_taskid)
416 verify++;
417 break;
419 case P_ZONEID:
420 if (id == (id_t)prinfo.pr_zoneid)
421 verify++;
422 break;
424 case P_CTID:
425 if (id == (id_t)prinfo.pr_contract)
426 verify++;
427 break;
429 case P_CID:
430 case P_ALL:
431 verify++;
432 break;
434 default:
435 fatalerr("%s: Bad idtype %d in verifyupri()\n",
436 basenm, idtype);
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);
451 (void) closedir(dirp);
453 return (error);
458 * Read a list of pids from a stream.
460 pid_t *
461 read_pidlist(size_t *npidsp, FILE *filep)
463 size_t nitems;
464 pid_t *pidlist = NULL;
466 *npidsp = 0;
468 do {
469 if ((pidlist = (pid_t *)realloc(pidlist,
470 (*npidsp + NPIDS) * sizeof (pid_t))) == NULL)
471 return (NULL);
473 nitems = fread(pidlist + *npidsp, sizeof (pid_t), NPIDS, filep);
474 if (ferror(filep))
475 return (NULL);
477 *npidsp += nitems;
478 } while (nitems == NPIDS);
480 return (pidlist);
484 void
485 free_pidlist(pid_t *pidlist)
487 free(pidlist);
491 long
492 str2num(char *p, long min, long max)
494 long val;
495 char *q;
496 errno = 0;
498 val = strtol(p, &q, 10);
499 if (errno != 0 || q == p || *q != '\0' || val < min || val > max)
500 errno = EINVAL;
502 return (val);
507 * itoa() and reverse() taken almost verbatim from K & R Chapter 3.
509 static void reverse();
512 * itoa(): Convert n to characters in s.
514 void
515 itoa(n, s)
516 long n;
517 char *s;
519 long i, sign;
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);
535 * reverse(): Reverse string s in place.
537 static void
538 reverse(s)
539 char *s;
541 int c, i, j;
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;
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.
559 * Convert interval expressed in htp->hrt_res to new_res.
561 * Calculate: (interval * new_res) / htp->hrt_res rounding off as
562 * specified by round.
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.
570 _hrtnewres(htp, new_res, round)
571 register hrtimer_t *htp;
572 register ulong_t new_res;
573 long round;
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;
588 if (new_res > NANOSEC || htp->hrt_rem < 0)
589 return (-1);
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;
596 interval = htp->hrt_rem;
597 if (interval == 0) {
598 htp->hrt_res = new_res;
599 return (0);
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:
607 * (interval * new_res) / hrt->hrt_res
610 numerator = interval * new_res;
612 if (numerator / new_res == interval) {
615 * The above multiply didn't give overflow since
616 * the division got back the original number. Go
617 * ahead and compute the result.
620 result = numerator / htp->hrt_res;
623 * For HRT_RND, compute the value of:
625 * (interval * new_res) % htp->hrt_res
627 * If it is greater than half of the htp->hrt_res,
628 * then rounding increases the result by 1.
630 * For HRT_RNDUP, we increase the result by 1 if:
632 * result * htp->hrt_res != numerator
634 * because this tells us we truncated when calculating
635 * result above.
637 * We also check for overflow when incrementing result
638 * although this is extremely rare.
641 if (round == HRT_RND) {
642 modulus = numerator - result * htp->hrt_res;
643 if ((twomodulus = 2 * modulus) / 2 == modulus) {
646 * No overflow (if we overflow in calculation
647 * of twomodulus we fall through and use
648 * double precision).
650 if (twomodulus >= htp->hrt_res) {
651 temp = result + 1;
652 if (temp - 1 == result)
653 result++;
654 else
655 return (-1);
657 htp->hrt_res = new_res;
658 htp->hrt_rem = result;
659 return (0);
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);
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);
680 * We would get overflow doing the calculation is
681 * single precision so do it the slow but careful way.
683 * Compute the interval times the resolution we are
684 * going to.
687 dint = interval;
688 dto_res = new_res;
689 prod = dint * dto_res;
692 * For HRT_RND the result will be equal to:
694 * ((interval * new_res) + htp->hrt_res / 2) / htp->hrt_res
696 * and for HRT_RNDUP we use:
698 * ((interval * new_res) + htp->hrt_res - 1) / htp->hrt_res
700 * This is a different but equivalent way of rounding.
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;
711 dfrom_res = htp->hrt_res;
712 quot = prod / dfrom_res;
715 * If the quotient won't fit in a long, then we have
716 * overflow. Otherwise, return the result.
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);