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