linux_misc_notalpha.c revision 1.74 1 /* $NetBSD: linux_misc_notalpha.c,v 1.74 2005/05/03 16:26:28 manu 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.74 2005/05/03 16:26:28 manu 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 #if !defined(__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 #ifndef __amd64__
183 int
184 linux_sys_nice(l, v, retval)
185 struct lwp *l;
186 void *v;
187 register_t *retval;
188 {
189 struct linux_sys_nice_args /* {
190 syscallarg(int) incr;
191 } */ *uap = v;
192 struct sys_setpriority_args bsa;
193
194 SCARG(&bsa, which) = PRIO_PROCESS;
195 SCARG(&bsa, who) = 0;
196 SCARG(&bsa, prio) = SCARG(uap, incr);
197 return sys_setpriority(l, &bsa, retval);
198 }
199 #endif
200
201 #ifndef __amd64__
202 /*
203 * The old Linux readdir was only able to read one entry at a time,
204 * even though it had a 'count' argument. In fact, the emulation
205 * of the old call was better than the original, because it did handle
206 * the count arg properly. Don't bother with it anymore now, and use
207 * it to distinguish between old and new. The difference is that the
208 * newer one actually does multiple entries, and the reclen field
209 * really is the reclen, not the namelength.
210 */
211 int
212 linux_sys_readdir(l, v, retval)
213 struct lwp *l;
214 void *v;
215 register_t *retval;
216 {
217 struct linux_sys_readdir_args /* {
218 syscallarg(int) fd;
219 syscallarg(struct linux_dirent *) dent;
220 syscallarg(unsigned int) count;
221 } */ *uap = v;
222
223 SCARG(uap, count) = 1;
224 return linux_sys_getdents(l, uap, retval);
225 }
226 #endif /* !amd64 */
227
228 /*
229 * I wonder why Linux has gettimeofday() _and_ time().. Still, we
230 * need to deal with it.
231 */
232 int
233 linux_sys_time(l, v, retval)
234 struct lwp *l;
235 void *v;
236 register_t *retval;
237 {
238 struct linux_sys_time_args /* {
239 linux_time_t *t;
240 } */ *uap = v;
241 struct timeval atv;
242 linux_time_t tt;
243 int error;
244
245 microtime(&atv);
246
247 tt = atv.tv_sec;
248 if (SCARG(uap, t) && (error = copyout(&tt, SCARG(uap, t), sizeof tt)))
249 return error;
250
251 retval[0] = tt;
252 return 0;
253 }
254
255 /*
256 * utime(). Do conversion to things that utimes() understands,
257 * and pass it on.
258 */
259 int
260 linux_sys_utime(l, v, retval)
261 struct lwp *l;
262 void *v;
263 register_t *retval;
264 {
265 struct linux_sys_utime_args /* {
266 syscallarg(const char *) path;
267 syscallarg(struct linux_utimbuf *)times;
268 } */ *uap = v;
269 struct proc *p = l->l_proc;
270 caddr_t sg;
271 int error;
272 struct sys_utimes_args ua;
273 struct timeval tv[2], *tvp;
274 struct linux_utimbuf lut;
275
276 sg = stackgap_init(p, 0);
277 tvp = (struct timeval *) stackgap_alloc(p, &sg, sizeof(tv));
278 CHECK_ALT_EXIST(p, &sg, SCARG(uap, path));
279
280 SCARG(&ua, path) = SCARG(uap, path);
281
282 if (SCARG(uap, times) != NULL) {
283 if ((error = copyin(SCARG(uap, times), &lut, sizeof lut)))
284 return error;
285 tv[0].tv_usec = tv[1].tv_usec = 0;
286 tv[0].tv_sec = lut.l_actime;
287 tv[1].tv_sec = lut.l_modtime;
288 if ((error = copyout(tv, tvp, sizeof tv)))
289 return error;
290 SCARG(&ua, tptr) = tvp;
291 }
292 else
293 SCARG(&ua, tptr) = NULL;
294
295 return sys_utimes(l, &ua, retval);
296 }
297
298 #ifndef __amd64__
299 /*
300 * waitpid(2). Just forward on to linux_sys_wait4 with a NULL rusage.
301 */
302 int
303 linux_sys_waitpid(l, v, retval)
304 struct lwp *l;
305 void *v;
306 register_t *retval;
307 {
308 struct linux_sys_waitpid_args /* {
309 syscallarg(int) pid;
310 syscallarg(int *) status;
311 syscallarg(int) options;
312 } */ *uap = v;
313 struct linux_sys_wait4_args linux_w4a;
314
315 SCARG(&linux_w4a, pid) = SCARG(uap, pid);
316 SCARG(&linux_w4a, status) = SCARG(uap, status);
317 SCARG(&linux_w4a, options) = SCARG(uap, options);
318 SCARG(&linux_w4a, rusage) = NULL;
319
320 return linux_sys_wait4(l, &linux_w4a, retval);
321 }
322 #endif /* !amd64 */
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
336 /*
337 * Note: These checks are a little different than the NetBSD
338 * setregid(2) call performs. This precisely follows the
339 * behavior of the Linux kernel.
340 */
341 return do_setresgid(l, SCARG(uap,rgid), SCARG(uap, egid),
342 SCARG(uap, sgid),
343 ID_R_EQ_R | ID_R_EQ_E | ID_R_EQ_S |
344 ID_E_EQ_R | ID_E_EQ_E | ID_E_EQ_S |
345 ID_S_EQ_R | ID_S_EQ_E | ID_S_EQ_S );
346 }
347
348 int
349 linux_sys_getresgid(l, v, retval)
350 struct lwp *l;
351 void *v;
352 register_t *retval;
353 {
354 struct linux_sys_getresgid_args /* {
355 syscallarg(gid_t *) rgid;
356 syscallarg(gid_t *) egid;
357 syscallarg(gid_t *) sgid;
358 } */ *uap = v;
359 struct proc *p = l->l_proc;
360 struct pcred *pc = p->p_cred;
361 int error;
362
363 /*
364 * Linux copies these values out to userspace like so:
365 *
366 * 1. Copy out rgid.
367 * 2. If that succeeds, copy out egid.
368 * 3. If both of those succeed, copy out sgid.
369 */
370 if ((error = copyout(&pc->p_rgid, SCARG(uap, rgid),
371 sizeof(gid_t))) != 0)
372 return (error);
373
374 if ((error = copyout(&pc->pc_ucred->cr_gid, SCARG(uap, egid),
375 sizeof(gid_t))) != 0)
376 return (error);
377
378 return (copyout(&pc->p_svgid, SCARG(uap, sgid), sizeof(gid_t)));
379 }
380
381 #ifndef __amd64__
382 /*
383 * I wonder why Linux has settimeofday() _and_ stime().. Still, we
384 * need to deal with it.
385 */
386 int
387 linux_sys_stime(l, v, retval)
388 struct lwp *l;
389 void *v;
390 register_t *retval;
391 {
392 struct linux_sys_time_args /* {
393 linux_time_t *t;
394 } */ *uap = v;
395 struct proc *p = l->l_proc;
396 struct timeval atv;
397 linux_time_t tt;
398 int error;
399
400 if ((error = suser(p->p_ucred, &p->p_acflag)) != 0)
401 return (error);
402
403 if ((error = copyin(&tt, SCARG(uap, t), sizeof tt)) != 0)
404 return error;
405
406 atv.tv_sec = tt;
407 atv.tv_usec = 0;
408
409 if ((error = settime(&atv)))
410 return (error);
411
412 return 0;
413 }
414 #endif /* !amd64 */
415
416 #if !defined(__m68k__)
417 /*
418 * Convert NetBSD statvfs structure to Linux statfs64 structure.
419 * See comments in bsd_to_linux_statfs() for further background.
420 * We can safely pass correct bsize and frsize here, since Linux glibc
421 * statvfs() doesn't use statfs64().
422 */
423 static void
424 bsd_to_linux_statfs64(bsp, lsp)
425 const struct statvfs *bsp;
426 struct linux_statfs64 *lsp;
427 {
428 int i, div;
429
430 for (i = 0; i < linux_fstypes_cnt; i++) {
431 if (strcmp(bsp->f_fstypename, linux_fstypes[i].bsd) == 0) {
432 lsp->l_ftype = linux_fstypes[i].linux;
433 break;
434 }
435 }
436
437 if (i == linux_fstypes_cnt) {
438 DPRINTF(("unhandled fstype in linux emulation: %s\n",
439 bsp->f_fstypename));
440 lsp->l_ftype = LINUX_DEFAULT_SUPER_MAGIC;
441 }
442
443 div = bsp->f_bsize / bsp->f_frsize;
444 lsp->l_fbsize = bsp->f_bsize;
445 lsp->l_ffrsize = bsp->f_frsize;
446 lsp->l_fblocks = bsp->f_blocks / div;
447 lsp->l_fbfree = bsp->f_bfree / div;
448 lsp->l_fbavail = bsp->f_bavail / div;
449 lsp->l_ffiles = bsp->f_files;
450 lsp->l_fffree = bsp->f_ffree / div;
451 /* Linux sets the fsid to 0..., we don't */
452 lsp->l_ffsid.val[0] = bsp->f_fsidx.__fsid_val[0];
453 lsp->l_ffsid.val[1] = bsp->f_fsidx.__fsid_val[1];
454 lsp->l_fnamelen = bsp->f_namemax;
455 (void)memset(lsp->l_fspare, 0, sizeof(lsp->l_fspare));
456 }
457
458 /*
459 * Implement the fs stat functions. Straightforward.
460 */
461 int
462 linux_sys_statfs64(l, v, retval)
463 struct lwp *l;
464 void *v;
465 register_t *retval;
466 {
467 struct linux_sys_statfs64_args /* {
468 syscallarg(const char *) path;
469 syscallarg(size_t) sz;
470 syscallarg(struct linux_statfs64 *) sp;
471 } */ *uap = v;
472 struct proc *p = l->l_proc;
473 struct statvfs btmp, *bsp;
474 struct linux_statfs64 ltmp;
475 struct sys_statvfs1_args bsa;
476 caddr_t sg;
477 int error;
478
479 if (SCARG(uap, sz) != sizeof ltmp)
480 return (EINVAL);
481
482 sg = stackgap_init(p, 0);
483 bsp = (struct statvfs *) stackgap_alloc(p, &sg, sizeof (struct statvfs));
484
485 CHECK_ALT_EXIST(p, &sg, SCARG(uap, path));
486
487 SCARG(&bsa, path) = SCARG(uap, path);
488 SCARG(&bsa, buf) = bsp;
489 SCARG(&bsa, flags) = ST_WAIT;
490
491 if ((error = sys_statvfs1(l, &bsa, retval)))
492 return error;
493
494 if ((error = copyin((caddr_t) bsp, (caddr_t) &btmp, sizeof btmp)))
495 return error;
496
497 bsd_to_linux_statfs64(&btmp, <mp);
498
499 return copyout((caddr_t) <mp, (caddr_t) SCARG(uap, sp), sizeof ltmp);
500 }
501
502 int
503 linux_sys_fstatfs64(l, v, retval)
504 struct lwp *l;
505 void *v;
506 register_t *retval;
507 {
508 struct linux_sys_fstatfs64_args /* {
509 syscallarg(int) fd;
510 syscallarg(size_t) sz;
511 syscallarg(struct linux_statfs64 *) sp;
512 } */ *uap = v;
513 struct proc *p = l->l_proc;
514 struct statvfs btmp, *bsp;
515 struct linux_statfs64 ltmp;
516 struct sys_fstatvfs1_args bsa;
517 caddr_t sg;
518 int error;
519
520 if (SCARG(uap, sz) != sizeof ltmp)
521 return (EINVAL);
522
523 sg = stackgap_init(p, 0);
524 bsp = (struct statvfs *) stackgap_alloc(p, &sg, sizeof (struct statvfs));
525
526 SCARG(&bsa, fd) = SCARG(uap, fd);
527 SCARG(&bsa, buf) = bsp;
528 SCARG(&bsa, flags) = ST_WAIT;
529
530 if ((error = sys_fstatvfs1(l, &bsa, retval)))
531 return error;
532
533 if ((error = copyin((caddr_t) bsp, (caddr_t) &btmp, sizeof btmp)))
534 return error;
535
536 bsd_to_linux_statfs64(&btmp, <mp);
537
538 return copyout((caddr_t) <mp, (caddr_t) SCARG(uap, sp), sizeof ltmp);
539 }
540 #endif /* !__m68k__ */
541