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