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