Home | History | Annotate | Download | only in gen
      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 (the "License").
      6  * You may not use this file except in compliance with the License.
      7  *
      8  * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
      9  * or http://www.opensolaris.org/os/licensing.
     10  * See the License for the specific language governing permissions
     11  * and limitations under the License.
     12  *
     13  * When distributing Covered Code, include this CDDL HEADER in each
     14  * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
     15  * If applicable, add the following below this CDDL HEADER, with the
     16  * fields enclosed by brackets "[]" replaced with your own identifying
     17  * information: Portions Copyright [yyyy] [name of copyright owner]
     18  *
     19  * CDDL HEADER END
     20  */
     21 
     22 /*
     23  * Copyright 2008 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  * University Copyright- Copyright (c) 1982, 1986, 1988
     32  * The Regents of the University of California
     33  * All Rights Reserved
     34  *
     35  * University Acknowledgment- Portions of this document are derived from
     36  * software developed by the University of California, Berkeley, and its
     37  * contributors.
     38  */
     39 
     40 #pragma ident	"%Z%%M%	%I%	%E% SMI"
     41 
     42 #include "lint.h"
     43 #include <string.h>
     44 #include <limits.h>
     45 #include <sys/types.h>
     46 #include <sys/time.h>
     47 #include <sys/resource.h>
     48 #include <sys/procset.h>
     49 #include <sys/priocntl.h>
     50 #include <limits.h>
     51 #include <errno.h>
     52 #include <priv.h>
     53 
     54 static idtype_t
     55 prio_to_idtype(int which)
     56 {
     57 	switch (which) {
     58 
     59 	case PRIO_PROCESS:
     60 		return (P_PID);
     61 
     62 	case PRIO_PGRP:
     63 		return (P_PGID);
     64 
     65 	case PRIO_USER:
     66 		return (P_UID);
     67 
     68 	case PRIO_GROUP:
     69 		return (P_GID);
     70 
     71 	case PRIO_SESSION:
     72 		return (P_SID);
     73 
     74 	case PRIO_LWP:
     75 		return (P_LWPID);
     76 
     77 	case PRIO_TASK:
     78 		return (P_TASKID);
     79 
     80 	case PRIO_PROJECT:
     81 		return (P_PROJID);
     82 
     83 	case PRIO_ZONE:
     84 		return (P_ZONEID);
     85 
     86 	case PRIO_CONTRACT:
     87 		return (P_CTID);
     88 
     89 	default:
     90 		return (-1);
     91 	}
     92 }
     93 
     94 static int
     95 old_idtype(int which)
     96 {
     97 	switch (which) {
     98 	case PRIO_PROCESS:
     99 	case PRIO_PGRP:
    100 	case PRIO_USER:
    101 		return (1);
    102 	default:
    103 		return (0);
    104 	}
    105 }
    106 
    107 int
    108 getpriority(int which, id_t who)
    109 {
    110 	id_t id;
    111 	idtype_t idtype;
    112 	pcnice_t pcnice;
    113 
    114 	if ((idtype = prio_to_idtype(which)) == -1) {
    115 		errno = EINVAL;
    116 		return (-1);
    117 	}
    118 
    119 	if (who < 0) {
    120 		if (old_idtype(which)) {
    121 			errno = EINVAL;
    122 			return (-1);
    123 		} else if (who != P_MYID) {
    124 			errno = EINVAL;
    125 			return (-1);
    126 		}
    127 	}
    128 
    129 	/*
    130 	 * The POSIX standard requires that a 0 value for the who argument
    131 	 * should specify the current process, process group, or user.
    132 	 * For all other id types we can treat zero as normal id value.
    133 	 */
    134 	if (who == 0 && old_idtype(which))
    135 		id = P_MYID;
    136 	else
    137 		id = who;
    138 
    139 	pcnice.pc_val = 0;
    140 	pcnice.pc_op = PC_GETNICE;
    141 
    142 	if (priocntl(idtype, id, PC_DONICE, &pcnice) == -1)
    143 		return (-1);
    144 	else
    145 		return (pcnice.pc_val);
    146 }
    147 
    148 int
    149 setpriority(int which, id_t who, int prio)
    150 {
    151 	id_t id;
    152 	idtype_t idtype;
    153 	pcnice_t pcnice;
    154 	int ret;
    155 
    156 	if ((idtype = prio_to_idtype(which)) == -1) {
    157 		errno = EINVAL;
    158 		return (-1);
    159 	}
    160 
    161 	if (who < 0) {
    162 		if (old_idtype(which)) {
    163 			errno = EINVAL;
    164 			return (-1);
    165 		} else if (who != P_MYID) {
    166 			errno = EINVAL;
    167 			return (-1);
    168 		}
    169 	}
    170 
    171 	if (who == 0 && old_idtype(which))
    172 		id = P_MYID;
    173 	else
    174 		id = who;
    175 
    176 	if (prio > NZERO - 1)
    177 		prio = NZERO - 1;
    178 	else if (prio < -NZERO)
    179 		prio = -NZERO;
    180 
    181 	pcnice.pc_val = prio;
    182 	pcnice.pc_op = PC_SETNICE;
    183 
    184 	ret = priocntl(idtype, id, PC_DONICE, &pcnice);
    185 
    186 	if (ret != 0 && errno == EPERM) {
    187 		pcnice_t	gpcnice = { 0, PC_GETNICE };
    188 		priv_set_t	*pset = NULL;
    189 
    190 		/*
    191 		 * The priocntl PC_DONICE subcommand returns EPERM if we lack
    192 		 * sufficient privileges to carry out the operation, but
    193 		 * setpriority(3C) may need to return EACCES.  We can't just
    194 		 * change EPERM to EACCES, because there are other conditions
    195 		 * which legitimately cause EPERM (such as an euid/ruid mismatch
    196 		 * between the current process and the target.).
    197 		 *
    198 		 * setpriority(3C) must return EACCES if we lack the privilege
    199 		 * checked for below and we are trying to increase the process
    200 		 * priority (by lowering the numeric value of its priority).
    201 		 */
    202 		if (priocntl(idtype, id, PC_DONICE, &gpcnice) == 0 &&
    203 		    prio < gpcnice.pc_val) {
    204 			if ((pset = priv_allocset()) != NULL &&
    205 			    getppriv(PRIV_EFFECTIVE, pset) == 0 &&
    206 			    !priv_ismember(pset, "proc_priocntl"))
    207 				errno = EACCES;
    208 			if (pset != NULL)
    209 				priv_freeset(pset);
    210 		}
    211 	}
    212 
    213 	return (ret);
    214 }
    215