/* * CDDL HEADER START * * The contents of this file are subject to the terms of the * Common Development and Distribution License, Version 1.0 only * (the "License"). You may not use this file except in compliance * with the License. * * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE * or http://www.opensolaris.org/os/licensing. * See the License for the specific language governing permissions * and limitations under the License. * * When distributing Covered Code, include this CDDL HEADER in each * file and include the License file at usr/src/OPENSOLARIS.LICENSE. * If applicable, add the following below this CDDL HEADER, with the * fields enclosed by brackets "[]" replaced with your own identifying * information: Portions Copyright [yyyy] [name of copyright owner] * * CDDL HEADER END */ /* * Copyright 2004 Sun Microsystems, Inc. All rights reserved. * Use is subject to license terms. */ #pragma ident "%Z%%M% %I% %E% SMI" /* Copyright (c) 1984, 1986, 1987, 1988, 1989 AT&T */ /* All Rights Reserved */ #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include "priocntl.h" /*LINTLIBRARY*/ /* * Utility functions for priocntl command. */ static char *procdir = "/proc"; /*PRINTFLIKE1*/ void fatalerr(format, a1, a2, a3, a4, a5) char *format; int a1, a2, a3, a4, a5; { (void) fprintf(stderr, format, a1, a2, a3, a4, a5); exit(1); } /* * Structure defining idtypes known to the priocntl command * along with the corresponding names and a liberal guess * of the max number of procs sharing any given ID of that type. * The idtype values themselves are defined in . */ static struct idtypes { idtype_t idtype; char *idtypnm; } idtypes [] = { { P_PID, "pid" }, { P_PPID, "ppid" }, { P_PGID, "pgid" }, { P_SID, "sid" }, { P_CID, "class" }, { P_UID, "uid" }, { P_GID, "gid" }, { P_PROJID, "projid" }, { P_TASKID, "taskid" }, { P_ZONEID, "zoneid" }, { P_CTID, "ctid" }, { P_ALL, "all" } }; #define IDCNT (sizeof (idtypes) / sizeof (struct idtypes)) int str2idtyp(idtypnm, idtypep) char *idtypnm; idtype_t *idtypep; { register struct idtypes *curp; register struct idtypes *endp; for (curp = idtypes, endp = &idtypes[IDCNT]; curp < endp; curp++) { if (strcmp(curp->idtypnm, idtypnm) == 0) { *idtypep = curp->idtype; return (0); } } return (-1); } int idtyp2str(idtype, idtypnm) idtype_t idtype; char *idtypnm; { register struct idtypes *curp; register struct idtypes *endp; for (curp = idtypes, endp = &idtypes[IDCNT]; curp < endp; curp++) { if (idtype == curp->idtype) { (void) strncpy(idtypnm, curp->idtypnm, PC_IDTYPNMSZ); return (0); } } return (-1); } /* * Compare two IDs for equality. */ int idcompar(id1p, id2p) id_t *id1p; id_t *id2p; { if (*id1p == *id2p) return (0); else return (-1); } id_t clname2cid(clname) char *clname; { pcinfo_t pcinfo; (void) strncpy(pcinfo.pc_clname, clname, PC_CLNMSZ); if (priocntl(0, 0, PC_GETCID, (caddr_t)&pcinfo) == -1) return ((id_t)-1); return (pcinfo.pc_cid); } int getmyid(idtype, idptr) idtype_t idtype; id_t *idptr; { pcinfo_t pcinfo; switch (idtype) { case P_PID: *idptr = (id_t)getpid(); break; case P_PPID: *idptr = (id_t)getppid(); break; case P_PGID: *idptr = (id_t)getpgrp(); break; case P_SID: *idptr = (id_t)getsid(getpid()); break; case P_CID: if (priocntl(P_PID, P_MYID, PC_GETXPARMS, NULL, PC_KY_CLNAME, pcinfo.pc_clname, 0) == -1 || priocntl(0, 0, PC_GETCID, (caddr_t)&pcinfo) == -1) return (-1); *idptr = pcinfo.pc_cid; break; case P_UID: *idptr = (id_t)getuid(); break; case P_GID: *idptr = (id_t)getgid(); break; case P_PROJID: *idptr = (id_t)getprojid(); break; case P_TASKID: *idptr = (id_t)gettaskid(); break; case P_ZONEID: *idptr = (id_t)getzoneid(); break; case P_CTID: { ctid_t id = getctid(); if (id == -1) return (-1); *idptr = id; break; } default: return (-1); } return (0); } int getmyidstr(idtype, idstr) idtype_t idtype; char *idstr; { char clname[PC_CLNMSZ]; switch (idtype) { case P_PID: itoa((long)getpid(), idstr); break; case P_PPID: itoa((long)getppid(), idstr); break; case P_PGID: itoa((long)getpgrp(), idstr); break; case P_SID: itoa((long)getsid(getpid()), idstr); break; case P_CID: if (priocntl(P_PID, P_MYID, PC_GETXPARMS, NULL, PC_KY_CLNAME, clname, 0) == -1) return (-1); (void) strncpy(idstr, clname, PC_CLNMSZ); break; case P_UID: itoa((long)getuid(), idstr); break; case P_GID: itoa((long)getgid(), idstr); break; case P_PROJID: itoa((long)getprojid(), idstr); break; case P_TASKID: itoa((long)gettaskid(), idstr); break; case P_ZONEID: itoa((long)getzoneid(), idstr); break; case P_CTID: { id_t id; if ((id = getctid()) == -1) return (-1); itoa((long)id, idstr); break; } default: return (-1); } return (0); } /* * Look for pids with "upri > uprilim" in the set specified by idtype/id. * If upri exceeds uprilim then print a warning. */ int verifyupri(idtype_t idtype, id_t id, char *clname, int key, pri_t upri, char *basenm) { psinfo_t prinfo; prcred_t prcred; DIR *dirp; struct dirent *dentp; char pname[MAXNAMLEN]; char *fname; int procfd; int saverr; pri_t uprilim; int verify; int error = 0; if (idtype == P_PID) { if (priocntl(P_PID, id, PC_GETXPARMS, clname, key, &uprilim, 0) == -1) error = -1; else if (upri > uprilim) (void) fprintf(stderr, "%s: Specified user priority %d exceeds" " limit %d; set to %d (pid %d)\n", basenm, upri, uprilim, uprilim, (int)id); return (error); } /* * Look for the processes in the set specified by idtype/id. * We read the /proc//psinfo file to get the necessary * process information. */ if ((dirp = opendir(procdir)) == NULL) fatalerr("%s: Can't open PROC directory %s\n", basenm, procdir); while ((dentp = readdir(dirp)) != NULL) { if (dentp->d_name[0] == '.') /* skip . and .. */ continue; (void) snprintf(pname, MAXNAMLEN, "%s/%s/", procdir, dentp->d_name); fname = pname + strlen(pname); retry: (void) strncpy(fname, "psinfo", strlen("psinfo") + 1); if ((procfd = open(pname, O_RDONLY)) < 0) continue; if (read(procfd, &prinfo, sizeof (prinfo)) != sizeof (prinfo)) { saverr = errno; (void) close(procfd); if (saverr == EAGAIN) goto retry; continue; } (void) close(procfd); if (idtype == P_UID || idtype == P_GID) { (void) strncpy(fname, "cred", strlen("cred") + 1); if ((procfd = open(pname, O_RDONLY)) < 0 || read(procfd, &prcred, sizeof (prcred)) != sizeof (prcred)) { saverr = errno; (void) close(procfd); if (saverr == EAGAIN) goto retry; continue; } (void) close(procfd); } if (prinfo.pr_lwp.pr_state == 0 || prinfo.pr_nlwp == 0) continue; /* * The lwp must be in the correct class. */ if (strncmp(clname, prinfo.pr_lwp.pr_clname, PC_CLNMSZ) != 0) continue; verify = 0; switch (idtype) { case P_PPID: if (id == (id_t)prinfo.pr_ppid) verify++; break; case P_PGID: if (id == (id_t)prinfo.pr_pgid) verify++; break; case P_SID: if (id == (id_t)prinfo.pr_sid) verify++; break; case P_UID: if (id == (id_t)prcred.pr_euid) verify++; break; case P_GID: if (id == (id_t)prcred.pr_egid) verify++; break; case P_PROJID: if (id == (id_t)prinfo.pr_projid) verify++; break; case P_TASKID: if (id == (id_t)prinfo.pr_taskid) verify++; break; case P_ZONEID: if (id == (id_t)prinfo.pr_zoneid) verify++; break; case P_CTID: if (id == (id_t)prinfo.pr_contract) verify++; break; case P_CID: case P_ALL: verify++; break; default: fatalerr("%s: Bad idtype %d in verifyupri()\n", basenm, idtype); } if (verify) { if (priocntl(P_PID, prinfo.pr_pid, PC_GETXPARMS, clname, key, &uprilim, 0) == -1) error = -1; else if (upri > uprilim) (void) fprintf(stderr, "%s: Specified user priority %d exceeds" " limit %d; set to %d (pid %d)\n", basenm, upri, uprilim, uprilim, (int)prinfo.pr_pid); } } (void) closedir(dirp); return (error); } /* * Read a list of pids from a stream. */ pid_t * read_pidlist(size_t *npidsp, FILE *filep) { size_t nitems; pid_t *pidlist = NULL; *npidsp = 0; do { if ((pidlist = (pid_t *)realloc(pidlist, (*npidsp + NPIDS) * sizeof (pid_t))) == NULL) return (NULL); nitems = fread(pidlist + *npidsp, sizeof (pid_t), NPIDS, filep); if (ferror(filep)) return (NULL); *npidsp += nitems; } while (nitems == NPIDS); return (pidlist); } void free_pidlist(pid_t *pidlist) { free(pidlist); } long str2num(char *p, long min, long max) { long val; char *q; errno = 0; val = strtol(p, &q, 10); if (errno != 0 || q == p || *q != '\0' || val < min || val > max) errno = EINVAL; return (val); } /* * itoa() and reverse() taken almost verbatim from K & R Chapter 3. */ static void reverse(); /* * itoa(): Convert n to characters in s. */ void itoa(n, s) long n; char *s; { long i, sign; if ((sign = n) < 0) /* record sign */ n = -n; /* make sign positive */ i = 0; do { /* generate digits in reverse order */ s[i++] = n % 10 + '0'; /* get next digit */ } while ((n /= 10) > 0); /* delete it */ if (sign < 0) s[i++] = '-'; s[i] = '\0'; reverse(s); } /* * reverse(): Reverse string s in place. */ static void reverse(s) char *s; { int c, i, j; for (i = 0, j = strlen(s) - 1; i < j; i++, j--) { c = s[i]; s[i] = s[j]; s[j] = (char)c; } } /* * The following routine was removed from libc (libc/port/gen/hrtnewres.c). * It has also been added to disadmin, so if you fix it here, you should * also probably fix it there. In the long term, this should be recoded to * not be hrt'ish. */ /* * Convert interval expressed in htp->hrt_res to new_res. * * Calculate: (interval * new_res) / htp->hrt_res rounding off as * specified by round. * * Note: All args are assumed to be positive. If * the last divide results in something bigger than * a long, then -1 is returned instead. */ int _hrtnewres(htp, new_res, round) register hrtimer_t *htp; register ulong_t new_res; long round; { register long interval; longlong_t dint; longlong_t dto_res; longlong_t drem; longlong_t dfrom_res; longlong_t prod; longlong_t quot; register long numerator; register long result; ulong_t modulus; ulong_t twomodulus; long temp; if (new_res > NANOSEC || htp->hrt_rem < 0) return (-1); if (htp->hrt_rem >= htp->hrt_res) { htp->hrt_secs += htp->hrt_rem / htp->hrt_res; htp->hrt_rem = htp->hrt_rem % htp->hrt_res; } interval = htp->hrt_rem; if (interval == 0) { htp->hrt_res = new_res; return (0); } /* * Try to do the calculations in single precision first * (for speed). If they overflow, use double precision. * What we want to compute is: * * (interval * new_res) / hrt->hrt_res */ numerator = interval * new_res; if (numerator / new_res == interval) { /* * The above multiply didn't give overflow since * the division got back the original number. Go * ahead and compute the result. */ result = numerator / htp->hrt_res; /* * For HRT_RND, compute the value of: * * (interval * new_res) % htp->hrt_res * * If it is greater than half of the htp->hrt_res, * then rounding increases the result by 1. * * For HRT_RNDUP, we increase the result by 1 if: * * result * htp->hrt_res != numerator * * because this tells us we truncated when calculating * result above. * * We also check for overflow when incrementing result * although this is extremely rare. */ if (round == HRT_RND) { modulus = numerator - result * htp->hrt_res; if ((twomodulus = 2 * modulus) / 2 == modulus) { /* * No overflow (if we overflow in calculation * of twomodulus we fall through and use * double precision). */ if (twomodulus >= htp->hrt_res) { temp = result + 1; if (temp - 1 == result) result++; else return (-1); } htp->hrt_res = new_res; htp->hrt_rem = result; return (0); } } else if (round == HRT_RNDUP) { if (result * htp->hrt_res != numerator) { temp = result + 1; if (temp - 1 == result) result++; else return (-1); } htp->hrt_res = new_res; htp->hrt_rem = result; return (0); } else { /* round == HRT_TRUNC */ htp->hrt_res = new_res; htp->hrt_rem = result; return (0); } } /* * We would get overflow doing the calculation is * single precision so do it the slow but careful way. * * Compute the interval times the resolution we are * going to. */ dint = interval; dto_res = new_res; prod = dint * dto_res; /* * For HRT_RND the result will be equal to: * * ((interval * new_res) + htp->hrt_res / 2) / htp->hrt_res * * and for HRT_RNDUP we use: * * ((interval * new_res) + htp->hrt_res - 1) / htp->hrt_res * * This is a different but equivalent way of rounding. */ if (round == HRT_RND) { drem = htp->hrt_res / 2; prod = prod + drem; } else if (round == HRT_RNDUP) { drem = htp->hrt_res - 1; prod = prod + drem; } dfrom_res = htp->hrt_res; quot = prod / dfrom_res; /* * If the quotient won't fit in a long, then we have * overflow. Otherwise, return the result. */ if (quot > UINT_MAX) { return (-1); } else { htp->hrt_res = new_res; htp->hrt_rem = (int)quot; return (0); } }