/usr/src/cmd/priocntl/subr.c
C | 729 lines | 472 code | 119 blank | 138 comment | 121 complexity | 867be0eb6eeef15dd5125227a4d7d963 MD5 | raw file
Possible License(s): AGPL-3.0, BSD-3-Clause, GPL-2.0, GPL-3.0, 0BSD, BSD-2-Clause, BSD-3-Clause-No-Nuclear-License-2014, MPL-2.0-no-copyleft-exception, AGPL-1.0, LGPL-2.1, LGPL-2.0
- /*
- * 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 <stdio.h>
- #include <string.h>
- #include <strings.h>
- #include <stdlib.h>
- #include <unistd.h>
- #include <sys/types.h>
- #include <limits.h>
- #include <dirent.h>
- #include <fcntl.h>
- #include <sys/time.h>
- #include <sys/procset.h>
- #include <sys/priocntl.h>
- #include <sys/task.h>
- #include <procfs.h>
- #include <project.h>
- #include <errno.h>
- #include <zone.h>
- #include <libcontract_priv.h>
- #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 <sys/procset.h>.
- */
- 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/<pid>/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);
- }
- }