linux_misc.c revision 1.83.2.6 1 /* $NetBSD: linux_misc.c,v 1.83.2.6 2001/11/14 19:13:11 nathanw Exp $ */
2
3 /*-
4 * Copyright (c) 1995, 1998, 1999 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 /*
41 * Linux compatibility module. Try to deal with various Linux system calls.
42 */
43
44 /*
45 * These functions have been moved to multiarch to allow
46 * selection of which machines include them to be
47 * determined by the individual files.linux_<arch> files.
48 *
49 * Function in multiarch:
50 * linux_sys_break : linux_break.c
51 * linux_sys_alarm : linux_misc_notalpha.c
52 * linux_sys_getresgid : linux_misc_notalpha.c
53 * linux_sys_nice : linux_misc_notalpha.c
54 * linux_sys_readdir : linux_misc_notalpha.c
55 * linux_sys_setresgid : linux_misc_notalpha.c
56 * linux_sys_time : linux_misc_notalpha.c
57 * linux_sys_utime : linux_misc_notalpha.c
58 * linux_sys_waitpid : linux_misc_notalpha.c
59 * linux_sys_old_mmap : linux_oldmmap.c
60 * linux_sys_oldolduname : linux_oldolduname.c
61 * linux_sys_oldselect : linux_oldselect.c
62 * linux_sys_olduname : linux_olduname.c
63 * linux_sys_pipe : linux_pipe.c
64 */
65
66 #include <sys/cdefs.h>
67 __KERNEL_RCSID(0, "$NetBSD: linux_misc.c,v 1.83.2.6 2001/11/14 19:13:11 nathanw Exp $");
68
69 #include <sys/param.h>
70 #include <sys/systm.h>
71 #include <sys/namei.h>
72 #include <sys/lwp.h>
73 #include <sys/proc.h>
74 #include <sys/dirent.h>
75 #include <sys/file.h>
76 #include <sys/stat.h>
77 #include <sys/filedesc.h>
78 #include <sys/ioctl.h>
79 #include <sys/kernel.h>
80 #include <sys/malloc.h>
81 #include <sys/mbuf.h>
82 #include <sys/mman.h>
83 #include <sys/mount.h>
84 #include <sys/reboot.h>
85 #include <sys/resource.h>
86 #include <sys/resourcevar.h>
87 #include <sys/signal.h>
88 #include <sys/signalvar.h>
89 #include <sys/socket.h>
90 #include <sys/time.h>
91 #include <sys/times.h>
92 #include <sys/vnode.h>
93 #include <sys/uio.h>
94 #include <sys/wait.h>
95 #include <sys/utsname.h>
96 #include <sys/unistd.h>
97 #include <sys/swap.h> /* for SWAP_ON */
98 #include <sys/sysctl.h> /* for KERN_DOMAINNAME */
99
100 #include <sys/ptrace.h>
101 #include <machine/ptrace.h>
102
103 #include <sys/syscallargs.h>
104
105 #include <compat/linux/common/linux_types.h>
106 #include <compat/linux/common/linux_signal.h>
107
108 #include <compat/linux/linux_syscallargs.h>
109
110 #include <compat/linux/common/linux_fcntl.h>
111 #include <compat/linux/common/linux_mmap.h>
112 #include <compat/linux/common/linux_dirent.h>
113 #include <compat/linux/common/linux_util.h>
114 #include <compat/linux/common/linux_misc.h>
115 #include <compat/linux/common/linux_ptrace.h>
116 #include <compat/linux/common/linux_reboot.h>
117 #include <compat/linux/common/linux_emuldata.h>
118
119 const int linux_ptrace_request_map[] = {
120 LINUX_PTRACE_TRACEME, PT_TRACE_ME,
121 LINUX_PTRACE_PEEKTEXT, PT_READ_I,
122 LINUX_PTRACE_PEEKDATA, PT_READ_D,
123 LINUX_PTRACE_POKETEXT, PT_WRITE_I,
124 LINUX_PTRACE_POKEDATA, PT_WRITE_D,
125 LINUX_PTRACE_CONT, PT_CONTINUE,
126 LINUX_PTRACE_KILL, PT_KILL,
127 LINUX_PTRACE_ATTACH, PT_ATTACH,
128 LINUX_PTRACE_DETACH, PT_DETACH,
129 #ifdef PT_STEP
130 LINUX_PTRACE_SINGLESTEP, PT_STEP,
131 #endif
132 -1
133 };
134
135 /* Local linux_misc.c functions: */
136 static void bsd_to_linux_statfs __P((struct statfs *, struct linux_statfs *));
137
138 /*
139 * The information on a terminated (or stopped) process needs
140 * to be converted in order for Linux binaries to get a valid signal
141 * number out of it.
142 */
143 void
144 bsd_to_linux_wstat(st)
145 int *st;
146 {
147
148 int sig;
149
150 if (WIFSIGNALED(*st)) {
151 sig = WTERMSIG(*st);
152 if (sig >= 0 && sig < NSIG)
153 *st= (*st& ~0177) | native_to_linux_sig[sig];
154 } else if (WIFSTOPPED(*st)) {
155 sig = WSTOPSIG(*st);
156 if (sig >= 0 && sig < NSIG)
157 *st = (*st & ~0xff00) | (native_to_linux_sig[sig] << 8);
158 }
159 }
160
161 /*
162 * This is very much the same as waitpid()
163 */
164 int
165 linux_sys_wait4(l, v, retval)
166 struct lwp *l;
167 void *v;
168 register_t *retval;
169 {
170 struct linux_sys_wait4_args /* {
171 syscallarg(int) pid;
172 syscallarg(int *) status;
173 syscallarg(int) options;
174 syscallarg(struct rusage *) rusage;
175 } */ *uap = v;
176 struct proc *p = l->l_proc;
177 struct sys_wait4_args w4a;
178 int error, *status, tstat, options, linux_options;
179 caddr_t sg;
180
181 if (SCARG(uap, status) != NULL) {
182 sg = stackgap_init(p->p_emul);
183 status = (int *) stackgap_alloc(&sg, sizeof *status);
184 } else
185 status = NULL;
186
187 linux_options = SCARG(uap, options);
188 options = 0;
189 if (linux_options &
190 ~(LINUX_WAIT4_WNOHANG|LINUX_WAIT4_WUNTRACED|LINUX_WAIT4_WALL|
191 LINUX_WAIT4_WCLONE))
192 return (EINVAL);
193
194 if (linux_options & LINUX_WAIT4_WNOHANG)
195 options |= WNOHANG;
196 if (linux_options & LINUX_WAIT4_WUNTRACED)
197 options |= WUNTRACED;
198 if (linux_options & LINUX_WAIT4_WALL)
199 options |= WALLSIG;
200 if (linux_options & LINUX_WAIT4_WCLONE)
201 options |= WALTSIG;
202
203 SCARG(&w4a, pid) = SCARG(uap, pid);
204 SCARG(&w4a, status) = status;
205 SCARG(&w4a, options) = options;
206 SCARG(&w4a, rusage) = SCARG(uap, rusage);
207
208 if ((error = sys_wait4(l, &w4a, retval)))
209 return error;
210
211 sigdelset(&p->p_sigctx.ps_siglist, SIGCHLD);
212
213 if (status != NULL) {
214 if ((error = copyin(status, &tstat, sizeof tstat)))
215 return error;
216
217 bsd_to_linux_wstat(&tstat);
218 return copyout(&tstat, SCARG(uap, status), sizeof tstat);
219 }
220
221 return 0;
222 }
223
224 /*
225 * Linux brk(2). The check if the new address is >= the old one is
226 * done in the kernel in Linux. NetBSD does it in the library.
227 */
228 int
229 linux_sys_brk(l, v, retval)
230 struct lwp *l;
231 void *v;
232 register_t *retval;
233 {
234 struct linux_sys_brk_args /* {
235 syscallarg(char *) nsize;
236 } */ *uap = v;
237 struct proc *p = l->l_proc;
238 char *nbrk = SCARG(uap, nsize);
239 struct sys_obreak_args oba;
240 struct vmspace *vm = p->p_vmspace;
241 struct linux_emuldata *ed = (struct linux_emuldata*)p->p_emuldata;
242
243 SCARG(&oba, nsize) = nbrk;
244
245 if ((caddr_t) nbrk > vm->vm_daddr && sys_obreak(l, &oba, retval) == 0)
246 ed->p_break = (char *)nbrk;
247 else
248 nbrk = ed->p_break;
249
250 retval[0] = (register_t)nbrk;
251 return 0;
252 }
253
254 /*
255 * Convert BSD statfs structure to Linux statfs structure.
256 * The Linux structure has less fields, and it also wants
257 * the length of a name in a dir entry in a field, which
258 * we fake (probably the wrong way).
259 */
260 static void
261 bsd_to_linux_statfs(bsp, lsp)
262 struct statfs *bsp;
263 struct linux_statfs *lsp;
264 {
265
266 lsp->l_ftype = bsp->f_type;
267 lsp->l_fbsize = bsp->f_bsize;
268 lsp->l_fblocks = bsp->f_blocks;
269 lsp->l_fbfree = bsp->f_bfree;
270 lsp->l_fbavail = bsp->f_bavail;
271 lsp->l_ffiles = bsp->f_files;
272 lsp->l_fffree = bsp->f_ffree;
273 lsp->l_ffsid.val[0] = bsp->f_fsid.val[0];
274 lsp->l_ffsid.val[1] = bsp->f_fsid.val[1];
275 lsp->l_fnamelen = MAXNAMLEN; /* XXX */
276 }
277
278 /*
279 * Implement the fs stat functions. Straightforward.
280 */
281 int
282 linux_sys_statfs(l, v, retval)
283 struct lwp *l;
284 void *v;
285 register_t *retval;
286 {
287 struct linux_sys_statfs_args /* {
288 syscallarg(const char *) path;
289 syscallarg(struct linux_statfs *) sp;
290 } */ *uap = v;
291 struct proc *p = l->l_proc;
292 struct statfs btmp, *bsp;
293 struct linux_statfs ltmp;
294 struct sys_statfs_args bsa;
295 caddr_t sg;
296 int error;
297
298 sg = stackgap_init(p->p_emul);
299 bsp = (struct statfs *) stackgap_alloc(&sg, sizeof (struct statfs));
300
301 CHECK_ALT_EXIST(p, &sg, SCARG(uap, path));
302
303 SCARG(&bsa, path) = SCARG(uap, path);
304 SCARG(&bsa, buf) = bsp;
305
306 if ((error = sys_statfs(l, &bsa, retval)))
307 return error;
308
309 if ((error = copyin((caddr_t) bsp, (caddr_t) &btmp, sizeof btmp)))
310 return error;
311
312 bsd_to_linux_statfs(&btmp, <mp);
313
314 return copyout((caddr_t) <mp, (caddr_t) SCARG(uap, sp), sizeof ltmp);
315 }
316
317 int
318 linux_sys_fstatfs(l, v, retval)
319 struct lwp *l;
320 void *v;
321 register_t *retval;
322 {
323 struct linux_sys_fstatfs_args /* {
324 syscallarg(int) fd;
325 syscallarg(struct linux_statfs *) sp;
326 } */ *uap = v;
327 struct proc *p = l->l_proc;
328 struct statfs btmp, *bsp;
329 struct linux_statfs ltmp;
330 struct sys_fstatfs_args bsa;
331 caddr_t sg;
332 int error;
333
334 sg = stackgap_init(p->p_emul);
335 bsp = (struct statfs *) stackgap_alloc(&sg, sizeof (struct statfs));
336
337 SCARG(&bsa, fd) = SCARG(uap, fd);
338 SCARG(&bsa, buf) = bsp;
339
340 if ((error = sys_fstatfs(l, &bsa, retval)))
341 return error;
342
343 if ((error = copyin((caddr_t) bsp, (caddr_t) &btmp, sizeof btmp)))
344 return error;
345
346 bsd_to_linux_statfs(&btmp, <mp);
347
348 return copyout((caddr_t) <mp, (caddr_t) SCARG(uap, sp), sizeof ltmp);
349 }
350
351 char linux_sysname[] = "Linux";
352 char linux_release[] = "2.0.38";
353 char linux_version[] = "#0 Sun Apr 1 11:11:11 MET 2000";
354
355 /*
356 * uname(). Just copy the info from the various strings stored in the
357 * kernel, and put it in the Linux utsname structure. That structure
358 * is almost the same as the NetBSD one, only it has fields 65 characters
359 * long, and an extra domainname field.
360 */
361 int
362 linux_sys_uname(l, v, retval)
363 struct lwp *l;
364 void *v;
365 register_t *retval;
366 {
367 struct linux_sys_uname_args /* {
368 syscallarg(struct linux_utsname *) up;
369 } */ *uap = v;
370 struct linux_utsname luts;
371
372 strncpy(luts.l_sysname, linux_sysname, sizeof(luts.l_sysname));
373 strncpy(luts.l_nodename, hostname, sizeof(luts.l_nodename));
374 strncpy(luts.l_release, linux_release, sizeof(luts.l_release));
375 strncpy(luts.l_version, linux_version, sizeof(luts.l_version));
376 strncpy(luts.l_machine, machine, sizeof(luts.l_machine));
377 strncpy(luts.l_domainname, domainname, sizeof(luts.l_domainname));
378
379 return copyout(&luts, SCARG(uap, up), sizeof(luts));
380 }
381
382 /* Used directly on: alpha, mips, ppc, sparc, sparc64 */
383 /* Used indirectly on: arm, i386, m68k */
384
385 /*
386 * New type Linux mmap call.
387 * Only called directly on machines with >= 6 free regs.
388 */
389 int
390 linux_sys_mmap(l, v, retval)
391 struct lwp *l;
392 void *v;
393 register_t *retval;
394 {
395 struct linux_sys_mmap_args /* {
396 syscallarg(unsigned long) addr;
397 syscallarg(size_t) len;
398 syscallarg(int) prot;
399 syscallarg(int) flags;
400 syscallarg(int) fd;
401 syscallarg(linux_off_t) offset;
402 } */ *uap = v;
403 struct sys_mmap_args cma;
404 int flags;
405
406 flags = 0;
407 flags |= cvtto_bsd_mask(SCARG(uap,flags), LINUX_MAP_SHARED, MAP_SHARED);
408 flags |= cvtto_bsd_mask(SCARG(uap,flags), LINUX_MAP_PRIVATE, MAP_PRIVATE);
409 flags |= cvtto_bsd_mask(SCARG(uap,flags), LINUX_MAP_FIXED, MAP_FIXED);
410 flags |= cvtto_bsd_mask(SCARG(uap,flags), LINUX_MAP_ANON, MAP_ANON);
411 /* XXX XAX ERH: Any other flags here? There are more defined... */
412
413 SCARG(&cma,addr) = (void *)SCARG(uap, addr);
414 SCARG(&cma,len) = SCARG(uap, len);
415 SCARG(&cma,prot) = SCARG(uap, prot);
416 if (SCARG(&cma,prot) & VM_PROT_WRITE) /* XXX */
417 SCARG(&cma,prot) |= VM_PROT_READ;
418 SCARG(&cma,flags) = flags;
419 SCARG(&cma,fd) = flags & MAP_ANON ? -1 : SCARG(uap, fd);
420 SCARG(&cma,pad) = 0;
421 SCARG(&cma,pos) = (off_t)SCARG(uap, offset);
422
423 return sys_mmap(l, &cma, retval);
424 }
425
426 int
427 linux_sys_mremap(l, v, retval)
428 struct lwp *l;
429 void *v;
430 register_t *retval;
431 {
432 struct linux_sys_mremap_args /* {
433 syscallarg(void *) old_address;
434 syscallarg(size_t) old_size;
435 syscallarg(size_t) new_size;
436 syscallarg(u_long) flags;
437 } */ *uap = v;
438 struct sys_munmap_args mua;
439 size_t old_size, new_size;
440 int error;
441
442 old_size = round_page(SCARG(uap, old_size));
443 new_size = round_page(SCARG(uap, new_size));
444
445 /*
446 * Growing mapped region.
447 */
448 if (new_size > old_size) {
449 /*
450 * XXX Implement me. What we probably want to do is
451 * XXX dig out the guts of the old mapping, mmap that
452 * XXX object again with the new size, then munmap
453 * XXX the old mapping.
454 */
455 *retval = 0;
456 return (ENOMEM);
457 }
458
459 /*
460 * Shrinking mapped region.
461 */
462 if (new_size < old_size) {
463 SCARG(&mua, addr) = (caddr_t)SCARG(uap, old_address) +
464 new_size;
465 SCARG(&mua, len) = old_size - new_size;
466 error = sys_munmap(l, &mua, retval);
467 *retval = error ? 0 : (register_t)SCARG(uap, old_address);
468 return (error);
469 }
470
471 /*
472 * No change.
473 */
474 *retval = (register_t)SCARG(uap, old_address);
475 return (0);
476 }
477
478 int
479 linux_sys_msync(l, v, retval)
480 struct lwp *l;
481 void *v;
482 register_t *retval;
483 {
484 struct linux_sys_msync_args /* {
485 syscallarg(caddr_t) addr;
486 syscallarg(int) len;
487 syscallarg(int) fl;
488 } */ *uap = v;
489
490 struct sys___msync13_args bma;
491
492 /* flags are ignored */
493 SCARG(&bma, addr) = SCARG(uap, addr);
494 SCARG(&bma, len) = SCARG(uap, len);
495 SCARG(&bma, flags) = SCARG(uap, fl);
496
497 return sys___msync13(l, &bma, retval);
498 }
499
500 /*
501 * This code is partly stolen from src/lib/libc/compat-43/times.c
502 * XXX - CLK_TCK isn't declared in /sys, just in <time.h>, done here
503 */
504
505 #define CLK_TCK 100
506 #define CONVTCK(r) (r.tv_sec * CLK_TCK + r.tv_usec / (1000000 / CLK_TCK))
507
508 int
509 linux_sys_times(l, v, retval)
510 struct lwp *l;
511 void *v;
512 register_t *retval;
513 {
514 struct linux_sys_times_args /* {
515 syscallarg(struct times *) tms;
516 } */ *uap = v;
517 struct proc *p = l->l_proc;
518 struct timeval t;
519 struct linux_tms ltms;
520 struct rusage ru;
521 int error, s;
522
523 calcru(p, &ru.ru_utime, &ru.ru_stime, NULL);
524 ltms.ltms_utime = CONVTCK(ru.ru_utime);
525 ltms.ltms_stime = CONVTCK(ru.ru_stime);
526
527 ltms.ltms_cutime = CONVTCK(p->p_stats->p_cru.ru_utime);
528 ltms.ltms_cstime = CONVTCK(p->p_stats->p_cru.ru_stime);
529
530 if ((error = copyout(<ms, SCARG(uap, tms), sizeof ltms)))
531 return error;
532
533 s = splclock();
534 timersub(&time, &boottime, &t);
535 splx(s);
536
537 retval[0] = ((linux_clock_t)(CONVTCK(t)));
538 return 0;
539 }
540
541 /*
542 * Linux 'readdir' call. This code is mostly taken from the
543 * SunOS getdents call (see compat/sunos/sunos_misc.c), though
544 * an attempt has been made to keep it a little cleaner (failing
545 * miserably, because of the cruft needed if count 1 is passed).
546 *
547 * The d_off field should contain the offset of the next valid entry,
548 * but in Linux it has the offset of the entry itself. We emulate
549 * that bug here.
550 *
551 * Read in BSD-style entries, convert them, and copy them out.
552 *
553 * Note that this doesn't handle union-mounted filesystems.
554 */
555 int
556 linux_sys_getdents(l, v, retval)
557 struct lwp *l;
558 void *v;
559 register_t *retval;
560 {
561 struct linux_sys_getdents_args /* {
562 syscallarg(int) fd;
563 syscallarg(struct linux_dirent *) dent;
564 syscallarg(unsigned int) count;
565 } */ *uap = v;
566 struct proc *p = l->l_proc;
567 struct dirent *bdp;
568 struct vnode *vp;
569 caddr_t inp, buf; /* BSD-format */
570 int len, reclen; /* BSD-format */
571 caddr_t outp; /* Linux-format */
572 int resid, linux_reclen = 0; /* Linux-format */
573 struct file *fp;
574 struct uio auio;
575 struct iovec aiov;
576 struct linux_dirent idb;
577 off_t off; /* true file offset */
578 int buflen, error, eofflag, nbytes, oldcall;
579 struct vattr va;
580 off_t *cookiebuf = NULL, *cookie;
581 int ncookies;
582
583 /* getvnode() will use the descriptor for us */
584 if ((error = getvnode(p->p_fd, SCARG(uap, fd), &fp)) != 0)
585 return (error);
586
587 if ((fp->f_flag & FREAD) == 0) {
588 error = EBADF;
589 goto out1;
590 }
591
592 vp = (struct vnode *)fp->f_data;
593 if (vp->v_type != VDIR) {
594 error = EINVAL;
595 goto out1;
596 }
597
598 if ((error = VOP_GETATTR(vp, &va, p->p_ucred, p)))
599 goto out1;
600
601 nbytes = SCARG(uap, count);
602 if (nbytes == 1) { /* emulating old, broken behaviour */
603 nbytes = sizeof (struct linux_dirent);
604 buflen = max(va.va_blocksize, nbytes);
605 oldcall = 1;
606 } else {
607 buflen = min(MAXBSIZE, nbytes);
608 if (buflen < va.va_blocksize)
609 buflen = va.va_blocksize;
610 oldcall = 0;
611 }
612 buf = malloc(buflen, M_TEMP, M_WAITOK);
613
614 vn_lock(vp, LK_EXCLUSIVE | LK_RETRY);
615 off = fp->f_offset;
616 again:
617 aiov.iov_base = buf;
618 aiov.iov_len = buflen;
619 auio.uio_iov = &aiov;
620 auio.uio_iovcnt = 1;
621 auio.uio_rw = UIO_READ;
622 auio.uio_segflg = UIO_SYSSPACE;
623 auio.uio_procp = p;
624 auio.uio_resid = buflen;
625 auio.uio_offset = off;
626 /*
627 * First we read into the malloc'ed buffer, then
628 * we massage it into user space, one record at a time.
629 */
630 error = VOP_READDIR(vp, &auio, fp->f_cred, &eofflag, &cookiebuf,
631 &ncookies);
632 if (error)
633 goto out;
634
635 inp = buf;
636 outp = (caddr_t)SCARG(uap, dent);
637 resid = nbytes;
638 if ((len = buflen - auio.uio_resid) == 0)
639 goto eof;
640
641 for (cookie = cookiebuf; len > 0; len -= reclen) {
642 bdp = (struct dirent *)inp;
643 reclen = bdp->d_reclen;
644 if (reclen & 3)
645 panic("linux_readdir");
646 if (bdp->d_fileno == 0) {
647 inp += reclen; /* it is a hole; squish it out */
648 off = *cookie++;
649 continue;
650 }
651 linux_reclen = LINUX_RECLEN(&idb, bdp->d_namlen);
652 if (reclen > len || resid < linux_reclen) {
653 /* entry too big for buffer, so just stop */
654 outp++;
655 break;
656 }
657 /*
658 * Massage in place to make a Linux-shaped dirent (otherwise
659 * we have to worry about touching user memory outside of
660 * the copyout() call).
661 */
662 idb.d_ino = (linux_ino_t)bdp->d_fileno;
663 /*
664 * The old readdir() call misuses the offset and reclen fields.
665 */
666 if (oldcall) {
667 idb.d_off = (linux_off_t)linux_reclen;
668 idb.d_reclen = (u_short)bdp->d_namlen;
669 } else {
670 if (sizeof (linux_off_t) < 4 && (off >> 32) != 0) {
671 compat_offseterr(vp, "linux_getdents");
672 error = EINVAL;
673 goto out;
674 }
675 idb.d_off = (linux_off_t)off;
676 idb.d_reclen = (u_short)linux_reclen;
677 }
678 strcpy(idb.d_name, bdp->d_name);
679 if ((error = copyout((caddr_t)&idb, outp, linux_reclen)))
680 goto out;
681 /* advance past this real entry */
682 inp += reclen;
683 off = *cookie++; /* each entry points to itself */
684 /* advance output past Linux-shaped entry */
685 outp += linux_reclen;
686 resid -= linux_reclen;
687 if (oldcall)
688 break;
689 }
690
691 /* if we squished out the whole block, try again */
692 if (outp == (caddr_t)SCARG(uap, dent))
693 goto again;
694 fp->f_offset = off; /* update the vnode offset */
695
696 if (oldcall)
697 nbytes = resid + linux_reclen;
698
699 eof:
700 *retval = nbytes - resid;
701 out:
702 VOP_UNLOCK(vp, 0);
703 if (cookiebuf)
704 free(cookiebuf, M_TEMP);
705 free(buf, M_TEMP);
706 out1:
707 FILE_UNUSE(fp, p);
708 return error;
709 }
710
711 /*
712 * Even when just using registers to pass arguments to syscalls you can
713 * have 5 of them on the i386. So this newer version of select() does
714 * this.
715 */
716 int
717 linux_sys_select(l, v, retval)
718 struct lwp *l;
719 void *v;
720 register_t *retval;
721 {
722 struct linux_sys_select_args /* {
723 syscallarg(int) nfds;
724 syscallarg(fd_set *) readfds;
725 syscallarg(fd_set *) writefds;
726 syscallarg(fd_set *) exceptfds;
727 syscallarg(struct timeval *) timeout;
728 } */ *uap = v;
729
730 return linux_select1(l, retval, SCARG(uap, nfds), SCARG(uap, readfds),
731 SCARG(uap, writefds), SCARG(uap, exceptfds), SCARG(uap, timeout));
732 }
733
734 /*
735 * Common code for the old and new versions of select(). A couple of
736 * things are important:
737 * 1) return the amount of time left in the 'timeout' parameter
738 * 2) select never returns ERESTART on Linux, always return EINTR
739 */
740 int
741 linux_select1(l, retval, nfds, readfds, writefds, exceptfds, timeout)
742 struct lwp *l;
743 register_t *retval;
744 int nfds;
745 fd_set *readfds, *writefds, *exceptfds;
746 struct timeval *timeout;
747 {
748 struct sys_select_args bsa;
749 struct proc *p = l->l_proc;
750 struct timeval tv0, tv1, utv, *tvp;
751 caddr_t sg;
752 int error;
753
754 SCARG(&bsa, nd) = nfds;
755 SCARG(&bsa, in) = readfds;
756 SCARG(&bsa, ou) = writefds;
757 SCARG(&bsa, ex) = exceptfds;
758 SCARG(&bsa, tv) = timeout;
759
760 /*
761 * Store current time for computation of the amount of
762 * time left.
763 */
764 if (timeout) {
765 if ((error = copyin(timeout, &utv, sizeof(utv))))
766 return error;
767 if (itimerfix(&utv)) {
768 /*
769 * The timeval was invalid. Convert it to something
770 * valid that will act as it does under Linux.
771 */
772 sg = stackgap_init(p->p_emul);
773 tvp = stackgap_alloc(&sg, sizeof(utv));
774 utv.tv_sec += utv.tv_usec / 1000000;
775 utv.tv_usec %= 1000000;
776 if (utv.tv_usec < 0) {
777 utv.tv_sec -= 1;
778 utv.tv_usec += 1000000;
779 }
780 if (utv.tv_sec < 0)
781 timerclear(&utv);
782 if ((error = copyout(&utv, tvp, sizeof(utv))))
783 return error;
784 SCARG(&bsa, tv) = tvp;
785 }
786 microtime(&tv0);
787 }
788
789 error = sys_select(l, &bsa, retval);
790 if (error) {
791 /*
792 * See fs/select.c in the Linux kernel. Without this,
793 * Maelstrom doesn't work.
794 */
795 if (error == ERESTART)
796 error = EINTR;
797 return error;
798 }
799
800 if (timeout) {
801 if (*retval) {
802 /*
803 * Compute how much time was left of the timeout,
804 * by subtracting the current time and the time
805 * before we started the call, and subtracting
806 * that result from the user-supplied value.
807 */
808 microtime(&tv1);
809 timersub(&tv1, &tv0, &tv1);
810 timersub(&utv, &tv1, &utv);
811 if (utv.tv_sec < 0)
812 timerclear(&utv);
813 } else
814 timerclear(&utv);
815 if ((error = copyout(&utv, timeout, sizeof(utv))))
816 return error;
817 }
818
819 return 0;
820 }
821
822 /*
823 * Get the process group of a certain process. Look it up
824 * and return the value.
825 */
826 int
827 linux_sys_getpgid(l, v, retval)
828 struct lwp *l;
829 void *v;
830 register_t *retval;
831 {
832 struct linux_sys_getpgid_args /* {
833 syscallarg(int) pid;
834 } */ *uap = v;
835 struct proc *p = l->l_proc;
836 struct proc *targp;
837
838 if (SCARG(uap, pid) != 0 && SCARG(uap, pid) != p->p_pid) {
839 if ((targp = pfind(SCARG(uap, pid))) == 0)
840 return ESRCH;
841 }
842 else
843 targp = p;
844
845 retval[0] = targp->p_pgid;
846 return 0;
847 }
848
849 /*
850 * Set the 'personality' (emulation mode) for the current process. Only
851 * accept the Linux personality here (0). This call is needed because
852 * the Linux ELF crt0 issues it in an ugly kludge to make sure that
853 * ELF binaries run in Linux mode, not SVR4 mode.
854 */
855 int
856 linux_sys_personality(l, v, retval)
857 struct lwp *l;
858 void *v;
859 register_t *retval;
860 {
861 struct linux_sys_personality_args /* {
862 syscallarg(int) per;
863 } */ *uap = v;
864
865 if (SCARG(uap, per) != 0)
866 return EINVAL;
867 retval[0] = 0;
868 return 0;
869 }
870
871 #if defined(__i386__) || defined(__m68k__)
872 /*
873 * The calls are here because of type conversions.
874 */
875 int
876 linux_sys_setreuid16(l, v, retval)
877 struct lwp *l;
878 void *v;
879 register_t *retval;
880 {
881 struct linux_sys_setreuid16_args /* {
882 syscallarg(int) ruid;
883 syscallarg(int) euid;
884 } */ *uap = v;
885 struct sys_setreuid_args bsa;
886
887 SCARG(&bsa, ruid) = ((linux_uid_t)SCARG(uap, ruid) == (linux_uid_t)-1) ?
888 (uid_t)-1 : SCARG(uap, ruid);
889 SCARG(&bsa, euid) = ((linux_uid_t)SCARG(uap, euid) == (linux_uid_t)-1) ?
890 (uid_t)-1 : SCARG(uap, euid);
891
892 return sys_setreuid(l, &bsa, retval);
893 }
894
895 int
896 linux_sys_setregid16(l, v, retval)
897 struct lwp *l;
898 void *v;
899 register_t *retval;
900 {
901 struct linux_sys_setregid16_args /* {
902 syscallarg(int) rgid;
903 syscallarg(int) egid;
904 } */ *uap = v;
905 struct sys_setregid_args bsa;
906
907 SCARG(&bsa, rgid) = ((linux_gid_t)SCARG(uap, rgid) == (linux_gid_t)-1) ?
908 (uid_t)-1 : SCARG(uap, rgid);
909 SCARG(&bsa, egid) = ((linux_gid_t)SCARG(uap, egid) == (linux_gid_t)-1) ?
910 (uid_t)-1 : SCARG(uap, egid);
911
912 return sys_setregid(l, &bsa, retval);
913 }
914
915 int
916 linux_sys_setresuid16(l, v, retval)
917 struct lwp *l;
918 void *v;
919 register_t *retval;
920 {
921 struct linux_sys_setresuid16_args /* {
922 syscallarg(uid_t) ruid;
923 syscallarg(uid_t) euid;
924 syscallarg(uid_t) suid;
925 } */ *uap = v;
926 struct linux_sys_setresuid16_args lsa;
927
928 SCARG(&lsa, ruid) = ((linux_uid_t)SCARG(uap, ruid) == (linux_uid_t)-1) ?
929 (uid_t)-1 : SCARG(uap, ruid);
930 SCARG(&lsa, euid) = ((linux_uid_t)SCARG(uap, euid) == (linux_uid_t)-1) ?
931 (uid_t)-1 : SCARG(uap, euid);
932 SCARG(&lsa, suid) = ((linux_uid_t)SCARG(uap, suid) == (linux_uid_t)-1) ?
933 (uid_t)-1 : SCARG(uap, suid);
934
935 return linux_sys_setresuid(l, &lsa, retval);
936 }
937
938 int
939 linux_sys_setresgid16(l, v, retval)
940 struct lwp *l;
941 void *v;
942 register_t *retval;
943 {
944 struct linux_sys_setresgid16_args /* {
945 syscallarg(gid_t) rgid;
946 syscallarg(gid_t) egid;
947 syscallarg(gid_t) sgid;
948 } */ *uap = v;
949 struct linux_sys_setresgid16_args lsa;
950
951 SCARG(&lsa, rgid) = ((linux_gid_t)SCARG(uap, rgid) == (linux_gid_t)-1) ?
952 (gid_t)-1 : SCARG(uap, rgid);
953 SCARG(&lsa, egid) = ((linux_gid_t)SCARG(uap, egid) == (linux_gid_t)-1) ?
954 (gid_t)-1 : SCARG(uap, egid);
955 SCARG(&lsa, sgid) = ((linux_gid_t)SCARG(uap, sgid) == (linux_gid_t)-1) ?
956 (gid_t)-1 : SCARG(uap, sgid);
957
958 return linux_sys_setresgid(l, &lsa, retval);
959 }
960
961 int
962 linux_sys_getgroups16(l, v, retval)
963 struct lwp *l;
964 void *v;
965 register_t *retval;
966 {
967 struct linux_sys_getgroups16_args /* {
968 syscallarg(int) gidsetsize;
969 syscallarg(linux_gid_t *) gidset;
970 } */ *uap = v;
971 struct proc *p = l->l_proc;
972 caddr_t sg;
973 int n, error, i;
974 struct sys_getgroups_args bsa;
975 gid_t *bset, *kbset;
976 linux_gid_t *lset;
977 struct pcred *pc = p->p_cred;
978
979 n = SCARG(uap, gidsetsize);
980 if (n < 0)
981 return EINVAL;
982 error = 0;
983 bset = kbset = NULL;
984 lset = NULL;
985 if (n > 0) {
986 n = min(pc->pc_ucred->cr_ngroups, n);
987 sg = stackgap_init(p->p_emul);
988 bset = stackgap_alloc(&sg, n * sizeof (gid_t));
989 kbset = malloc(n * sizeof (gid_t), M_TEMP, M_WAITOK);
990 lset = malloc(n * sizeof (linux_gid_t), M_TEMP, M_WAITOK);
991 if (bset == NULL || kbset == NULL || lset == NULL)
992 return ENOMEM;
993 SCARG(&bsa, gidsetsize) = n;
994 SCARG(&bsa, gidset) = bset;
995 error = sys_getgroups(l, &bsa, retval);
996 if (error != 0)
997 goto out;
998 error = copyin(bset, kbset, n * sizeof (gid_t));
999 if (error != 0)
1000 goto out;
1001 for (i = 0; i < n; i++)
1002 lset[i] = (linux_gid_t)kbset[i];
1003 error = copyout(lset, SCARG(uap, gidset),
1004 n * sizeof (linux_gid_t));
1005 } else
1006 *retval = pc->pc_ucred->cr_ngroups;
1007 out:
1008 if (kbset != NULL)
1009 free(kbset, M_TEMP);
1010 if (lset != NULL)
1011 free(lset, M_TEMP);
1012 return error;
1013 }
1014
1015 int
1016 linux_sys_setgroups16(l, v, retval)
1017 struct lwp *l;
1018 void *v;
1019 register_t *retval;
1020 {
1021 struct linux_sys_setgroups16_args /* {
1022 syscallarg(int) gidsetsize;
1023 syscallarg(linux_gid_t *) gidset;
1024 } */ *uap = v;
1025 struct proc *p = l->l_proc;
1026 caddr_t sg;
1027 int n;
1028 int error, i;
1029 struct sys_setgroups_args bsa;
1030 gid_t *bset, *kbset;
1031 linux_gid_t *lset;
1032
1033 n = SCARG(uap, gidsetsize);
1034 if (n < 0 || n > NGROUPS)
1035 return EINVAL;
1036 sg = stackgap_init(p->p_emul);
1037 bset = stackgap_alloc(&sg, n * sizeof (gid_t));
1038 lset = malloc(n * sizeof (linux_gid_t), M_TEMP, M_WAITOK);
1039 kbset = malloc(n * sizeof (linux_gid_t), M_TEMP, M_WAITOK);
1040 if (lset == NULL || bset == NULL)
1041 return ENOMEM;
1042 error = copyin(SCARG(uap, gidset), lset, n * sizeof (linux_gid_t));
1043 if (error != 0)
1044 goto out;
1045 for (i = 0; i < n; i++)
1046 kbset[i] = (gid_t)lset[i];
1047 error = copyout(kbset, bset, n * sizeof (gid_t));
1048 if (error != 0)
1049 goto out;
1050 SCARG(&bsa, gidsetsize) = n;
1051 SCARG(&bsa, gidset) = bset;
1052 error = sys_setgroups(l, &bsa, retval);
1053
1054 out:
1055 if (lset != NULL)
1056 free(lset, M_TEMP);
1057 if (kbset != NULL)
1058 free(kbset, M_TEMP);
1059
1060 return error;
1061 }
1062
1063 #endif /* __i386__ || __m68k__ */
1064
1065 /*
1066 * We have nonexistent fsuid equal to uid.
1067 * If modification is requested, refuse.
1068 */
1069 int
1070 linux_sys_setfsuid(l, v, retval)
1071 struct lwp *l;
1072 void *v;
1073 register_t *retval;
1074 {
1075 struct linux_sys_setfsuid_args /* {
1076 syscallarg(uid_t) uid;
1077 } */ *uap = v;
1078 struct proc *p = l->l_proc;
1079 uid_t uid;
1080
1081 uid = SCARG(uap, uid);
1082 if (p->p_cred->p_ruid != uid)
1083 return sys_nosys(l, v, retval);
1084 else
1085 return (0);
1086 }
1087
1088 /* XXX XXX XXX */
1089 #ifndef alpha
1090 int
1091 linux_sys_getfsuid(l, v, retval)
1092 struct lwp *l;
1093 void *v;
1094 register_t *retval;
1095 {
1096 return sys_getuid(l, v, retval);
1097 }
1098 #endif
1099
1100 int
1101 linux_sys___sysctl(l, v, retval)
1102 struct lwp *l;
1103 void *v;
1104 register_t *retval;
1105 {
1106 struct linux_sys___sysctl_args /* {
1107 syscallarg(struct linux___sysctl *) lsp;
1108 } */ *uap = v;
1109 struct linux___sysctl ls;
1110 struct sys___sysctl_args bsa;
1111 int error;
1112
1113 if ((error = copyin(SCARG(uap, lsp), &ls, sizeof ls)))
1114 return error;
1115 SCARG(&bsa, name) = ls.name;
1116 SCARG(&bsa, namelen) = ls.namelen;
1117 SCARG(&bsa, old) = ls.old;
1118 SCARG(&bsa, oldlenp) = ls.oldlenp;
1119 SCARG(&bsa, new) = ls.new;
1120 SCARG(&bsa, newlen) = ls.newlen;
1121
1122 return sys___sysctl(l, &bsa, retval);
1123 }
1124
1125 int
1126 linux_sys_setresuid(l, v, retval)
1127 struct lwp *l;
1128 void *v;
1129 register_t *retval;
1130 {
1131 struct linux_sys_setresuid_args /* {
1132 syscallarg(uid_t) ruid;
1133 syscallarg(uid_t) euid;
1134 syscallarg(uid_t) suid;
1135 } */ *uap = v;
1136 struct proc *p = l->l_proc;
1137 struct pcred *pc = p->p_cred;
1138 uid_t ruid, euid, suid;
1139 int error;
1140
1141 ruid = SCARG(uap, ruid);
1142 euid = SCARG(uap, euid);
1143 suid = SCARG(uap, suid);
1144
1145 /*
1146 * Note: These checks are a little different than the NetBSD
1147 * setreuid(2) call performs. This precisely follows the
1148 * behavior of the Linux kernel.
1149 */
1150 if (ruid != (uid_t)-1 &&
1151 ruid != pc->p_ruid &&
1152 ruid != pc->pc_ucred->cr_uid &&
1153 ruid != pc->p_svuid &&
1154 (error = suser(pc->pc_ucred, &p->p_acflag)))
1155 return (error);
1156
1157 if (euid != (uid_t)-1 &&
1158 euid != pc->p_ruid &&
1159 euid != pc->pc_ucred->cr_uid &&
1160 euid != pc->p_svuid &&
1161 (error = suser(pc->pc_ucred, &p->p_acflag)))
1162 return (error);
1163
1164 if (suid != (uid_t)-1 &&
1165 suid != pc->p_ruid &&
1166 suid != pc->pc_ucred->cr_uid &&
1167 suid != pc->p_svuid &&
1168 (error = suser(pc->pc_ucred, &p->p_acflag)))
1169 return (error);
1170
1171 /*
1172 * Now assign the new real, effective, and saved UIDs.
1173 * Note that Linux, unlike NetBSD in setreuid(2), does not
1174 * set the saved UID in this call unless the user specifies
1175 * it.
1176 */
1177 if (ruid != (uid_t)-1) {
1178 (void)chgproccnt(pc->p_ruid, -1);
1179 (void)chgproccnt(ruid, 1);
1180 pc->p_ruid = ruid;
1181 }
1182
1183 if (euid != (uid_t)-1) {
1184 pc->pc_ucred = crcopy(pc->pc_ucred);
1185 pc->pc_ucred->cr_uid = euid;
1186 }
1187
1188 if (suid != (uid_t)-1)
1189 pc->p_svuid = suid;
1190
1191 if (ruid != (uid_t)-1 && euid != (uid_t)-1 && suid != (uid_t)-1)
1192 p->p_flag |= P_SUGID;
1193 return (0);
1194 }
1195
1196 int
1197 linux_sys_getresuid(l, v, retval)
1198 struct lwp *l;
1199 void *v;
1200 register_t *retval;
1201 {
1202 struct linux_sys_getresuid_args /* {
1203 syscallarg(uid_t *) ruid;
1204 syscallarg(uid_t *) euid;
1205 syscallarg(uid_t *) suid;
1206 } */ *uap = v;
1207 struct proc *p = l->l_proc;
1208 struct pcred *pc = p->p_cred;
1209 int error;
1210
1211 /*
1212 * Linux copies these values out to userspace like so:
1213 *
1214 * 1. Copy out ruid.
1215 * 2. If that succeeds, copy out euid.
1216 * 3. If both of those succeed, copy out suid.
1217 */
1218 if ((error = copyout(&pc->p_ruid, SCARG(uap, ruid),
1219 sizeof(uid_t))) != 0)
1220 return (error);
1221
1222 if ((error = copyout(&pc->pc_ucred->cr_uid, SCARG(uap, euid),
1223 sizeof(uid_t))) != 0)
1224 return (error);
1225
1226 return (copyout(&pc->p_svuid, SCARG(uap, suid), sizeof(uid_t)));
1227 }
1228
1229 int
1230 linux_sys_ptrace(l, v, retval)
1231 struct lwp *l;
1232 void *v;
1233 register_t *retval;
1234 {
1235 struct linux_sys_ptrace_args /* {
1236 i386, m68k, powerpc: T=int
1237 alpha: T=long
1238 syscallarg(T) request;
1239 syscallarg(T) pid;
1240 syscallarg(T) addr;
1241 syscallarg(T) data;
1242 } */ *uap = v;
1243 const int *ptr;
1244 int request;
1245 int error;
1246
1247 ptr = linux_ptrace_request_map;
1248 request = SCARG(uap, request);
1249 while (*ptr != -1)
1250 if (*ptr++ == request) {
1251 struct sys_ptrace_args pta;
1252
1253 SCARG(&pta, req) = *ptr;
1254 SCARG(&pta, pid) = SCARG(uap, pid);
1255 SCARG(&pta, addr) = (caddr_t)SCARG(uap, addr);
1256 SCARG(&pta, data) = SCARG(uap, data);
1257
1258 /*
1259 * Linux ptrace(PTRACE_CONT, pid, 0, 0) means actually
1260 * to continue where the process left off previously.
1261 * The same thing is achieved by addr == (caddr_t) 1
1262 * on NetBSD, so rewrite 'addr' appropriately.
1263 */
1264 if (request == LINUX_PTRACE_CONT && SCARG(uap, addr)==0)
1265 SCARG(&pta, addr) = (caddr_t) 1;
1266
1267 error = sys_ptrace(l, &pta, retval);
1268 if (error)
1269 return error;
1270 switch (request) {
1271 case LINUX_PTRACE_PEEKTEXT:
1272 case LINUX_PTRACE_PEEKDATA:
1273 error = copyout (retval,
1274 (caddr_t)SCARG(uap, data), sizeof *retval);
1275 *retval = SCARG(uap, data);
1276 break;
1277 default:
1278 break;
1279 }
1280 return error;
1281 }
1282 else
1283 ptr++;
1284
1285 return LINUX_SYS_PTRACE_ARCH(l, uap, retval);
1286 }
1287
1288 int
1289 linux_sys_reboot(struct lwp *l, void *v, register_t *retval)
1290 {
1291 struct linux_sys_reboot_args /* {
1292 syscallarg(int) magic1;
1293 syscallarg(int) magic2;
1294 syscallarg(int) cmd;
1295 syscallarg(void *) arg;
1296 } */ *uap = v;
1297 struct sys_reboot_args /* {
1298 syscallarg(int) opt;
1299 syscallarg(char *) bootstr;
1300 } */ sra;
1301 struct proc *p = l->l_proc;
1302 int error;
1303
1304 if ((error = suser(p->p_ucred, &p->p_acflag)) != 0)
1305 return(error);
1306
1307 if (SCARG(uap, magic1) != LINUX_REBOOT_MAGIC1)
1308 return(EINVAL);
1309 if (SCARG(uap, magic2) != LINUX_REBOOT_MAGIC2 &&
1310 SCARG(uap, magic2) != LINUX_REBOOT_MAGIC2A &&
1311 SCARG(uap, magic2) != LINUX_REBOOT_MAGIC2B)
1312 return(EINVAL);
1313
1314 switch (SCARG(uap, cmd)) {
1315 case LINUX_REBOOT_CMD_RESTART:
1316 SCARG(&sra, opt) = RB_AUTOBOOT;
1317 break;
1318 case LINUX_REBOOT_CMD_HALT:
1319 SCARG(&sra, opt) = RB_HALT;
1320 break;
1321 case LINUX_REBOOT_CMD_POWER_OFF:
1322 SCARG(&sra, opt) = RB_HALT|RB_POWERDOWN;
1323 break;
1324 case LINUX_REBOOT_CMD_RESTART2:
1325 /* Reboot with an argument. */
1326 SCARG(&sra, opt) = RB_AUTOBOOT|RB_STRING;
1327 SCARG(&sra, bootstr) = SCARG(uap, arg);
1328 break;
1329 case LINUX_REBOOT_CMD_CAD_ON:
1330 return(EINVAL); /* We don't implement ctrl-alt-delete */
1331 case LINUX_REBOOT_CMD_CAD_OFF:
1332 return(0);
1333 default:
1334 return(EINVAL);
1335 }
1336
1337 return(sys_reboot(l, &sra, retval));
1338 }
1339
1340 /*
1341 * Copy of compat_12_sys_swapon().
1342 */
1343 int
1344 linux_sys_swapon(l, v, retval)
1345 struct lwp *l;
1346 void *v;
1347 register_t *retval;
1348 {
1349 struct sys_swapctl_args ua;
1350 struct linux_sys_swapon_args /* {
1351 syscallarg(const char *) name;
1352 } */ *uap = v;
1353
1354 SCARG(&ua, cmd) = SWAP_ON;
1355 SCARG(&ua, arg) = (void *)SCARG(uap, name);
1356 SCARG(&ua, misc) = 0; /* priority */
1357 return (sys_swapctl(l, &ua, retval));
1358 }
1359
1360 /*
1361 * Stop swapping to the file or block device specified by path.
1362 */
1363 int
1364 linux_sys_swapoff(l, v, retval)
1365 struct lwp *l;
1366 void *v;
1367 register_t *retval;
1368 {
1369 struct sys_swapctl_args ua;
1370 struct linux_sys_swapoff_args /* {
1371 syscallarg(const char *) path;
1372 } */ *uap = v;
1373
1374 SCARG(&ua, cmd) = SWAP_OFF;
1375 SCARG(&ua, arg) = (void *)SCARG(uap, path);
1376 return (sys_swapctl(l, &ua, retval));
1377 }
1378
1379 /*
1380 * Copy of compat_09_sys_setdomainname()
1381 */
1382 /* ARGSUSED */
1383 int
1384 linux_sys_setdomainname(l, v, retval)
1385 struct lwp *l;
1386 void *v;
1387 register_t *retval;
1388 {
1389 struct linux_sys_setdomainname_args /* {
1390 syscallarg(char *) domainname;
1391 syscallarg(int) len;
1392 } */ *uap = v;
1393 struct proc *p = l->l_proc;
1394 int name;
1395 int error;
1396
1397 if ((error = suser(p->p_ucred, &p->p_acflag)) != 0)
1398 return (error);
1399 name = KERN_DOMAINNAME;
1400 return (kern_sysctl(&name, 1, 0, 0, SCARG(uap, domainname),
1401 SCARG(uap, len), p));
1402 }
1403
1404 /*
1405 * sysinfo()
1406 */
1407 /* ARGSUSED */
1408 int
1409 linux_sys_sysinfo(l, v, retval)
1410 struct lwp *l;
1411 void *v;
1412 register_t *retval;
1413 {
1414 struct linux_sys_sysinfo_args /* {
1415 syscallarg(struct linux_sysinfo *) arg;
1416 } */ *uap = v;
1417 struct linux_sysinfo si;
1418 struct loadavg *la;
1419
1420 si.uptime = time.tv_sec - boottime.tv_sec;
1421 la = &averunnable;
1422 si.loads[0] = la->ldavg[0] * LINUX_SYSINFO_LOADS_SCALE / la->fscale;
1423 si.loads[1] = la->ldavg[1] * LINUX_SYSINFO_LOADS_SCALE / la->fscale;
1424 si.loads[2] = la->ldavg[2] * LINUX_SYSINFO_LOADS_SCALE / la->fscale;
1425 si.totalram = ctob(physmem);
1426 si.freeram = uvmexp.free * uvmexp.pagesize;
1427 si.sharedram = 0; /* XXX */
1428 si.bufferram = uvmexp.vnodepages * uvmexp.pagesize;
1429 si.totalswap = uvmexp.swpages * uvmexp.pagesize;
1430 si.freeswap = (uvmexp.swpages - uvmexp.swpginuse) * uvmexp.pagesize;
1431 si.procs = nprocs;
1432
1433 /* The following are only present in newer Linux kernels. */
1434 si.totalbig = 0;
1435 si.freebig = 0;
1436 si.mem_unit = 1;
1437
1438 return (copyout(&si, SCARG(uap, arg), sizeof si));
1439 }
1440
1441 /*
1442 * This gets called for unsupported syscalls. The difference to sys_nosys()
1443 * is that process does not get SIGSYS, the call just returns with ENOSYS.
1444 * This is the way Linux does it and glibc depends on this behaviour.
1445 */
1446 int
1447 linux_sys_nosys(l, v, retval)
1448 struct lwp *l;
1449 void *v;
1450 register_t *retval;
1451 {
1452 return (ENOSYS);
1453 }
1454