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 * Copyright 2006 Sun Microsystems, Inc. All rights reserved. 23 * Use is subject to license terms. 24 */ 25 26 /* Copyright (c) 1984, 1986, 1987, 1988, 1989 AT&T */ 27 /* All Rights Reserved */ 28 29 /* 30 * University Copyright- Copyright (c) 1982, 1986, 1988 31 * The Regents of the University of California 32 * All Rights Reserved 33 * 34 * University Acknowledgment- Portions of this document are derived from 35 * software developed by the University of California, Berkeley, and its 36 * contributors. 37 */ 38 39 #pragma ident "%Z%%M% %I% %E% SMI" 40 41 #include "synonyms.h" 42 43 #include <string.h> 44 #include <sys/types.h> 45 #include <sys/time.h> 46 #include <sys/resource.h> 47 #include <sys/procset.h> 48 #include <sys/priocntl.h> 49 #include <limits.h> 50 #include <errno.h> 51 #include <priv.h> 52 53 static idtype_t 54 prio_to_idtype(int which) 55 { 56 switch (which) { 57 58 case PRIO_PROCESS: 59 return (P_PID); 60 61 case PRIO_PGRP: 62 return (P_PGID); 63 64 case PRIO_USER: 65 return (P_UID); 66 67 case PRIO_GROUP: 68 return (P_GID); 69 70 case PRIO_SESSION: 71 return (P_SID); 72 73 case PRIO_LWP: 74 return (P_LWPID); 75 76 case PRIO_TASK: 77 return (P_TASKID); 78 79 case PRIO_PROJECT: 80 return (P_PROJID); 81 82 case PRIO_ZONE: 83 return (P_ZONEID); 84 85 case PRIO_CONTRACT: 86 return (P_CTID); 87 88 default: 89 return (-1); 90 } 91 } 92 93 static int 94 old_idtype(int which) 95 { 96 switch (which) { 97 case PRIO_PROCESS: 98 case PRIO_PGRP: 99 case PRIO_USER: 100 return (1); 101 default: 102 return (0); 103 } 104 } 105 106 int 107 getpriority(int which, id_t who) 108 { 109 id_t id; 110 idtype_t idtype; 111 pcnice_t pcnice; 112 113 if ((idtype = prio_to_idtype(which)) == -1) { 114 errno = EINVAL; 115 return (-1); 116 } 117 118 if (who < 0) { 119 if (old_idtype(which)) { 120 errno = EINVAL; 121 return (-1); 122 } else if (who != P_MYID) { 123 errno = EINVAL; 124 return (-1); 125 } 126 } 127 128 /* 129 * The POSIX standard requires that a 0 value for the who argument 130 * should specify the current process, process group, or user. 131 * For all other id types we can treat zero as normal id value. 132 */ 133 if (who == 0 && old_idtype(which)) 134 id = P_MYID; 135 else 136 id = who; 137 138 pcnice.pc_val = 0; 139 pcnice.pc_op = PC_GETNICE; 140 141 if (priocntl(idtype, id, PC_DONICE, (caddr_t)&pcnice) == -1) 142 return (-1); 143 else 144 return (pcnice.pc_val); 145 } 146 147 int 148 setpriority(int which, id_t who, int prio) 149 { 150 id_t id; 151 idtype_t idtype; 152 pcnice_t pcnice; 153 int ret; 154 155 if ((idtype = prio_to_idtype(which)) == -1) { 156 errno = EINVAL; 157 return (-1); 158 } 159 160 if (who < 0) { 161 if (old_idtype(which)) { 162 errno = EINVAL; 163 return (-1); 164 } else if (who != P_MYID) { 165 errno = EINVAL; 166 return (-1); 167 } 168 } 169 170 if (who == 0 && old_idtype(which)) 171 id = P_MYID; 172 else 173 id = who; 174 175 if (prio > 19) 176 prio = 19; 177 else if (prio < -20) 178 prio = -20; 179 180 pcnice.pc_val = prio; 181 pcnice.pc_op = PC_SETNICE; 182 183 ret = priocntl(idtype, id, PC_DONICE, (caddr_t)&pcnice); 184 185 if (ret != 0 && errno == EPERM) { 186 int incr; 187 int tmp; 188 pcnice_t gpcnice = { 0, PC_GETNICE }; 189 priv_set_t *pset; 190 191 /* 192 * The priocntl PC_DONICE subcommand returns EPERM if we lack 193 * sufficient privileges to carry out the operation, but 194 * setpriority(3C) needs to return EACCES. We can't just change 195 * EPERM to EACCES, because there are other conditions which 196 * legitimately cause EPERM (such as an euid/ruid mismatch 197 * between the current process and the target.). 198 */ 199 if ((tmp = priocntl(idtype, id, PC_DONICE, 200 (caddr_t)&gpcnice)) != 0) 201 return (tmp); 202 203 incr = prio - gpcnice.pc_val; 204 205 if ((pset = priv_allocset()) == NULL || 206 getppriv(PRIV_EFFECTIVE, pset) != 0) 207 return (-1); 208 209 /* 210 * setpriority(3C) must return EACCES if we lack the privilege 211 * checked for below and we are trying to increase the process 212 * priority (by lowering the numeric value of its priority). 213 */ 214 if ((incr < 0 || incr > 2 * NZERO) && 215 !priv_ismember(pset, "proc_priocntl")) 216 errno = EACCES; 217 218 priv_freeset(pset); 219 } 220 221 return (ret); 222 } 223