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 #pragma ident "%Z%%M% %I% %E% SMI"
27
28 #include <errno.h>
29 #include <strings.h>
30 #include <sys/types.h>
31 #include <sys/systm.h>
32 #include <sys/resource.h>
33 #include <sys/sysconfig.h>
34 #include <sys/lx_types.h>
35 #include <sys/lx_misc.h>
36
37 #define LX_RLIMIT_RSS 5
38 #define LX_RLIMIT_NPROC 6
39 #define LX_RLIMIT_MEMLOCK 8
40 #define LX_RLIMIT_LOCKS 10
41 #define LX_RLIMIT_NLIMITS 11
42
43 /*
44 * Linux supports many of the same resources that we do, but the numbering
45 * is slightly different. This table is used to translate Linux resource
46 * limit keys into their Solaris equivalents.
47 */
48 static int ltos_resource[LX_RLIMIT_NLIMITS] = {
49 RLIMIT_CPU,
50 RLIMIT_FSIZE,
51 RLIMIT_DATA,
52 RLIMIT_STACK,
53 RLIMIT_CORE,
54 -1, /* RSS */
55 -1, /* NPROC */
56 RLIMIT_NOFILE,
57 -1, /* MEMLOCK */
58 RLIMIT_AS,
59 -1 /* LOCKS */
60 };
61
62 #define NLIMITS (sizeof (ltos_resource) / sizeof (int))
63
64 /*
65 * Magic values Linux uses to indicate infinity
66 */
67 #define LX_RLIM_INFINITY_O (0x7fffffffUL)
68 #define LX_RLIM_INFINITY_N (0xffffffffUL)
69
70 /*
71 * Array to store the rlimits that we track but do not enforce.
72 */
73 static struct rlimit fake_limits[NLIMITS] = {
74 0, 0,
75 0, 0,
76 0, 0,
77 0, 0,
78 0, 0,
79 RLIM_INFINITY, RLIM_INFINITY, /* LX_RLIM_RSS */
80 RLIM_INFINITY, RLIM_INFINITY, /* LX_RLIM_NPROC */
81 0, 0,
82 RLIM_INFINITY, RLIM_INFINITY, /* LX_RLIM_MEMLOCK */
83 0, 0,
84 RLIM_INFINITY, RLIM_INFINITY /* LX_RLIM_LOCKS */
85 };
86
87 static int
88 lx_getrlimit_common(int resource, struct rlimit *rlp, int inf)
89 {
90 int rv;
91 int sresource;
92 struct rlimit rl;
93
94 if (resource < 0 || resource >= LX_RLIMIT_NLIMITS)
95 return (-EINVAL);
96
97 sresource = ltos_resource[resource];
98
99 if (sresource == -1) {
100 switch (resource) {
101 case LX_RLIMIT_MEMLOCK:
102 case LX_RLIMIT_RSS:
103 case LX_RLIMIT_LOCKS:
104 case LX_RLIMIT_NPROC:
105 rl.rlim_max = fake_limits[resource].rlim_max;
106 rl.rlim_cur = fake_limits[resource].rlim_cur;
107 if (rl.rlim_cur == RLIM_INFINITY)
108 rl.rlim_cur = inf;
109 if (rl.rlim_max == RLIM_INFINITY)
110 rl.rlim_max = inf;
111 if ((uucopy(&rl, rlp, sizeof (rl))) != 0)
112 return (-errno);
113 return (0);
114 default:
115 lx_unsupported("Unsupported resource type %d\n",
116 resource);
117 return (-ENOTSUP);
118 }
119 } else {
120 rv = getrlimit(sresource, rlp);
121 }
122
123 if (rv < 0)
124 return (-errno);
125
126 if (rlp->rlim_cur == RLIM_INFINITY)
127 rlp->rlim_cur = inf;
128
129 if (rlp->rlim_max == RLIM_INFINITY)
130 rlp->rlim_max = inf;
131
132 return (0);
133 }
134
135 /*
136 * This is the 'new' getrlimit, variously called getrlimit or ugetrlimit
137 * in Linux headers and code. The only difference between this and the old
138 * getrlimit (variously called getrlimit or old_getrlimit) is the value of
139 * RLIM_INFINITY, which is smaller for the older version. Modern code will
140 * use this version by default.
141 */
142 int
143 lx_getrlimit(uintptr_t p1, uintptr_t p2)
144 {
145 int resource = (int)p1;
146 struct rlimit *rlp = (struct rlimit *)p2;
147
148 return (lx_getrlimit_common(resource, rlp, LX_RLIM_INFINITY_N));
149 }
150
151 /*
152 * This is the 'old' getrlimit, variously called getrlimit or old_getrlimit
153 * in Linux headers and code. The only difference between this and the new
154 * getrlimit (variously called getrlimit or ugetrlimit) is the value of
155 * RLIM_INFINITY, which is smaller for the older version.
156 */
157 int
158 lx_oldgetrlimit(uintptr_t p1, uintptr_t p2)
159 {
160 int resource = (int)p1;
161 struct rlimit *rlp = (struct rlimit *)p2;
162
163 return (lx_getrlimit_common(resource, rlp, LX_RLIM_INFINITY_O));
164 }
165
166 int
167 lx_setrlimit(uintptr_t p1, uintptr_t p2)
168 {
169 int resource = (int)p1;
170 struct rlimit *rlp = (struct rlimit *)p2;
171 struct rlimit rl;
172 int rv, sresource;
173
174 if (resource < 0 || resource >= LX_RLIMIT_NLIMITS)
175 return (-EINVAL);
176
177 sresource = ltos_resource[resource];
178
179 if (sresource == -1) {
180 if (uucopy((void *)p2, &rl, sizeof (rl)) != 0)
181 return (-errno);
182
183 switch (resource) {
184 case LX_RLIMIT_MEMLOCK:
185 case LX_RLIMIT_RSS:
186 case LX_RLIMIT_LOCKS:
187 case LX_RLIMIT_NPROC:
188 if (rl.rlim_max != LX_RLIM_INFINITY_N &&
189 (rl.rlim_cur == LX_RLIM_INFINITY_N ||
190 rl.rlim_cur > rl.rlim_max))
191 return (-EINVAL);
192 if (rl.rlim_max == LX_RLIM_INFINITY_N)
193 fake_limits[resource].rlim_max = RLIM_INFINITY;
194 else
195 fake_limits[resource].rlim_max = rl.rlim_max;
196 if (rl.rlim_cur == LX_RLIM_INFINITY_N)
197 fake_limits[resource].rlim_cur = RLIM_INFINITY;
198 else
199 fake_limits[resource].rlim_cur = rl.rlim_cur;
200 return (0);
201 }
202
203 lx_unsupported("Unsupported resource type %d\n", resource);
204 return (-ENOTSUP);
205 }
206
207 rv = setrlimit(sresource, rlp);
208
209 return (rv < 0 ? -errno : 0);
210 }
211
212 /*
213 * We lucked out here. Linux and Solaris have exactly the same
214 * rusage structures.
215 */
216 int
217 lx_getrusage(uintptr_t p1, uintptr_t p2)
218 {
219 int who = (int)p1;
220 struct rusage *rup = (struct rusage *)p2;
221 int rv, swho;
222
223 if (who == LX_RUSAGE_SELF)
224 swho = _RUSAGESYS_GETRUSAGE;
225 else if (who == LX_RUSAGE_CHILDREN)
226 swho = _RUSAGESYS_GETRUSAGE_CHLD;
227 else
228 return (-EINVAL);
229
230 rv = getrusage(swho, rup);
231
232 return (rv < 0 ? -errno : 0);
233 }