linux_misc_notalpha.c revision 1.73 1 /* $NetBSD: linux_misc_notalpha.c,v 1.73 2005/02/26 23:10:19 perry 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.73 2005/02/26 23:10:19 perry 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/sa.h>
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 #ifdef DEBUG_LINUX
79 #define DPRINTF(a) uprintf a
80 #else
81 #define DPRINTF(a)
82 #endif
83
84 #ifndef __m68k__
85 static void bsd_to_linux_statfs64(const struct statvfs *,
86 struct linux_statfs64 *);
87 #endif
88
89 /*
90 * Alarm. This is a libc call which uses setitimer(2) in NetBSD.
91 * Fiddle with the timers to make it work.
92 */
93 int
94 linux_sys_alarm(l, v, retval)
95 struct lwp *l;
96 void *v;
97 register_t *retval;
98 {
99 struct linux_sys_alarm_args /* {
100 syscallarg(unsigned int) secs;
101 } */ *uap = v;
102 struct proc *p = l->l_proc;
103 int s;
104 struct itimerval *itp, it;
105 struct ptimer *ptp;
106
107 if (p->p_timers && p->p_timers->pts_timers[ITIMER_REAL])
108 itp = &p->p_timers->pts_timers[ITIMER_REAL]->pt_time;
109 else
110 itp = NULL;
111 s = splclock();
112 /*
113 * Clear any pending timer alarms.
114 */
115 if (itp) {
116 callout_stop(&p->p_timers->pts_timers[ITIMER_REAL]->pt_ch);
117 timerclear(&itp->it_interval);
118 if (timerisset(&itp->it_value) &&
119 timercmp(&itp->it_value, &time, >))
120 timersub(&itp->it_value, &time, &itp->it_value);
121 /*
122 * Return how many seconds were left (rounded up)
123 */
124 retval[0] = itp->it_value.tv_sec;
125 if (itp->it_value.tv_usec)
126 retval[0]++;
127 } else {
128 retval[0] = 0;
129 }
130
131 /*
132 * alarm(0) just resets the timer.
133 */
134 if (SCARG(uap, secs) == 0) {
135 if (itp)
136 timerclear(&itp->it_value);
137 splx(s);
138 return 0;
139 }
140
141 /*
142 * Check the new alarm time for sanity, and set it.
143 */
144 timerclear(&it.it_interval);
145 it.it_value.tv_sec = SCARG(uap, secs);
146 it.it_value.tv_usec = 0;
147 if (itimerfix(&it.it_value) || itimerfix(&it.it_interval)) {
148 splx(s);
149 return (EINVAL);
150 }
151
152 if (p->p_timers == NULL)
153 timers_alloc(p);
154 ptp = p->p_timers->pts_timers[ITIMER_REAL];
155 if (ptp == NULL) {
156 ptp = pool_get(&ptimer_pool, PR_WAITOK);
157 ptp->pt_ev.sigev_notify = SIGEV_SIGNAL;
158 ptp->pt_ev.sigev_signo = SIGALRM;
159 ptp->pt_overruns = 0;
160 ptp->pt_proc = p;
161 ptp->pt_type = CLOCK_REALTIME;
162 ptp->pt_entry = CLOCK_REALTIME;
163 callout_init(&ptp->pt_ch);
164 p->p_timers->pts_timers[ITIMER_REAL] = ptp;
165 }
166
167 if (timerisset(&it.it_value)) {
168 /*
169 * Don't need to check hzto() return value, here.
170 * callout_reset() does it for us.
171 */
172 timeradd(&it.it_value, &time, &it.it_value);
173 callout_reset(&ptp->pt_ch, hzto(&it.it_value),
174 realtimerexpire, ptp);
175 }
176 ptp->pt_time = it;
177 splx(s);
178
179 return 0;
180 }
181
182 int
183 linux_sys_nice(l, v, retval)
184 struct lwp *l;
185 void *v;
186 register_t *retval;
187 {
188 struct linux_sys_nice_args /* {
189 syscallarg(int) incr;
190 } */ *uap = v;
191 struct sys_setpriority_args bsa;
192
193 SCARG(&bsa, which) = PRIO_PROCESS;
194 SCARG(&bsa, who) = 0;
195 SCARG(&bsa, prio) = SCARG(uap, incr);
196 return sys_setpriority(l, &bsa, retval);
197 }
198
199 /*
200 * The old Linux readdir was only able to read one entry at a time,
201 * even though it had a 'count' argument. In fact, the emulation
202 * of the old call was better than the original, because it did handle
203 * the count arg properly. Don't bother with it anymore now, and use
204 * it to distinguish between old and new. The difference is that the
205 * newer one actually does multiple entries, and the reclen field
206 * really is the reclen, not the namelength.
207 */
208 int
209 linux_sys_readdir(l, v, retval)
210 struct lwp *l;
211 void *v;
212 register_t *retval;
213 {
214 struct linux_sys_readdir_args /* {
215 syscallarg(int) fd;
216 syscallarg(struct linux_dirent *) dent;
217 syscallarg(unsigned int) count;
218 } */ *uap = v;
219
220 SCARG(uap, count) = 1;
221 return linux_sys_getdents(l, uap, retval);
222 }
223
224 /*
225 * I wonder why Linux has gettimeofday() _and_ time().. Still, we
226 * need to deal with it.
227 */
228 int
229 linux_sys_time(l, v, retval)
230 struct lwp *l;
231 void *v;
232 register_t *retval;
233 {
234 struct linux_sys_time_args /* {
235 linux_time_t *t;
236 } */ *uap = v;
237 struct timeval atv;
238 linux_time_t tt;
239 int error;
240
241 microtime(&atv);
242
243 tt = atv.tv_sec;
244 if (SCARG(uap, t) && (error = copyout(&tt, SCARG(uap, t), sizeof tt)))
245 return error;
246
247 retval[0] = tt;
248 return 0;
249 }
250
251 /*
252 * utime(). Do conversion to things that utimes() understands,
253 * and pass it on.
254 */
255 int
256 linux_sys_utime(l, v, retval)
257 struct lwp *l;
258 void *v;
259 register_t *retval;
260 {
261 struct linux_sys_utime_args /* {
262 syscallarg(const char *) path;
263 syscallarg(struct linux_utimbuf *)times;
264 } */ *uap = v;
265 struct proc *p = l->l_proc;
266 caddr_t sg;
267 int error;
268 struct sys_utimes_args ua;
269 struct timeval tv[2], *tvp;
270 struct linux_utimbuf lut;
271
272 sg = stackgap_init(p, 0);
273 tvp = (struct timeval *) stackgap_alloc(p, &sg, sizeof(tv));
274 CHECK_ALT_EXIST(p, &sg, SCARG(uap, path));
275
276 SCARG(&ua, path) = SCARG(uap, path);
277
278 if (SCARG(uap, times) != NULL) {
279 if ((error = copyin(SCARG(uap, times), &lut, sizeof lut)))
280 return error;
281 tv[0].tv_usec = tv[1].tv_usec = 0;
282 tv[0].tv_sec = lut.l_actime;
283 tv[1].tv_sec = lut.l_modtime;
284 if ((error = copyout(tv, tvp, sizeof tv)))
285 return error;
286 SCARG(&ua, tptr) = tvp;
287 }
288 else
289 SCARG(&ua, tptr) = NULL;
290
291 return sys_utimes(l, &ua, retval);
292 }
293
294 /*
295 * waitpid(2). Just forward on to linux_sys_wait4 with a NULL rusage.
296 */
297 int
298 linux_sys_waitpid(l, v, retval)
299 struct lwp *l;
300 void *v;
301 register_t *retval;
302 {
303 struct linux_sys_waitpid_args /* {
304 syscallarg(int) pid;
305 syscallarg(int *) status;
306 syscallarg(int) options;
307 } */ *uap = v;
308 struct linux_sys_wait4_args linux_w4a;
309
310 SCARG(&linux_w4a, pid) = SCARG(uap, pid);
311 SCARG(&linux_w4a, status) = SCARG(uap, status);
312 SCARG(&linux_w4a, options) = SCARG(uap, options);
313 SCARG(&linux_w4a, rusage) = NULL;
314
315 return linux_sys_wait4(l, &linux_w4a, retval);
316 }
317
318 int
319 linux_sys_setresgid(l, v, retval)
320 struct lwp *l;
321 void *v;
322 register_t *retval;
323 {
324 struct linux_sys_setresgid_args /* {
325 syscallarg(gid_t) rgid;
326 syscallarg(gid_t) egid;
327 syscallarg(gid_t) sgid;
328 } */ *uap = v;
329
330 /*
331 * Note: These checks are a little different than the NetBSD
332 * setregid(2) call performs. This precisely follows the
333 * behavior of the Linux kernel.
334 */
335 return do_setresgid(l, SCARG(uap,rgid), SCARG(uap, egid),
336 SCARG(uap, sgid),
337 ID_R_EQ_R | ID_R_EQ_E | ID_R_EQ_S |
338 ID_E_EQ_R | ID_E_EQ_E | ID_E_EQ_S |
339 ID_S_EQ_R | ID_S_EQ_E | ID_S_EQ_S );
340 }
341
342 int
343 linux_sys_getresgid(l, v, retval)
344 struct lwp *l;
345 void *v;
346 register_t *retval;
347 {
348 struct linux_sys_getresgid_args /* {
349 syscallarg(gid_t *) rgid;
350 syscallarg(gid_t *) egid;
351 syscallarg(gid_t *) sgid;
352 } */ *uap = v;
353 struct proc *p = l->l_proc;
354 struct pcred *pc = p->p_cred;
355 int error;
356
357 /*
358 * Linux copies these values out to userspace like so:
359 *
360 * 1. Copy out rgid.
361 * 2. If that succeeds, copy out egid.
362 * 3. If both of those succeed, copy out sgid.
363 */
364 if ((error = copyout(&pc->p_rgid, SCARG(uap, rgid),
365 sizeof(gid_t))) != 0)
366 return (error);
367
368 if ((error = copyout(&pc->pc_ucred->cr_gid, SCARG(uap, egid),
369 sizeof(gid_t))) != 0)
370 return (error);
371
372 return (copyout(&pc->p_svgid, SCARG(uap, sgid), sizeof(gid_t)));
373 }
374
375 /*
376 * I wonder why Linux has settimeofday() _and_ stime().. Still, we
377 * need to deal with it.
378 */
379 int
380 linux_sys_stime(l, v, retval)
381 struct lwp *l;
382 void *v;
383 register_t *retval;
384 {
385 struct linux_sys_time_args /* {
386 linux_time_t *t;
387 } */ *uap = v;
388 struct proc *p = l->l_proc;
389 struct timeval atv;
390 linux_time_t tt;
391 int error;
392
393 if ((error = suser(p->p_ucred, &p->p_acflag)) != 0)
394 return (error);
395
396 if ((error = copyin(&tt, SCARG(uap, t), sizeof tt)) != 0)
397 return error;
398
399 atv.tv_sec = tt;
400 atv.tv_usec = 0;
401
402 if ((error = settime(&atv)))
403 return (error);
404
405 return 0;
406 }
407
408 #ifndef __m68k__
409 /*
410 * Convert NetBSD statvfs structure to Linux statfs64 structure.
411 * See comments in bsd_to_linux_statfs() for further background.
412 * We can safely pass correct bsize and frsize here, since Linux glibc
413 * statvfs() doesn't use statfs64().
414 */
415 static void
416 bsd_to_linux_statfs64(bsp, lsp)
417 const struct statvfs *bsp;
418 struct linux_statfs64 *lsp;
419 {
420 int i, div;
421
422 for (i = 0; i < linux_fstypes_cnt; i++) {
423 if (strcmp(bsp->f_fstypename, linux_fstypes[i].bsd) == 0) {
424 lsp->l_ftype = linux_fstypes[i].linux;
425 break;
426 }
427 }
428
429 if (i == linux_fstypes_cnt) {
430 DPRINTF(("unhandled fstype in linux emulation: %s\n",
431 bsp->f_fstypename));
432 lsp->l_ftype = LINUX_DEFAULT_SUPER_MAGIC;
433 }
434
435 div = bsp->f_bsize / bsp->f_frsize;
436 lsp->l_fbsize = bsp->f_bsize;
437 lsp->l_ffrsize = bsp->f_frsize;
438 lsp->l_fblocks = bsp->f_blocks / div;
439 lsp->l_fbfree = bsp->f_bfree / div;
440 lsp->l_fbavail = bsp->f_bavail / div;
441 lsp->l_ffiles = bsp->f_files;
442 lsp->l_fffree = bsp->f_ffree / div;
443 /* Linux sets the fsid to 0..., we don't */
444 lsp->l_ffsid.val[0] = bsp->f_fsidx.__fsid_val[0];
445 lsp->l_ffsid.val[1] = bsp->f_fsidx.__fsid_val[1];
446 lsp->l_fnamelen = bsp->f_namemax;
447 (void)memset(lsp->l_fspare, 0, sizeof(lsp->l_fspare));
448 }
449
450 /*
451 * Implement the fs stat functions. Straightforward.
452 */
453 int
454 linux_sys_statfs64(l, v, retval)
455 struct lwp *l;
456 void *v;
457 register_t *retval;
458 {
459 struct linux_sys_statfs64_args /* {
460 syscallarg(const char *) path;
461 syscallarg(size_t) sz;
462 syscallarg(struct linux_statfs64 *) sp;
463 } */ *uap = v;
464 struct proc *p = l->l_proc;
465 struct statvfs btmp, *bsp;
466 struct linux_statfs64 ltmp;
467 struct sys_statvfs1_args bsa;
468 caddr_t sg;
469 int error;
470
471 if (SCARG(uap, sz) != sizeof ltmp)
472 return (EINVAL);
473
474 sg = stackgap_init(p, 0);
475 bsp = (struct statvfs *) stackgap_alloc(p, &sg, sizeof (struct statvfs));
476
477 CHECK_ALT_EXIST(p, &sg, SCARG(uap, path));
478
479 SCARG(&bsa, path) = SCARG(uap, path);
480 SCARG(&bsa, buf) = bsp;
481 SCARG(&bsa, flags) = ST_WAIT;
482
483 if ((error = sys_statvfs1(l, &bsa, retval)))
484 return error;
485
486 if ((error = copyin((caddr_t) bsp, (caddr_t) &btmp, sizeof btmp)))
487 return error;
488
489 bsd_to_linux_statfs64(&btmp, <mp);
490
491 return copyout((caddr_t) <mp, (caddr_t) SCARG(uap, sp), sizeof ltmp);
492 }
493
494 int
495 linux_sys_fstatfs64(l, v, retval)
496 struct lwp *l;
497 void *v;
498 register_t *retval;
499 {
500 struct linux_sys_fstatfs64_args /* {
501 syscallarg(int) fd;
502 syscallarg(size_t) sz;
503 syscallarg(struct linux_statfs64 *) sp;
504 } */ *uap = v;
505 struct proc *p = l->l_proc;
506 struct statvfs btmp, *bsp;
507 struct linux_statfs64 ltmp;
508 struct sys_fstatvfs1_args bsa;
509 caddr_t sg;
510 int error;
511
512 if (SCARG(uap, sz) != sizeof ltmp)
513 return (EINVAL);
514
515 sg = stackgap_init(p, 0);
516 bsp = (struct statvfs *) stackgap_alloc(p, &sg, sizeof (struct statvfs));
517
518 SCARG(&bsa, fd) = SCARG(uap, fd);
519 SCARG(&bsa, buf) = bsp;
520 SCARG(&bsa, flags) = ST_WAIT;
521
522 if ((error = sys_fstatvfs1(l, &bsa, retval)))
523 return error;
524
525 if ((error = copyin((caddr_t) bsp, (caddr_t) &btmp, sizeof btmp)))
526 return error;
527
528 bsd_to_linux_statfs64(&btmp, <mp);
529
530 return copyout((caddr_t) <mp, (caddr_t) SCARG(uap, sp), sizeof ltmp);
531 }
532 #endif /* !__m68k__ */
533