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
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]
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 */
36 #include <sys/types.h>
41 #include <sys/procset.h>
42 #include <sys/priocntl.h>
48 #include <libcontract_priv.h>
55 * Utility functions for priocntl command.
58 static char *procdir
= "/proc";
62 fatalerr(format
, a1
, a2
, a3
, a4
, a5
)
64 int a1
, a2
, a3
, a4
, a5
;
66 (void) fprintf(stderr
, format
, a1
, a2
, a3
, a4
, a5
);
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
{
87 { P_PROJID
, "projid" },
88 { P_TASKID
, "taskid" },
89 { P_ZONEID
, "zoneid" },
94 #define IDCNT (sizeof (idtypes) / sizeof (struct idtypes))
98 str2idtyp(idtypnm
, 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
;
116 idtyp2str(idtype
, 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
);
134 * Compare two IDs for equality.
154 (void) strncpy(pcinfo
.pc_clname
, clname
, PC_CLNMSZ
);
155 if (priocntl(0, 0, PC_GETCID
, (caddr_t
)&pcinfo
) == -1)
157 return (pcinfo
.pc_cid
);
162 getmyid(idtype
, idptr
)
171 *idptr
= (id_t
)getpid();
175 *idptr
= (id_t
)getppid();
179 *idptr
= (id_t
)getpgrp();
183 *idptr
= (id_t
)getsid(getpid());
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)
192 *idptr
= pcinfo
.pc_cid
;
196 *idptr
= (id_t
)getuid();
200 *idptr
= (id_t
)getgid();
204 *idptr
= (id_t
)getprojid();
208 *idptr
= (id_t
)gettaskid();
212 *idptr
= (id_t
)getzoneid();
216 ctid_t id
= getctid();
231 getmyidstr(idtype
, idstr
)
235 char clname
[PC_CLNMSZ
];
240 itoa((long)getpid(), idstr
);
244 itoa((long)getppid(), idstr
);
248 itoa((long)getpgrp(), idstr
);
251 itoa((long)getsid(getpid()), idstr
);
255 if (priocntl(P_PID
, P_MYID
, PC_GETXPARMS
, NULL
,
256 PC_KY_CLNAME
, clname
, 0) == -1)
258 (void) strncpy(idstr
, clname
, PC_CLNMSZ
);
262 itoa((long)getuid(), idstr
);
266 itoa((long)getgid(), idstr
);
270 itoa((long)getprojid(), idstr
);
274 itoa((long)gettaskid(), idstr
);
278 itoa((long)getzoneid(), idstr
);
283 if ((id
= getctid()) == -1)
285 itoa((long)id
, idstr
);
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
)
306 struct dirent
*dentp
;
307 char pname
[MAXNAMLEN
];
315 if (idtype
== P_PID
) {
316 if (priocntl(P_PID
, id
, PC_GETXPARMS
, clname
, key
,
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
);
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",
338 while ((dentp
= readdir(dirp
)) != NULL
) {
339 if (dentp
->d_name
[0] == '.') /* skip . and .. */
342 (void) snprintf(pname
, MAXNAMLEN
, "%s/%s/",
343 procdir
, dentp
->d_name
);
344 fname
= pname
+ strlen(pname
);
346 (void) strncpy(fname
, "psinfo", strlen("psinfo") + 1);
347 if ((procfd
= open(pname
, O_RDONLY
)) < 0)
349 if (read(procfd
, &prinfo
, sizeof (prinfo
)) != sizeof (prinfo
)) {
351 (void) close(procfd
);
352 if (saverr
== EAGAIN
)
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
)) !=
364 (void) close(procfd
);
365 if (saverr
== EAGAIN
)
369 (void) close(procfd
);
372 if (prinfo
.pr_lwp
.pr_state
== 0 || prinfo
.pr_nlwp
== 0)
376 * The lwp must be in the correct class.
378 if (strncmp(clname
, prinfo
.pr_lwp
.pr_clname
, PC_CLNMSZ
) != 0)
385 if (id
== (id_t
)prinfo
.pr_ppid
)
390 if (id
== (id_t
)prinfo
.pr_pgid
)
395 if (id
== (id_t
)prinfo
.pr_sid
)
400 if (id
== (id_t
)prcred
.pr_euid
)
405 if (id
== (id_t
)prcred
.pr_egid
)
410 if (id
== (id_t
)prinfo
.pr_projid
)
415 if (id
== (id_t
)prinfo
.pr_taskid
)
420 if (id
== (id_t
)prinfo
.pr_zoneid
)
425 if (id
== (id_t
)prinfo
.pr_contract
)
435 fatalerr("%s: Bad idtype %d in verifyupri()\n",
440 if (priocntl(P_PID
, prinfo
.pr_pid
, PC_GETXPARMS
,
441 clname
, key
, &uprilim
, 0) == -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
,
451 (void) closedir(dirp
);
458 * Read a list of pids from a stream.
461 read_pidlist(size_t *npidsp
, FILE *filep
)
464 pid_t
*pidlist
= NULL
;
469 if ((pidlist
= reallocarray(pidlist
, *npidsp
+ NPIDS
,
470 sizeof (pid_t
))) == NULL
)
473 nitems
= fread(pidlist
+ *npidsp
, sizeof (pid_t
), NPIDS
, filep
);
478 } while (nitems
== NPIDS
);
485 free_pidlist(pid_t
*pidlist
)
492 str2num(char *p
, long min
, long max
)
498 val
= strtol(p
, &q
, 10);
499 if (errno
!= 0 || q
== p
|| *q
!= '\0' || val
< min
|| val
> max
)
507 * itoa() and reverse() taken almost verbatim from K & R Chapter 3.
509 static void reverse();
512 * itoa(): Convert n to characters in s.
521 if ((sign
= n
) < 0) /* record sign */
522 n
= -n
; /* make sign positive */
524 do { /* generate digits in reverse order */
525 s
[i
++] = n
% 10 + '0'; /* get next digit */
526 } while ((n
/= 10) > 0); /* delete it */
535 * reverse(): Reverse string s in place.
543 for (i
= 0, j
= strlen(s
) - 1; i
< j
; i
++, j
--) {
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
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
;
575 register long interval
;
579 longlong_t dfrom_res
;
582 register long numerator
;
583 register long result
;
588 if (new_res
> NANOSEC
|| htp
->hrt_rem
< 0)
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
;
598 htp
->hrt_res
= new_res
;
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
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
650 if (twomodulus
>= htp
->hrt_res
) {
652 if (temp
- 1 == result
)
657 htp
->hrt_res
= new_res
;
658 htp
->hrt_rem
= result
;
661 } else if (round
== HRT_RNDUP
) {
662 if (result
* htp
->hrt_res
!= numerator
) {
664 if (temp
- 1 == result
)
669 htp
->hrt_res
= new_res
;
670 htp
->hrt_rem
= result
;
672 } else { /* round == HRT_TRUNC */
673 htp
->hrt_res
= new_res
;
674 htp
->hrt_rem
= result
;
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
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;
706 } else if (round
== HRT_RNDUP
) {
707 drem
= htp
->hrt_res
- 1;
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
) {
722 htp
->hrt_res
= new_res
;
723 htp
->hrt_rem
= (int)quot
;