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