linux_misc_notalpha.c revision 1.51 1 /* $NetBSD: linux_misc_notalpha.c,v 1.51 1999/05/14 18:45:31 thorpej Exp $ */
2
3 /*-
4 * Copyright (c) 1995, 1998 The NetBSD Foundation, Inc.
5 * All rights reserved.
6 *
7 * This code is derived from software contributed to The NetBSD Foundation
8 * by Frank van der Linden and Eric Haszlakiewicz; by Jason R. Thorpe
9 * of the Numerical Aerospace Simulation Facility, NASA Ames Research Center.
10 *
11 * Redistribution and use in source and binary forms, with or without
12 * modification, are permitted provided that the following conditions
13 * are met:
14 * 1. Redistributions of source code must retain the above copyright
15 * notice, this list of conditions and the following disclaimer.
16 * 2. Redistributions in binary form must reproduce the above copyright
17 * notice, this list of conditions and the following disclaimer in the
18 * documentation and/or other materials provided with the distribution.
19 * 3. All advertising materials mentioning features or use of this software
20 * must display the following acknowledgement:
21 * This product includes software developed by the NetBSD
22 * Foundation, Inc. and its contributors.
23 * 4. Neither the name of The NetBSD Foundation nor the names of its
24 * contributors may be used to endorse or promote products derived
25 * from this software without specific prior written permission.
26 *
27 * THIS SOFTWARE IS PROVIDED BY THE NETBSD FOUNDATION, INC. AND CONTRIBUTORS
28 * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED
29 * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
30 * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE FOUNDATION OR CONTRIBUTORS
31 * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
32 * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
33 * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
34 * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
35 * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
36 * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
37 * POSSIBILITY OF SUCH DAMAGE.
38 */
39
40 #include <sys/param.h>
41 #include <sys/systm.h>
42 #include <sys/kernel.h>
43 #include <sys/mman.h>
44 #include <sys/mount.h>
45 #include <sys/malloc.h>
46 #include <sys/mbuf.h>
47 #include <sys/namei.h>
48 #include <sys/ptrace.h>
49 #include <sys/resource.h>
50 #include <sys/resourcevar.h>
51 #include <sys/wait.h>
52
53 #include <sys/syscallargs.h>
54
55 #include <vm/vm.h>
56 #include <vm/vm_param.h>
57
58 #include <compat/linux/common/linux_types.h>
59 #include <compat/linux/common/linux_fcntl.h>
60 #include <compat/linux/common/linux_misc.h>
61 #include <compat/linux/common/linux_mmap.h>
62 #include <compat/linux/common/linux_signal.h>
63 #include <compat/linux/common/linux_util.h>
64
65 #include <compat/linux/linux_syscallargs.h>
66
67 /*
68 * This file contains routines which are used
69 * on every linux architechture except the Alpha.
70 */
71
72 /* Used on: arm, i386, m68k, mips, ppc, sparc, sparc64 */
73 /* Not used on: alpha */
74
75 /*
76 * Alarm. This is a libc call which uses setitimer(2) in NetBSD.
77 * Fiddle with the timers to make it work.
78 */
79 int
80 linux_sys_alarm(p, v, retval)
81 struct proc *p;
82 void *v;
83 register_t *retval;
84 {
85 struct linux_sys_alarm_args /* {
86 syscallarg(unsigned int) secs;
87 } */ *uap = v;
88 int s;
89 struct itimerval *itp, it;
90
91 itp = &p->p_realtimer;
92 s = splclock();
93 /*
94 * Clear any pending timer alarms.
95 */
96 untimeout(realitexpire, p);
97 timerclear(&itp->it_interval);
98 if (timerisset(&itp->it_value) &&
99 timercmp(&itp->it_value, &time, >))
100 timersub(&itp->it_value, &time, &itp->it_value);
101 /*
102 * Return how many seconds were left (rounded up)
103 */
104 retval[0] = itp->it_value.tv_sec;
105 if (itp->it_value.tv_usec)
106 retval[0]++;
107
108 /*
109 * alarm(0) just resets the timer.
110 */
111 if (SCARG(uap, secs) == 0) {
112 timerclear(&itp->it_value);
113 splx(s);
114 return 0;
115 }
116
117 /*
118 * Check the new alarm time for sanity, and set it.
119 */
120 timerclear(&it.it_interval);
121 it.it_value.tv_sec = SCARG(uap, secs);
122 it.it_value.tv_usec = 0;
123 if (itimerfix(&it.it_value) || itimerfix(&it.it_interval)) {
124 splx(s);
125 return (EINVAL);
126 }
127
128 if (timerisset(&it.it_value)) {
129 timeradd(&it.it_value, &time, &it.it_value);
130 timeout(realitexpire, p, hzto(&it.it_value));
131 }
132 p->p_realtimer = it;
133 splx(s);
134
135 return 0;
136 }
137
138 int
139 linux_sys_nice(p, v, retval)
140 struct proc *p;
141 void *v;
142 register_t *retval;
143 {
144 struct linux_sys_nice_args /* {
145 syscallarg(int) incr;
146 } */ *uap = v;
147 struct sys_setpriority_args bsa;
148
149 SCARG(&bsa, which) = PRIO_PROCESS;
150 SCARG(&bsa, who) = 0;
151 SCARG(&bsa, prio) = SCARG(uap, incr);
152 return sys_setpriority(p, &bsa, retval);
153 }
154
155 /*
156 * The old Linux readdir was only able to read one entry at a time,
157 * even though it had a 'count' argument. In fact, the emulation
158 * of the old call was better than the original, because it did handle
159 * the count arg properly. Don't bother with it anymore now, and use
160 * it to distinguish between old and new. The difference is that the
161 * newer one actually does multiple entries, and the reclen field
162 * really is the reclen, not the namelength.
163 */
164 int
165 linux_sys_readdir(p, v, retval)
166 struct proc *p;
167 void *v;
168 register_t *retval;
169 {
170 struct linux_sys_readdir_args /* {
171 syscallarg(int) fd;
172 syscallarg(struct linux_dirent *) dent;
173 syscallarg(unsigned int) count;
174 } */ *uap = v;
175
176 SCARG(uap, count) = 1;
177 return linux_sys_getdents(p, uap, retval);
178 }
179
180 /*
181 * I wonder why Linux has gettimeofday() _and_ time().. Still, we
182 * need to deal with it.
183 */
184 int
185 linux_sys_time(p, v, retval)
186 struct proc *p;
187 void *v;
188 register_t *retval;
189 {
190 struct linux_sys_time_args /* {
191 linux_time_t *t;
192 } */ *uap = v;
193 struct timeval atv;
194 linux_time_t tt;
195 int error;
196
197 microtime(&atv);
198
199 tt = atv.tv_sec;
200 if (SCARG(uap, t) && (error = copyout(&tt, SCARG(uap, t), sizeof tt)))
201 return error;
202
203 retval[0] = tt;
204 return 0;
205 }
206
207 /*
208 * utime(). Do conversion to things that utimes() understands,
209 * and pass it on.
210 */
211 int
212 linux_sys_utime(p, v, retval)
213 struct proc *p;
214 void *v;
215 register_t *retval;
216 {
217 struct linux_sys_utime_args /* {
218 syscallarg(const char *) path;
219 syscallarg(struct linux_utimbuf *)times;
220 } */ *uap = v;
221 caddr_t sg;
222 int error;
223 struct sys_utimes_args ua;
224 struct timeval tv[2], *tvp;
225 struct linux_utimbuf lut;
226
227 sg = stackgap_init(p->p_emul);
228 LINUX_CHECK_ALT_EXIST(p, &sg, SCARG(uap, path));
229
230 SCARG(&ua, path) = SCARG(uap, path);
231
232 if (SCARG(uap, times) != NULL) {
233 if ((error = copyin(SCARG(uap, times), &lut, sizeof lut)))
234 return error;
235 tv[0].tv_usec = tv[1].tv_usec = 0;
236 tv[0].tv_sec = lut.l_actime;
237 tv[1].tv_sec = lut.l_modtime;
238 tvp = (struct timeval *) stackgap_alloc(&sg, sizeof(tv));
239 if ((error = copyout(tv, tvp, sizeof tv)))
240 return error;
241 SCARG(&ua, tptr) = tvp;
242 }
243 else
244 SCARG(&ua, tptr) = NULL;
245
246 return sys_utimes(p, &ua, retval);
247 }
248
249 /*
250 * waitpid(2). Passed on to the NetBSD call, surrounded by code to
251 * reserve some space for a NetBSD-style wait status, and converting
252 * it to what Linux wants.
253 */
254 int
255 linux_sys_waitpid(p, v, retval)
256 struct proc *p;
257 void *v;
258 register_t *retval;
259 {
260 struct linux_sys_waitpid_args /* {
261 syscallarg(int) pid;
262 syscallarg(int *) status;
263 syscallarg(int) options;
264 } */ *uap = v;
265 struct sys_wait4_args w4a;
266 int error, *status, tstat;
267 caddr_t sg;
268
269 if (SCARG(uap, status) != NULL) {
270 sg = stackgap_init(p->p_emul);
271 status = (int *) stackgap_alloc(&sg, sizeof status);
272 } else
273 status = NULL;
274
275 SCARG(&w4a, pid) = SCARG(uap, pid);
276 SCARG(&w4a, status) = status;
277 SCARG(&w4a, options) = SCARG(uap, options);
278 SCARG(&w4a, rusage) = NULL;
279
280 if ((error = sys_wait4(p, &w4a, retval)))
281 return error;
282
283 sigdelset(&p->p_siglist, SIGCHLD);
284
285 if (status != NULL) {
286 if ((error = copyin(status, &tstat, sizeof tstat)))
287 return error;
288
289 bsd_to_linux_wstat(&tstat);
290 return copyout(&tstat, SCARG(uap, status), sizeof tstat);
291 }
292
293 return 0;
294 }
295
296 int
297 linux_sys_setresgid(p, v, retval)
298 struct proc *p;
299 void *v;
300 register_t *retval;
301 {
302 struct linux_sys_setresgid_args /* {
303 syscallarg(gid_t) rgid;
304 syscallarg(gid_t) egid;
305 syscallarg(gid_t) sgid;
306 } */ *uap = v;
307 struct pcred *pc = p->p_cred;
308 gid_t rgid, egid, sgid;
309 int error;
310
311 rgid = SCARG(uap, rgid);
312 egid = SCARG(uap, egid);
313 sgid = SCARG(uap, sgid);
314
315 /*
316 * Note: These checks are a little different than the NetBSD
317 * setregid(2) call performs. This precisely follows the
318 * behavior of the Linux kernel.
319 */
320 if (rgid != (gid_t)-1 &&
321 rgid != pc->p_rgid &&
322 rgid != pc->pc_ucred->cr_gid &&
323 rgid != pc->p_svgid &&
324 (error = suser(pc->pc_ucred, &p->p_acflag)))
325 return (error);
326
327 if (egid != (gid_t)-1 &&
328 egid != pc->p_rgid &&
329 egid != pc->pc_ucred->cr_gid &&
330 egid != pc->p_svgid &&
331 (error = suser(pc->pc_ucred, &p->p_acflag)))
332 return (error);
333
334 if (sgid != (gid_t)-1 &&
335 sgid != pc->p_rgid &&
336 sgid != pc->pc_ucred->cr_gid &&
337 sgid != pc->p_svgid &&
338 (error = suser(pc->pc_ucred, &p->p_acflag)))
339 return (error);
340
341 /*
342 * Now assign the real, effective, and saved GIDs.
343 * Note that Linux, unlike NetBSD in setregid(2), does not
344 * set the saved UID in this call unless the user specifies
345 * it.
346 */
347 if (rgid != (gid_t)-1)
348 pc->p_rgid = rgid;
349
350 if (egid != (gid_t)-1) {
351 pc->pc_ucred = crcopy(pc->pc_ucred);
352 pc->pc_ucred->cr_gid = egid;
353 }
354
355 if (sgid != (gid_t)-1)
356 pc->p_svgid = sgid;
357
358 if (rgid != (gid_t)-1 && egid != (gid_t)-1 && sgid != (gid_t)-1)
359 p->p_flag |= P_SUGID;
360 return (0);
361 }
362
363 int
364 linux_sys_getresgid(p, v, retval)
365 struct proc *p;
366 void *v;
367 register_t *retval;
368 {
369 struct linux_sys_getresgid_args /* {
370 syscallarg(gid_t *) rgid;
371 syscallarg(gid_t *) egid;
372 syscallarg(gid_t *) sgid;
373 } */ *uap = v;
374 struct pcred *pc = p->p_cred;
375 int error;
376
377 /*
378 * Linux copies these values out to userspace like so:
379 *
380 * 1. Copy out rgid.
381 * 2. If that succeeds, copy out egid.
382 * 3. If both of those succeed, copy out sgid.
383 */
384 if ((error = copyout(&pc->p_rgid, SCARG(uap, rgid),
385 sizeof(gid_t))) != 0)
386 return (error);
387
388 if ((error = copyout(&pc->pc_ucred->cr_uid, SCARG(uap, egid),
389 sizeof(gid_t))) != 0)
390 return (error);
391
392 return (copyout(&pc->p_svgid, SCARG(uap, sgid), sizeof(gid_t)));
393 }
394