xref: /illumos-gate/usr/src/lib/libc/port/gen/setpriority.c (revision e7cbe64f7a72dae5cb44f100db60ca88f3313c65)
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 "synonyms.h"
43 
44 #include <string.h>
45 #include <limits.h>
46 #include <sys/types.h>
47 #include <sys/time.h>
48 #include <sys/resource.h>
49 #include <sys/procset.h>
50 #include <sys/priocntl.h>
51 #include <limits.h>
52 #include <errno.h>
53 #include <priv.h>
54 
55 static idtype_t
56 prio_to_idtype(int which)
57 {
58 	switch (which) {
59 
60 	case PRIO_PROCESS:
61 		return (P_PID);
62 
63 	case PRIO_PGRP:
64 		return (P_PGID);
65 
66 	case PRIO_USER:
67 		return (P_UID);
68 
69 	case PRIO_GROUP:
70 		return (P_GID);
71 
72 	case PRIO_SESSION:
73 		return (P_SID);
74 
75 	case PRIO_LWP:
76 		return (P_LWPID);
77 
78 	case PRIO_TASK:
79 		return (P_TASKID);
80 
81 	case PRIO_PROJECT:
82 		return (P_PROJID);
83 
84 	case PRIO_ZONE:
85 		return (P_ZONEID);
86 
87 	case PRIO_CONTRACT:
88 		return (P_CTID);
89 
90 	default:
91 		return (-1);
92 	}
93 }
94 
95 static int
96 old_idtype(int which)
97 {
98 	switch (which) {
99 	case PRIO_PROCESS:
100 	case PRIO_PGRP:
101 	case PRIO_USER:
102 		return (1);
103 	default:
104 		return (0);
105 	}
106 }
107 
108 int
109 getpriority(int which, id_t who)
110 {
111 	id_t id;
112 	idtype_t idtype;
113 	pcnice_t pcnice;
114 
115 	if ((idtype = prio_to_idtype(which)) == -1) {
116 		errno = EINVAL;
117 		return (-1);
118 	}
119 
120 	if (who < 0) {
121 		if (old_idtype(which)) {
122 			errno = EINVAL;
123 			return (-1);
124 		} else if (who != P_MYID) {
125 			errno = EINVAL;
126 			return (-1);
127 		}
128 	}
129 
130 	/*
131 	 * The POSIX standard requires that a 0 value for the who argument
132 	 * should specify the current process, process group, or user.
133 	 * For all other id types we can treat zero as normal id value.
134 	 */
135 	if (who == 0 && old_idtype(which))
136 		id = P_MYID;
137 	else
138 		id = who;
139 
140 	pcnice.pc_val = 0;
141 	pcnice.pc_op = PC_GETNICE;
142 
143 	if (priocntl(idtype, id, PC_DONICE, &pcnice) == -1)
144 		return (-1);
145 	else
146 		return (pcnice.pc_val);
147 }
148 
149 int
150 setpriority(int which, id_t who, int prio)
151 {
152 	id_t id;
153 	idtype_t idtype;
154 	pcnice_t pcnice;
155 	int ret;
156 
157 	if ((idtype = prio_to_idtype(which)) == -1) {
158 		errno = EINVAL;
159 		return (-1);
160 	}
161 
162 	if (who < 0) {
163 		if (old_idtype(which)) {
164 			errno = EINVAL;
165 			return (-1);
166 		} else if (who != P_MYID) {
167 			errno = EINVAL;
168 			return (-1);
169 		}
170 	}
171 
172 	if (who == 0 && old_idtype(which))
173 		id = P_MYID;
174 	else
175 		id = who;
176 
177 	if (prio > NZERO - 1)
178 		prio = NZERO - 1;
179 	else if (prio < -NZERO)
180 		prio = -NZERO;
181 
182 	pcnice.pc_val = prio;
183 	pcnice.pc_op = PC_SETNICE;
184 
185 	ret = priocntl(idtype, id, PC_DONICE, &pcnice);
186 
187 	if (ret != 0 && errno == EPERM) {
188 		pcnice_t	gpcnice = { 0, PC_GETNICE };
189 		priv_set_t	*pset = NULL;
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) may need to return EACCES.  We can't just
195 		 * change EPERM to EACCES, because there are other conditions
196 		 * which legitimately cause EPERM (such as an euid/ruid mismatch
197 		 * between the current process and the target.).
198 		 *
199 		 * setpriority(3C) must return EACCES if we lack the privilege
200 		 * checked for below and we are trying to increase the process
201 		 * priority (by lowering the numeric value of its priority).
202 		 */
203 		if (priocntl(idtype, id, PC_DONICE, &gpcnice) == 0 &&
204 		    prio < gpcnice.pc_val) {
205 			if ((pset = priv_allocset()) != NULL &&
206 			    getppriv(PRIV_EFFECTIVE, pset) == 0 &&
207 			    !priv_ismember(pset, "proc_priocntl"))
208 				errno = EACCES;
209 			if (pset != NULL)
210 				priv_freeset(pset);
211 		}
212 	}
213 
214 	return (ret);
215 }
216