linux_misc_notalpha.c revision 1.60.2.2 1 /* $NetBSD: linux_misc_notalpha.c,v 1.60.2.2 2001/11/14 19:13:11 nathanw 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/cdefs.h>
41 __KERNEL_RCSID(0, "$NetBSD: linux_misc_notalpha.c,v 1.60.2.2 2001/11/14 19:13:11 nathanw Exp $");
42
43 #include <sys/param.h>
44 #include <sys/systm.h>
45 #include <sys/kernel.h>
46 #include <sys/mman.h>
47 #include <sys/mount.h>
48 #include <sys/malloc.h>
49 #include <sys/mbuf.h>
50 #include <sys/namei.h>
51 #include <sys/proc.h>
52 #include <sys/ptrace.h>
53 #include <sys/resource.h>
54 #include <sys/resourcevar.h>
55 #include <sys/wait.h>
56
57 #include <sys/syscallargs.h>
58
59 #include <compat/linux/common/linux_types.h>
60 #include <compat/linux/common/linux_fcntl.h>
61 #include <compat/linux/common/linux_misc.h>
62 #include <compat/linux/common/linux_mmap.h>
63 #include <compat/linux/common/linux_signal.h>
64 #include <compat/linux/common/linux_util.h>
65
66 #include <compat/linux/linux_syscallargs.h>
67
68 /*
69 * This file contains routines which are used
70 * on every linux architechture except the Alpha.
71 */
72
73 /* Used on: arm, i386, m68k, mips, ppc, sparc, sparc64 */
74 /* Not used on: alpha */
75
76 /*
77 * Alarm. This is a libc call which uses setitimer(2) in NetBSD.
78 * Fiddle with the timers to make it work.
79 */
80 int
81 linux_sys_alarm(l, v, retval)
82 struct lwp *l;
83 void *v;
84 register_t *retval;
85 {
86 struct linux_sys_alarm_args /* {
87 syscallarg(unsigned int) secs;
88 } */ *uap = v;
89 struct proc *p = l->l_proc;
90 int s;
91 struct itimerval *itp, it;
92
93 itp = &p->p_realtimer;
94 s = splclock();
95 /*
96 * Clear any pending timer alarms.
97 */
98 callout_stop(&p->p_realit_ch);
99 timerclear(&itp->it_interval);
100 if (timerisset(&itp->it_value) &&
101 timercmp(&itp->it_value, &time, >))
102 timersub(&itp->it_value, &time, &itp->it_value);
103 /*
104 * Return how many seconds were left (rounded up)
105 */
106 retval[0] = itp->it_value.tv_sec;
107 if (itp->it_value.tv_usec)
108 retval[0]++;
109
110 /*
111 * alarm(0) just resets the timer.
112 */
113 if (SCARG(uap, secs) == 0) {
114 timerclear(&itp->it_value);
115 splx(s);
116 return 0;
117 }
118
119 /*
120 * Check the new alarm time for sanity, and set it.
121 */
122 timerclear(&it.it_interval);
123 it.it_value.tv_sec = SCARG(uap, secs);
124 it.it_value.tv_usec = 0;
125 if (itimerfix(&it.it_value) || itimerfix(&it.it_interval)) {
126 splx(s);
127 return (EINVAL);
128 }
129
130 if (timerisset(&it.it_value)) {
131 /*
132 * Don't need to check hzto() return value, here.
133 * callout_reset() does it for us.
134 */
135 timeradd(&it.it_value, &time, &it.it_value);
136 callout_reset(&p->p_realit_ch, hzto(&it.it_value),
137 realitexpire, p);
138 }
139 p->p_realtimer = it;
140 splx(s);
141
142 return 0;
143 }
144
145 int
146 linux_sys_nice(l, v, retval)
147 struct lwp *l;
148 void *v;
149 register_t *retval;
150 {
151 struct linux_sys_nice_args /* {
152 syscallarg(int) incr;
153 } */ *uap = v;
154 struct sys_setpriority_args bsa;
155
156 SCARG(&bsa, which) = PRIO_PROCESS;
157 SCARG(&bsa, who) = 0;
158 SCARG(&bsa, prio) = SCARG(uap, incr);
159 return sys_setpriority(l, &bsa, retval);
160 }
161
162 /*
163 * The old Linux readdir was only able to read one entry at a time,
164 * even though it had a 'count' argument. In fact, the emulation
165 * of the old call was better than the original, because it did handle
166 * the count arg properly. Don't bother with it anymore now, and use
167 * it to distinguish between old and new. The difference is that the
168 * newer one actually does multiple entries, and the reclen field
169 * really is the reclen, not the namelength.
170 */
171 int
172 linux_sys_readdir(l, v, retval)
173 struct lwp *l;
174 void *v;
175 register_t *retval;
176 {
177 struct linux_sys_readdir_args /* {
178 syscallarg(int) fd;
179 syscallarg(struct linux_dirent *) dent;
180 syscallarg(unsigned int) count;
181 } */ *uap = v;
182
183 SCARG(uap, count) = 1;
184 return linux_sys_getdents(l, uap, retval);
185 }
186
187 /*
188 * I wonder why Linux has gettimeofday() _and_ time().. Still, we
189 * need to deal with it.
190 */
191 int
192 linux_sys_time(l, v, retval)
193 struct lwp *l;
194 void *v;
195 register_t *retval;
196 {
197 struct linux_sys_time_args /* {
198 linux_time_t *t;
199 } */ *uap = v;
200 struct timeval atv;
201 linux_time_t tt;
202 int error;
203
204 microtime(&atv);
205
206 tt = atv.tv_sec;
207 if (SCARG(uap, t) && (error = copyout(&tt, SCARG(uap, t), sizeof tt)))
208 return error;
209
210 retval[0] = tt;
211 return 0;
212 }
213
214 /*
215 * utime(). Do conversion to things that utimes() understands,
216 * and pass it on.
217 */
218 int
219 linux_sys_utime(l, v, retval)
220 struct lwp *l;
221 void *v;
222 register_t *retval;
223 {
224 struct linux_sys_utime_args /* {
225 syscallarg(const char *) path;
226 syscallarg(struct linux_utimbuf *)times;
227 } */ *uap = v;
228 struct proc *p = l->l_proc;
229 caddr_t sg;
230 int error;
231 struct sys_utimes_args ua;
232 struct timeval tv[2], *tvp;
233 struct linux_utimbuf lut;
234
235 sg = stackgap_init(p->p_emul);
236 tvp = (struct timeval *) stackgap_alloc(&sg, sizeof(tv));
237 CHECK_ALT_EXIST(p, &sg, SCARG(uap, path));
238
239 SCARG(&ua, path) = SCARG(uap, path);
240
241 if (SCARG(uap, times) != NULL) {
242 if ((error = copyin(SCARG(uap, times), &lut, sizeof lut)))
243 return error;
244 tv[0].tv_usec = tv[1].tv_usec = 0;
245 tv[0].tv_sec = lut.l_actime;
246 tv[1].tv_sec = lut.l_modtime;
247 if ((error = copyout(tv, tvp, sizeof tv)))
248 return error;
249 SCARG(&ua, tptr) = tvp;
250 }
251 else
252 SCARG(&ua, tptr) = NULL;
253
254 return sys_utimes(l, &ua, retval);
255 }
256
257 /*
258 * waitpid(2). Passed on to the NetBSD call, surrounded by code to
259 * reserve some space for a NetBSD-style wait status, and converting
260 * it to what Linux wants.
261 */
262 int
263 linux_sys_waitpid(l, v, retval)
264 struct lwp *l;
265 void *v;
266 register_t *retval;
267 {
268 struct linux_sys_waitpid_args /* {
269 syscallarg(int) pid;
270 syscallarg(int *) status;
271 syscallarg(int) options;
272 } */ *uap = v;
273 struct proc *p = l->l_proc;
274 struct sys_wait4_args w4a;
275 int error, *status, tstat;
276 caddr_t sg;
277
278 if (SCARG(uap, status) != NULL) {
279 sg = stackgap_init(p->p_emul);
280 status = (int *) stackgap_alloc(&sg, sizeof status);
281 } else
282 status = NULL;
283
284 SCARG(&w4a, pid) = SCARG(uap, pid);
285 SCARG(&w4a, status) = status;
286 SCARG(&w4a, options) = SCARG(uap, options);
287 SCARG(&w4a, rusage) = NULL;
288
289 if ((error = sys_wait4(l, &w4a, retval)))
290 return error;
291
292 sigdelset(&p->p_sigctx.ps_siglist, SIGCHLD);
293
294 if (status != NULL) {
295 if ((error = copyin(status, &tstat, sizeof tstat)))
296 return error;
297
298 bsd_to_linux_wstat(&tstat);
299 return copyout(&tstat, SCARG(uap, status), sizeof tstat);
300 }
301
302 return 0;
303 }
304
305 int
306 linux_sys_setresgid(l, v, retval)
307 struct lwp *l;
308 void *v;
309 register_t *retval;
310 {
311 struct linux_sys_setresgid_args /* {
312 syscallarg(gid_t) rgid;
313 syscallarg(gid_t) egid;
314 syscallarg(gid_t) sgid;
315 } */ *uap = v;
316 struct proc *p = l->l_proc;
317 struct pcred *pc = p->p_cred;
318 gid_t rgid, egid, sgid;
319 int error;
320
321 rgid = SCARG(uap, rgid);
322 egid = SCARG(uap, egid);
323 sgid = SCARG(uap, sgid);
324
325 /*
326 * Note: These checks are a little different than the NetBSD
327 * setregid(2) call performs. This precisely follows the
328 * behavior of the Linux kernel.
329 */
330 if (rgid != (gid_t)-1 &&
331 rgid != pc->p_rgid &&
332 rgid != pc->pc_ucred->cr_gid &&
333 rgid != pc->p_svgid &&
334 (error = suser(pc->pc_ucred, &p->p_acflag)))
335 return (error);
336
337 if (egid != (gid_t)-1 &&
338 egid != pc->p_rgid &&
339 egid != pc->pc_ucred->cr_gid &&
340 egid != pc->p_svgid &&
341 (error = suser(pc->pc_ucred, &p->p_acflag)))
342 return (error);
343
344 if (sgid != (gid_t)-1 &&
345 sgid != pc->p_rgid &&
346 sgid != pc->pc_ucred->cr_gid &&
347 sgid != pc->p_svgid &&
348 (error = suser(pc->pc_ucred, &p->p_acflag)))
349 return (error);
350
351 /*
352 * Now assign the real, effective, and saved GIDs.
353 * Note that Linux, unlike NetBSD in setregid(2), does not
354 * set the saved UID in this call unless the user specifies
355 * it.
356 */
357 if (rgid != (gid_t)-1)
358 pc->p_rgid = rgid;
359
360 if (egid != (gid_t)-1) {
361 pc->pc_ucred = crcopy(pc->pc_ucred);
362 pc->pc_ucred->cr_gid = egid;
363 }
364
365 if (sgid != (gid_t)-1)
366 pc->p_svgid = sgid;
367
368 if (rgid != (gid_t)-1 && egid != (gid_t)-1 && sgid != (gid_t)-1)
369 p->p_flag |= P_SUGID;
370 return (0);
371 }
372
373 int
374 linux_sys_getresgid(l, v, retval)
375 struct lwp *l;
376 void *v;
377 register_t *retval;
378 {
379 struct linux_sys_getresgid_args /* {
380 syscallarg(gid_t *) rgid;
381 syscallarg(gid_t *) egid;
382 syscallarg(gid_t *) sgid;
383 } */ *uap = v;
384 struct proc *p = l->l_proc;
385 struct pcred *pc = p->p_cred;
386 int error;
387
388 /*
389 * Linux copies these values out to userspace like so:
390 *
391 * 1. Copy out rgid.
392 * 2. If that succeeds, copy out egid.
393 * 3. If both of those succeed, copy out sgid.
394 */
395 if ((error = copyout(&pc->p_rgid, SCARG(uap, rgid),
396 sizeof(gid_t))) != 0)
397 return (error);
398
399 if ((error = copyout(&pc->pc_ucred->cr_uid, SCARG(uap, egid),
400 sizeof(gid_t))) != 0)
401 return (error);
402
403 return (copyout(&pc->p_svgid, SCARG(uap, sgid), sizeof(gid_t)));
404 }
405
406 /*
407 * I wonder why Linux has settimeofday() _and_ stime().. Still, we
408 * need to deal with it.
409 */
410 int
411 linux_sys_stime(l, v, retval)
412 struct lwp *l;
413 void *v;
414 register_t *retval;
415 {
416 struct linux_sys_time_args /* {
417 linux_time_t *t;
418 } */ *uap = v;
419 struct proc *p = l->l_proc;
420 struct timeval atv;
421 linux_time_t tt;
422 int error;
423
424 if ((error = suser(p->p_ucred, &p->p_acflag)) != 0)
425 return (error);
426
427 if ((error = copyin(&tt, SCARG(uap, t), sizeof tt)) != 0)
428 return error;
429
430 atv.tv_sec = tt;
431 atv.tv_usec = 0;
432
433 if ((error = settime(&atv)))
434 return (error);
435
436 return 0;
437 }
438