Annotation of sys/compat/linux/linux_misc.c, Revision 1.1
1.1 ! nbrk 1: /* $OpenBSD: linux_misc.c,v 1.60 2007/02/06 18:42:37 art Exp $ */
! 2: /* $NetBSD: linux_misc.c,v 1.27 1996/05/20 01:59:21 fvdl Exp $ */
! 3:
! 4: /*-
! 5: * Copyright (c) 1995, 1998, 1999 The NetBSD Foundation, Inc.
! 6: * All rights reserved.
! 7: *
! 8: * This code is derived from software contributed to The NetBSD Foundation
! 9: * by Frank van der Linden and Eric Haszlakiewicz; by Jason R. Thorpe
! 10: * of the Numerical Aerospace Simulation Facility, NASA Ames Research Center.
! 11: *
! 12: * Redistribution and use in source and binary forms, with or without
! 13: * modification, are permitted provided that the following conditions
! 14: * are met:
! 15: * 1. Redistributions of source code must retain the above copyright
! 16: * notice, this list of conditions and the following disclaimer.
! 17: * 2. Redistributions in binary form must reproduce the above copyright
! 18: * notice, this list of conditions and the following disclaimer in the
! 19: * documentation and/or other materials provided with the distribution.
! 20: * 3. All advertising materials mentioning features or use of this software
! 21: * must display the following acknowledgement:
! 22: * This product includes software developed by the NetBSD
! 23: * Foundation, Inc. and its contributors.
! 24: * 4. Neither the name of The NetBSD Foundation nor the names of its
! 25: * contributors may be used to endorse or promote products derived
! 26: * from this software without specific prior written permission.
! 27: *
! 28: * THIS SOFTWARE IS PROVIDED BY THE NETBSD FOUNDATION, INC. AND CONTRIBUTORS
! 29: * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED
! 30: * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
! 31: * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE FOUNDATION OR CONTRIBUTORS
! 32: * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
! 33: * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
! 34: * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
! 35: * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
! 36: * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
! 37: * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
! 38: * POSSIBILITY OF SUCH DAMAGE.
! 39: */
! 40:
! 41: /*
! 42: * Linux compatibility module. Try to deal with various Linux system calls.
! 43: */
! 44:
! 45: #include <sys/param.h>
! 46: #include <sys/systm.h>
! 47: #include <sys/namei.h>
! 48: #include <sys/proc.h>
! 49: #include <sys/dirent.h>
! 50: #include <sys/file.h>
! 51: #include <sys/stat.h>
! 52: #include <sys/filedesc.h>
! 53: #include <sys/ioctl.h>
! 54: #include <sys/kernel.h>
! 55: #include <sys/malloc.h>
! 56: #include <sys/mbuf.h>
! 57: #include <sys/mman.h>
! 58: #include <sys/mount.h>
! 59: #include <sys/ptrace.h>
! 60: #include <sys/resource.h>
! 61: #include <sys/resourcevar.h>
! 62: #include <sys/signal.h>
! 63: #include <sys/signalvar.h>
! 64: #include <sys/socket.h>
! 65: #include <sys/time.h>
! 66: #include <sys/times.h>
! 67: #include <sys/vnode.h>
! 68: #include <sys/uio.h>
! 69: #include <sys/wait.h>
! 70: #include <sys/utsname.h>
! 71: #include <sys/unistd.h>
! 72:
! 73: #include <sys/syscallargs.h>
! 74:
! 75: #include <uvm/uvm_extern.h>
! 76:
! 77: #include <compat/linux/linux_types.h>
! 78: #include <compat/linux/linux_fcntl.h>
! 79: #include <compat/linux/linux_misc.h>
! 80: #include <compat/linux/linux_mmap.h>
! 81: #include <compat/linux/linux_sched.h>
! 82: #include <compat/linux/linux_signal.h>
! 83: #include <compat/linux/linux_syscallargs.h>
! 84: #include <compat/linux/linux_util.h>
! 85: #include <compat/linux/linux_dirent.h>
! 86: #include <compat/linux/linux_emuldata.h>
! 87:
! 88: #include <compat/common/compat_dir.h>
! 89:
! 90: /* linux_misc.c */
! 91: static void bsd_to_linux_statfs(struct statfs *, struct linux_statfs *);
! 92: int linux_select1(struct proc *, register_t *, int, fd_set *,
! 93: fd_set *, fd_set *, struct timeval *);
! 94: static int getdents_common(struct proc *, void *, register_t *, int);
! 95: static void linux_to_bsd_mmap_args(struct sys_mmap_args *,
! 96: const struct linux_sys_mmap2_args *);
! 97:
! 98: /*
! 99: * The information on a terminated (or stopped) process needs
! 100: * to be converted in order for Linux binaries to get a valid signal
! 101: * number out of it.
! 102: */
! 103: void
! 104: bsd_to_linux_wstat(status)
! 105: int *status;
! 106: {
! 107:
! 108: if (WIFSIGNALED(*status))
! 109: *status = (*status & ~0177) |
! 110: bsd_to_linux_sig[WTERMSIG(*status)];
! 111: else if (WIFSTOPPED(*status))
! 112: *status = (*status & ~0xff00) |
! 113: (bsd_to_linux_sig[WSTOPSIG(*status)] << 8);
! 114: }
! 115:
! 116: /*
! 117: * waitpid(2). Just forward on to linux_sys_wait4 with a NULL rusage.
! 118: */
! 119: int
! 120: linux_sys_waitpid(p, v, retval)
! 121: struct proc *p;
! 122: void *v;
! 123: register_t *retval;
! 124: {
! 125: struct linux_sys_waitpid_args /* {
! 126: syscallarg(int) pid;
! 127: syscallarg(int *) status;
! 128: syscallarg(int) options;
! 129: } */ *uap = v;
! 130: struct sys_wait4_args linux_w4a;
! 131:
! 132: SCARG(&linux_w4a, pid) = SCARG(uap, pid);
! 133: SCARG(&linux_w4a, status) = SCARG(uap, status);
! 134: SCARG(&linux_w4a, options) = SCARG(uap, options);
! 135: SCARG(&linux_w4a, rusage) = NULL;
! 136:
! 137: return (linux_sys_wait4(p, &linux_w4a, retval));
! 138: }
! 139:
! 140: /*
! 141: * wait4(2). Passed on to the OpenBSD call, surrounded by code to reserve
! 142: * some space for an OpenBSD-style wait status, and converting it to what
! 143: * Linux wants.
! 144: */
! 145: int
! 146: linux_sys_wait4(p, v, retval)
! 147: struct proc *p;
! 148: void *v;
! 149: register_t *retval;
! 150: {
! 151: struct linux_sys_wait4_args /* {
! 152: syscallarg(int) pid;
! 153: syscallarg(int *) status;
! 154: syscallarg(int) options;
! 155: syscallarg(struct rusage *) rusage;
! 156: } */ *uap = v;
! 157: struct sys_wait4_args w4a;
! 158: int error, *status, tstat, linux_options, options;
! 159: caddr_t sg;
! 160:
! 161: if (SCARG(uap, status) != NULL) {
! 162: sg = stackgap_init(p->p_emul);
! 163: status = (int *) stackgap_alloc(&sg, sizeof status);
! 164: } else
! 165: status = NULL;
! 166:
! 167: linux_options = SCARG(uap, options);
! 168: options = 0;
! 169: if (linux_options &
! 170: ~(LINUX_WAIT4_WNOHANG|LINUX_WAIT4_WUNTRACED|LINUX_WAIT4_WCLONE))
! 171: return (EINVAL);
! 172:
! 173: if (linux_options & LINUX_WAIT4_WNOHANG)
! 174: options |= WNOHANG;
! 175: if (linux_options & LINUX_WAIT4_WUNTRACED)
! 176: options |= WUNTRACED;
! 177: if (linux_options & LINUX_WAIT4_WCLONE)
! 178: options |= WALTSIG;
! 179:
! 180: SCARG(&w4a, pid) = SCARG(uap, pid);
! 181: SCARG(&w4a, status) = status;
! 182: SCARG(&w4a, options) = options;
! 183: SCARG(&w4a, rusage) = SCARG(uap, rusage);
! 184:
! 185: if ((error = sys_wait4(p, &w4a, retval)))
! 186: return error;
! 187:
! 188: atomic_clearbits_int(&p->p_siglist, sigmask(SIGCHLD));
! 189:
! 190: if (status != NULL) {
! 191: if ((error = copyin(status, &tstat, sizeof tstat)))
! 192: return error;
! 193:
! 194: bsd_to_linux_wstat(&tstat);
! 195: return copyout(&tstat, SCARG(uap, status), sizeof tstat);
! 196: }
! 197:
! 198: return 0;
! 199: }
! 200:
! 201: int
! 202: linux_sys_setresgid16(p, v, retval)
! 203: struct proc *p;
! 204: void *v;
! 205: register_t *retval;
! 206: {
! 207: struct linux_sys_setresgid16_args /* {
! 208: syscallarg(u_int16_t) rgid;
! 209: syscallarg(u_int16_t) egid;
! 210: syscallarg(u_int16_t) sgid;
! 211: } */ *uap = v;
! 212: struct sys_setresgid_args nuap;
! 213: u_int16_t rgid, egid, sgid;
! 214:
! 215: rgid = SCARG(uap, rgid);
! 216: SCARG(&nuap, rgid) = (rgid == (u_int16_t)-1) ? (gid_t)-1 : rgid;
! 217: egid = SCARG(uap, egid);
! 218: SCARG(&nuap, egid) = (egid == (u_int16_t)-1) ? (gid_t)-1 : egid;
! 219: sgid = SCARG(uap, sgid);
! 220: SCARG(&nuap, sgid) = (sgid == (u_int16_t)-1) ? (gid_t)-1 : sgid;
! 221:
! 222: return sys_setresgid(p, &nuap, retval);
! 223: }
! 224:
! 225: int
! 226: linux_sys_getresgid16(p, v, retval)
! 227: struct proc *p;
! 228: void *v;
! 229: register_t *retval;
! 230: {
! 231: struct linux_sys_getresgid16_args /* {
! 232: syscallarg(u_int16_t *) rgid;
! 233: syscallarg(u_int16_t *) egid;
! 234: syscallarg(u_int16_t *) sgid;
! 235: } */ *uap = v;
! 236: struct sys_getresgid_args nuap;
! 237:
! 238: SCARG(&nuap, rgid) = (gid_t *)SCARG(uap, rgid);
! 239: SCARG(&nuap, egid) = (gid_t *)SCARG(uap, egid);
! 240: SCARG(&nuap, sgid) = (gid_t *)SCARG(uap, sgid);
! 241:
! 242: return sys_getresgid(p, &nuap, retval);
! 243: }
! 244:
! 245: int
! 246: linux_sys_setresuid16(p, v, retval)
! 247: struct proc *p;
! 248: void *v;
! 249: register_t *retval;
! 250: {
! 251: struct linux_sys_setresuid16_args /* {
! 252: syscallarg(u_int16_t) ruid;
! 253: syscallarg(u_int16_t) euid;
! 254: syscallarg(u_int16_t) suid;
! 255: } */ *uap = v;
! 256: struct sys_setresuid_args nuap;
! 257: u_int16_t ruid, euid, suid;
! 258:
! 259: ruid = SCARG(uap, ruid);
! 260: SCARG(&nuap, ruid) = (ruid == (u_int16_t)-1) ? (uid_t)-1 : ruid;
! 261: euid = SCARG(uap, euid);
! 262: SCARG(&nuap, euid) = (euid == (u_int16_t)-1) ? (uid_t)-1 : euid;
! 263: suid = SCARG(uap, suid);
! 264: SCARG(&nuap, suid) = (suid == (u_int16_t)-1) ? (uid_t)-1 : suid;
! 265:
! 266: return sys_setresuid(p, &nuap, retval);
! 267: }
! 268:
! 269: int
! 270: linux_sys_getresuid16(p, v, retval)
! 271: struct proc *p;
! 272: void *v;
! 273: register_t *retval;
! 274: {
! 275: struct linux_sys_getresuid16_args /* {
! 276: syscallarg(u_int16_t *) ruid;
! 277: syscallarg(u_int16_t *) euid;
! 278: syscallarg(u_int16_t *) suid;
! 279: } */ *uap = v;
! 280: struct sys_getresuid_args nuap;
! 281:
! 282: SCARG(&nuap, ruid) = (uid_t *)SCARG(uap, ruid);
! 283: SCARG(&nuap, euid) = (uid_t *)SCARG(uap, euid);
! 284: SCARG(&nuap, suid) = (uid_t *)SCARG(uap, suid);
! 285:
! 286: return sys_getresuid(p, &nuap, retval);
! 287: }
! 288:
! 289: /*
! 290: * This is the old brk(2) call. I don't think anything in the Linux
! 291: * world uses this anymore
! 292: */
! 293: int
! 294: linux_sys_break(p, v, retval)
! 295: struct proc *p;
! 296: void *v;
! 297: register_t *retval;
! 298: {
! 299: #if 0
! 300: struct linux_sys_brk_args /* {
! 301: syscallarg(char *) nsize;
! 302: } */ *uap = v;
! 303: #endif
! 304:
! 305: return ENOSYS;
! 306: }
! 307:
! 308: /*
! 309: * Linux brk(2). The check if the new address is >= the old one is
! 310: * done in the kernel in Linux. OpenBSD does it in the library.
! 311: */
! 312: int
! 313: linux_sys_brk(p, v, retval)
! 314: struct proc *p;
! 315: void *v;
! 316: register_t *retval;
! 317: {
! 318: struct linux_sys_brk_args /* {
! 319: syscallarg(char *) nsize;
! 320: } */ *uap = v;
! 321: char *nbrk = SCARG(uap, nsize);
! 322: struct sys_obreak_args oba;
! 323: struct vmspace *vm = p->p_vmspace;
! 324: struct linux_emuldata *ed = (struct linux_emuldata*)p->p_emuldata;
! 325:
! 326: SCARG(&oba, nsize) = nbrk;
! 327:
! 328: if ((caddr_t) nbrk > vm->vm_daddr && sys_obreak(p, &oba, retval) == 0)
! 329: ed->p_break = (char*)nbrk;
! 330: else
! 331: nbrk = ed->p_break;
! 332:
! 333: retval[0] = (register_t)nbrk;
! 334:
! 335: return 0;
! 336: }
! 337:
! 338: /*
! 339: * I wonder why Linux has gettimeofday() _and_ time().. Still, we
! 340: * need to deal with it.
! 341: */
! 342: int
! 343: linux_sys_time(p, v, retval)
! 344: struct proc *p;
! 345: void *v;
! 346: register_t *retval;
! 347: {
! 348: struct linux_sys_time_args /* {
! 349: linux_time_t *t;
! 350: } */ *uap = v;
! 351: struct timeval atv;
! 352: linux_time_t tt;
! 353: int error;
! 354:
! 355: microtime(&atv);
! 356:
! 357: tt = atv.tv_sec;
! 358: if (SCARG(uap, t) && (error = copyout(&tt, SCARG(uap, t), sizeof tt)))
! 359: return error;
! 360:
! 361: retval[0] = tt;
! 362: return 0;
! 363: }
! 364:
! 365: /*
! 366: * Convert BSD statfs structure to Linux statfs structure.
! 367: * The Linux structure has less fields, and it also wants
! 368: * the length of a name in a dir entry in a field, which
! 369: * we fake (probably the wrong way).
! 370: */
! 371: static void
! 372: bsd_to_linux_statfs(bsp, lsp)
! 373: struct statfs *bsp;
! 374: struct linux_statfs *lsp;
! 375: {
! 376:
! 377: /*
! 378: * Convert BSD filesystem names to Linux filesystem type numbers
! 379: * where possible. Linux statfs uses a value of -1 to indicate
! 380: * an unsupported field.
! 381: */
! 382: if (!strcmp(bsp->f_fstypename, MOUNT_FFS) ||
! 383: !strcmp(bsp->f_fstypename, MOUNT_MFS))
! 384: lsp->l_ftype = 0x11954;
! 385: else if (!strcmp(bsp->f_fstypename, MOUNT_NFS))
! 386: lsp->l_ftype = 0x6969;
! 387: else if (!strcmp(bsp->f_fstypename, MOUNT_MSDOS))
! 388: lsp->l_ftype = 0x4d44;
! 389: else if (!strcmp(bsp->f_fstypename, MOUNT_PROCFS))
! 390: lsp->l_ftype = 0x9fa0;
! 391: else if (!strcmp(bsp->f_fstypename, MOUNT_EXT2FS))
! 392: lsp->l_ftype = 0xef53;
! 393: else if (!strcmp(bsp->f_fstypename, MOUNT_CD9660))
! 394: lsp->l_ftype = 0x9660;
! 395: else if (!strcmp(bsp->f_fstypename, MOUNT_NCPFS))
! 396: lsp->l_ftype = 0x6969;
! 397: else
! 398: lsp->l_ftype = -1;
! 399:
! 400: lsp->l_fbsize = bsp->f_bsize;
! 401: lsp->l_fblocks = bsp->f_blocks;
! 402: lsp->l_fbfree = bsp->f_bfree;
! 403: lsp->l_fbavail = bsp->f_bavail;
! 404: lsp->l_ffiles = bsp->f_files;
! 405: lsp->l_fffree = bsp->f_ffree;
! 406: lsp->l_ffsid.val[0] = bsp->f_fsid.val[0];
! 407: lsp->l_ffsid.val[1] = bsp->f_fsid.val[1];
! 408: lsp->l_fnamelen = MAXNAMLEN; /* XXX */
! 409: }
! 410:
! 411: /*
! 412: * Implement the fs stat functions. Straightforward.
! 413: */
! 414: int
! 415: linux_sys_statfs(p, v, retval)
! 416: struct proc *p;
! 417: void *v;
! 418: register_t *retval;
! 419: {
! 420: struct linux_sys_statfs_args /* {
! 421: syscallarg(char *) path;
! 422: syscallarg(struct linux_statfs *) sp;
! 423: } */ *uap = v;
! 424: struct statfs btmp, *bsp;
! 425: struct linux_statfs ltmp;
! 426: struct sys_statfs_args bsa;
! 427: caddr_t sg;
! 428: int error;
! 429:
! 430: sg = stackgap_init(p->p_emul);
! 431: bsp = (struct statfs *) stackgap_alloc(&sg, sizeof (struct statfs));
! 432:
! 433: LINUX_CHECK_ALT_EXIST(p, &sg, SCARG(uap, path));
! 434:
! 435: SCARG(&bsa, path) = SCARG(uap, path);
! 436: SCARG(&bsa, buf) = bsp;
! 437:
! 438: if ((error = sys_statfs(p, &bsa, retval)))
! 439: return error;
! 440:
! 441: if ((error = copyin((caddr_t) bsp, (caddr_t) &btmp, sizeof btmp)))
! 442: return error;
! 443:
! 444: bsd_to_linux_statfs(&btmp, <mp);
! 445:
! 446: return copyout((caddr_t) <mp, (caddr_t) SCARG(uap, sp), sizeof ltmp);
! 447: }
! 448:
! 449: int
! 450: linux_sys_fstatfs(p, v, retval)
! 451: struct proc *p;
! 452: void *v;
! 453: register_t *retval;
! 454: {
! 455: struct linux_sys_fstatfs_args /* {
! 456: syscallarg(int) fd;
! 457: syscallarg(struct linux_statfs *) sp;
! 458: } */ *uap = v;
! 459: struct statfs btmp, *bsp;
! 460: struct linux_statfs ltmp;
! 461: struct sys_fstatfs_args bsa;
! 462: caddr_t sg;
! 463: int error;
! 464:
! 465: sg = stackgap_init(p->p_emul);
! 466: bsp = (struct statfs *) stackgap_alloc(&sg, sizeof (struct statfs));
! 467:
! 468: SCARG(&bsa, fd) = SCARG(uap, fd);
! 469: SCARG(&bsa, buf) = bsp;
! 470:
! 471: if ((error = sys_fstatfs(p, &bsa, retval)))
! 472: return error;
! 473:
! 474: if ((error = copyin((caddr_t) bsp, (caddr_t) &btmp, sizeof btmp)))
! 475: return error;
! 476:
! 477: bsd_to_linux_statfs(&btmp, <mp);
! 478:
! 479: return copyout((caddr_t) <mp, (caddr_t) SCARG(uap, sp), sizeof ltmp);
! 480: }
! 481:
! 482: /*
! 483: * uname(). Just copy the info from the various strings stored in the
! 484: * kernel, and put it in the Linux utsname structure. That structure
! 485: * is almost the same as the OpenBSD one, only it has fields 65 characters
! 486: * long, and an extra domainname field.
! 487: */
! 488: int
! 489: linux_sys_uname(p, v, retval)
! 490: struct proc *p;
! 491: void *v;
! 492: register_t *retval;
! 493: {
! 494: struct linux_sys_uname_args /* {
! 495: syscallarg(struct linux_utsname *) up;
! 496: } */ *uap = v;
! 497: extern char hostname[], machine[], domainname[];
! 498: struct linux_utsname luts;
! 499: int len;
! 500: char *cp;
! 501:
! 502: strlcpy(luts.l_sysname, ostype, sizeof(luts.l_sysname));
! 503: strlcpy(luts.l_nodename, hostname, sizeof(luts.l_nodename));
! 504: strlcpy(luts.l_release, osrelease, sizeof(luts.l_release));
! 505: strlcpy(luts.l_version, version, sizeof(luts.l_version));
! 506: strlcpy(luts.l_machine, machine, sizeof(luts.l_machine));
! 507: strlcpy(luts.l_domainname, domainname, sizeof(luts.l_domainname));
! 508:
! 509: /* This part taken from the uname() in libc */
! 510: len = sizeof(luts.l_version);
! 511: for (cp = luts.l_version; len--; ++cp)
! 512: if (*cp == '\n' || *cp == '\t')
! 513: *cp = (len > 1) ? ' ' : '\0';
! 514:
! 515: return copyout(&luts, SCARG(uap, up), sizeof(luts));
! 516: }
! 517:
! 518: int
! 519: linux_sys_olduname(p, v, retval)
! 520: struct proc *p;
! 521: void *v;
! 522: register_t *retval;
! 523: {
! 524: struct linux_sys_uname_args /* {
! 525: syscallarg(struct linux_oldutsname *) up;
! 526: } */ *uap = v;
! 527: extern char hostname[], machine[];
! 528: struct linux_oldutsname luts;
! 529: int len;
! 530: char *cp;
! 531:
! 532: strlcpy(luts.l_sysname, ostype, sizeof(luts.l_sysname));
! 533: strlcpy(luts.l_nodename, hostname, sizeof(luts.l_nodename));
! 534: strlcpy(luts.l_release, osrelease, sizeof(luts.l_release));
! 535: strlcpy(luts.l_version, version, sizeof(luts.l_version));
! 536: strlcpy(luts.l_machine, machine, sizeof(luts.l_machine));
! 537:
! 538: /* This part taken from the uname() in libc */
! 539: len = sizeof(luts.l_version);
! 540: for (cp = luts.l_version; len--; ++cp)
! 541: if (*cp == '\n' || *cp == '\t')
! 542: *cp = (len > 1) ? ' ' : '\0';
! 543:
! 544: return copyout(&luts, SCARG(uap, up), sizeof(luts));
! 545: }
! 546:
! 547: int
! 548: linux_sys_oldolduname(p, v, retval)
! 549: struct proc *p;
! 550: void *v;
! 551: register_t *retval;
! 552: {
! 553: struct linux_sys_uname_args /* {
! 554: syscallarg(struct linux_oldoldutsname *) up;
! 555: } */ *uap = v;
! 556: extern char hostname[], machine[];
! 557: struct linux_oldoldutsname luts;
! 558: int len;
! 559: char *cp;
! 560:
! 561: strlcpy(luts.l_sysname, ostype, sizeof(luts.l_sysname));
! 562: strlcpy(luts.l_nodename, hostname, sizeof(luts.l_nodename));
! 563: strlcpy(luts.l_release, osrelease, sizeof(luts.l_release));
! 564: strlcpy(luts.l_version, version, sizeof(luts.l_version));
! 565: strlcpy(luts.l_machine, machine, sizeof(luts.l_machine));
! 566:
! 567: /* This part taken from the uname() in libc */
! 568: len = sizeof(luts.l_version);
! 569: for (cp = luts.l_version; len--; ++cp)
! 570: if (*cp == '\n' || *cp == '\t')
! 571: *cp = (len > 1) ? ' ' : '\0';
! 572:
! 573: return copyout(&luts, SCARG(uap, up), sizeof(luts));
! 574: }
! 575:
! 576: /*
! 577: * Linux wants to pass everything to a syscall in registers. However,
! 578: * mmap() has 6 of them. Oops: out of register error. They just pass
! 579: * everything in a structure.
! 580: */
! 581: int
! 582: linux_sys_mmap(p, v, retval)
! 583: struct proc *p;
! 584: void *v;
! 585: register_t *retval;
! 586: {
! 587: struct linux_sys_mmap_args /* {
! 588: syscallarg(struct linux_mmap *) lmp;
! 589: } */ *uap = v;
! 590: struct linux_mmap lmap;
! 591: struct linux_sys_mmap2_args nlmap;
! 592: struct sys_mmap_args cma;
! 593: int error;
! 594:
! 595: if ((error = copyin(SCARG(uap, lmp), &lmap, sizeof lmap)))
! 596: return error;
! 597:
! 598: if (lmap.lm_pos & PAGE_MASK)
! 599: return EINVAL;
! 600:
! 601: /* repackage into something sane */
! 602: SCARG(&nlmap,addr) = (unsigned long)lmap.lm_addr;
! 603: SCARG(&nlmap,len) = lmap.lm_len;
! 604: SCARG(&nlmap,prot) = lmap.lm_prot;
! 605: SCARG(&nlmap,flags) = lmap.lm_flags;
! 606: SCARG(&nlmap,fd) = lmap.lm_fd;
! 607: SCARG(&nlmap,offset) = (unsigned)lmap.lm_pos;
! 608:
! 609: linux_to_bsd_mmap_args(&cma, &nlmap);
! 610: SCARG(&cma, pos) = (off_t)SCARG(&nlmap, offset);
! 611:
! 612: return sys_mmap(p, &cma, retval);
! 613: }
! 614:
! 615: /*
! 616: * Guts of most architectures' mmap64() implementations. This shares
! 617: * its list of arguments with linux_sys_mmap().
! 618: *
! 619: * The difference in linux_sys_mmap2() is that "offset" is actually
! 620: * (offset / pagesize), not an absolute byte count. This translation
! 621: * to pagesize offsets is done inside glibc between the mmap64() call
! 622: * point, and the actual syscall.
! 623: */
! 624: int
! 625: linux_sys_mmap2(p, v, retval)
! 626: struct proc *p;
! 627: void *v;
! 628: register_t *retval;
! 629: {
! 630: struct linux_sys_mmap2_args /* {
! 631: syscallarg(unsigned long) addr;
! 632: syscallarg(size_t) len;
! 633: syscallarg(int) prot;
! 634: syscallarg(int) flags;
! 635: syscallarg(int) fd;
! 636: syscallarg(linux_off_t) offset;
! 637: } */ *uap = v;
! 638: struct sys_mmap_args cma;
! 639:
! 640: linux_to_bsd_mmap_args(&cma, uap);
! 641: SCARG(&cma, pos) = ((off_t)SCARG(uap, offset)) << PAGE_SHIFT;
! 642:
! 643: return sys_mmap(p, &cma, retval);
! 644: }
! 645:
! 646: static void
! 647: linux_to_bsd_mmap_args(cma, uap)
! 648: struct sys_mmap_args *cma;
! 649: const struct linux_sys_mmap2_args *uap;
! 650: {
! 651: int flags = MAP_TRYFIXED, fl = SCARG(uap, flags);
! 652:
! 653: flags |= cvtto_bsd_mask(fl, LINUX_MAP_SHARED, MAP_SHARED);
! 654: flags |= cvtto_bsd_mask(fl, LINUX_MAP_PRIVATE, MAP_PRIVATE);
! 655: flags |= cvtto_bsd_mask(fl, LINUX_MAP_FIXED, MAP_FIXED);
! 656: flags |= cvtto_bsd_mask(fl, LINUX_MAP_ANON, MAP_ANON);
! 657: /* XXX XAX ERH: Any other flags here? There are more defined... */
! 658:
! 659: SCARG(cma, addr) = (void *)SCARG(uap, addr);
! 660: SCARG(cma, len) = SCARG(uap, len);
! 661: SCARG(cma, prot) = SCARG(uap, prot);
! 662: if (SCARG(cma, prot) & VM_PROT_WRITE) /* XXX */
! 663: SCARG(cma, prot) |= VM_PROT_READ;
! 664: SCARG(cma, flags) = flags;
! 665: SCARG(cma, fd) = flags & MAP_ANON ? -1 : SCARG(uap, fd);
! 666: SCARG(cma, pad) = 0;
! 667: }
! 668:
! 669: int
! 670: linux_sys_mremap(p, v, retval)
! 671: struct proc *p;
! 672: void *v;
! 673: register_t *retval;
! 674: {
! 675:
! 676: struct linux_sys_mremap_args /* {
! 677: syscallarg(void *) old_address;
! 678: syscallarg(size_t) old_size;
! 679: syscallarg(size_t) new_size;
! 680: syscallarg(u_long) flags;
! 681: } */ *uap = v;
! 682: struct sys_munmap_args mua;
! 683: size_t old_size, new_size;
! 684: int error;
! 685:
! 686: old_size = round_page(SCARG(uap, old_size));
! 687: new_size = round_page(SCARG(uap, new_size));
! 688:
! 689: /*
! 690: * Growing mapped region.
! 691: */
! 692: if (new_size > old_size) {
! 693: /*
! 694: * XXX Implement me. What we probably want to do is
! 695: * XXX dig out the guts of the old mapping, mmap that
! 696: * XXX object again with the new size, then munmap
! 697: * XXX the old mapping.
! 698: */
! 699: *retval = 0;
! 700: return (ENOMEM);
! 701: }
! 702: /*
! 703: * Shrinking mapped region.
! 704: */
! 705: if (new_size < old_size) {
! 706: SCARG(&mua, addr) = (caddr_t)SCARG(uap, old_address) + new_size;
! 707: SCARG(&mua, len) = old_size - new_size;
! 708: error = sys_munmap(p, &mua, retval);
! 709: *retval = error ? 0 : (register_t)SCARG(uap, old_address);
! 710: return (error);
! 711: }
! 712:
! 713: /*
! 714: * No change.
! 715: */
! 716: *retval = (register_t)SCARG(uap, old_address);
! 717: return (0);
! 718:
! 719: }
! 720:
! 721: /*
! 722: * This code is partly stolen from src/lib/libc/gen/times.c
! 723: * XXX - CLK_TCK isn't declared in /sys, just in <time.h>, done here
! 724: */
! 725:
! 726: #define CLK_TCK 100
! 727: #define CONVTCK(r) (r.tv_sec * CLK_TCK + r.tv_usec / (1000000 / CLK_TCK))
! 728:
! 729: int
! 730: linux_sys_times(p, v, retval)
! 731: struct proc *p;
! 732: void *v;
! 733: register_t *retval;
! 734: {
! 735: struct linux_sys_times_args /* {
! 736: syscallarg(struct times *) tms;
! 737: } */ *uap = v;
! 738: struct timeval t;
! 739: struct linux_tms ltms;
! 740: struct rusage ru;
! 741: int error;
! 742:
! 743: calcru(p, &ru.ru_utime, &ru.ru_stime, NULL);
! 744: ltms.ltms_utime = CONVTCK(ru.ru_utime);
! 745: ltms.ltms_stime = CONVTCK(ru.ru_stime);
! 746:
! 747: ltms.ltms_cutime = CONVTCK(p->p_stats->p_cru.ru_utime);
! 748: ltms.ltms_cstime = CONVTCK(p->p_stats->p_cru.ru_stime);
! 749:
! 750: if ((error = copyout(<ms, SCARG(uap, tms), sizeof ltms)))
! 751: return error;
! 752:
! 753: microuptime(&t);
! 754:
! 755: retval[0] = ((linux_clock_t)(CONVTCK(t)));
! 756: return 0;
! 757: }
! 758:
! 759: /*
! 760: * OpenBSD passes fd[0] in retval[0], and fd[1] in retval[1].
! 761: * Linux directly passes the pointer.
! 762: */
! 763: int
! 764: linux_sys_pipe(p, v, retval)
! 765: struct proc *p;
! 766: void *v;
! 767: register_t *retval;
! 768: {
! 769: struct linux_sys_pipe_args /* {
! 770: syscallarg(int *) pfds;
! 771: } */ *uap = v;
! 772: int error;
! 773: int pfds[2];
! 774: #ifdef __i386__
! 775: int reg_edx = retval[1];
! 776: #endif /* __i386__ */
! 777:
! 778: if ((error = sys_opipe(p, 0, retval))) {
! 779: #ifdef __i386__
! 780: retval[1] = reg_edx;
! 781: #endif /* __i386__ */
! 782: return error;
! 783: }
! 784:
! 785: /* Assumes register_t is an int */
! 786:
! 787: pfds[0] = retval[0];
! 788: pfds[1] = retval[1];
! 789: if ((error = copyout(pfds, SCARG(uap, pfds), 2 * sizeof (int)))) {
! 790: #ifdef __i386__
! 791: retval[1] = reg_edx;
! 792: #endif /* __i386__ */
! 793: fdrelease(p, retval[0]);
! 794: fdrelease(p, retval[1]);
! 795: return error;
! 796: }
! 797:
! 798: retval[0] = 0;
! 799: #ifdef __i386__
! 800: retval[1] = reg_edx;
! 801: #endif /* __i386__ */
! 802: return 0;
! 803: }
! 804:
! 805: /*
! 806: * Alarm. This is a libc call which uses setitimer(2) in OpenBSD.
! 807: * Fiddle with the timers to make it work.
! 808: */
! 809: int
! 810: linux_sys_alarm(p, v, retval)
! 811: struct proc *p;
! 812: void *v;
! 813: register_t *retval;
! 814: {
! 815: struct linux_sys_alarm_args /* {
! 816: syscallarg(unsigned int) secs;
! 817: } */ *uap = v;
! 818: int s;
! 819: struct itimerval *itp, it;
! 820: struct timeval tv;
! 821: int timo;
! 822:
! 823: itp = &p->p_realtimer;
! 824: s = splclock();
! 825: /*
! 826: * Clear any pending timer alarms.
! 827: */
! 828: getmicrouptime(&tv);
! 829: timeout_del(&p->p_realit_to);
! 830: timerclear(&itp->it_interval);
! 831: if (timerisset(&itp->it_value) &&
! 832: timercmp(&itp->it_value, &tv, >))
! 833: timersub(&itp->it_value, &tv, &itp->it_value);
! 834: /*
! 835: * Return how many seconds were left (rounded up)
! 836: */
! 837: retval[0] = itp->it_value.tv_sec;
! 838: if (itp->it_value.tv_usec)
! 839: retval[0]++;
! 840:
! 841: /*
! 842: * alarm(0) just resets the timer.
! 843: */
! 844: if (SCARG(uap, secs) == 0) {
! 845: timerclear(&itp->it_value);
! 846: splx(s);
! 847: return 0;
! 848: }
! 849:
! 850: /*
! 851: * Check the new alarm time for sanity, and set it.
! 852: */
! 853: timerclear(&it.it_interval);
! 854: it.it_value.tv_sec = SCARG(uap, secs);
! 855: it.it_value.tv_usec = 0;
! 856: if (itimerfix(&it.it_value) || itimerfix(&it.it_interval)) {
! 857: splx(s);
! 858: return (EINVAL);
! 859: }
! 860:
! 861: if (timerisset(&it.it_value)) {
! 862: timo = tvtohz(&it.it_value);
! 863: timeradd(&it.it_value, &tv, &it.it_value);
! 864: timeout_add(&p->p_realit_to, timo);
! 865: }
! 866: p->p_realtimer = it;
! 867: splx(s);
! 868:
! 869: return 0;
! 870: }
! 871:
! 872: /*
! 873: * utime(). Do conversion to things that utimes() understands,
! 874: * and pass it on.
! 875: */
! 876: int
! 877: linux_sys_utime(p, v, retval)
! 878: struct proc *p;
! 879: void *v;
! 880: register_t *retval;
! 881: {
! 882: struct linux_sys_utime_args /* {
! 883: syscallarg(char *) path;
! 884: syscallarg(struct linux_utimbuf *)times;
! 885: } */ *uap = v;
! 886: caddr_t sg;
! 887: int error;
! 888: struct sys_utimes_args ua;
! 889: struct timeval tv[2], *tvp;
! 890: struct linux_utimbuf lut;
! 891:
! 892: sg = stackgap_init(p->p_emul);
! 893: tvp = (struct timeval *) stackgap_alloc(&sg, sizeof(tv));
! 894: LINUX_CHECK_ALT_EXIST(p, &sg, SCARG(uap, path));
! 895:
! 896: SCARG(&ua, path) = SCARG(uap, path);
! 897:
! 898: if (SCARG(uap, times) != NULL) {
! 899: if ((error = copyin(SCARG(uap, times), &lut, sizeof lut)))
! 900: return error;
! 901: tv[0].tv_usec = tv[1].tv_usec = 0;
! 902: tv[0].tv_sec = lut.l_actime;
! 903: tv[1].tv_sec = lut.l_modtime;
! 904: if ((error = copyout(tv, tvp, sizeof tv)))
! 905: return error;
! 906: SCARG(&ua, tptr) = tvp;
! 907: }
! 908: else
! 909: SCARG(&ua, tptr) = NULL;
! 910:
! 911: return sys_utimes(p, &ua, retval);
! 912: }
! 913:
! 914: /*
! 915: * The old Linux readdir was only able to read one entry at a time,
! 916: * even though it had a 'count' argument. In fact, the emulation
! 917: * of the old call was better than the original, because it did handle
! 918: * the count arg properly. Don't bother with it anymore now, and use
! 919: * it to distinguish between old and new. The difference is that the
! 920: * newer one actually does multiple entries, and the reclen field
! 921: * really is the reclen, not the namelength.
! 922: */
! 923: int
! 924: linux_sys_readdir(p, v, retval)
! 925: struct proc *p;
! 926: void *v;
! 927: register_t *retval;
! 928: {
! 929: struct linux_sys_readdir_args /* {
! 930: syscallarg(int) fd;
! 931: syscallarg(struct linux_dirent *) dent;
! 932: syscallarg(unsigned int) count;
! 933: } */ *uap = v;
! 934:
! 935: SCARG(uap, count) = 1;
! 936:
! 937: return linux_sys_getdents(p, uap, retval);
! 938: }
! 939:
! 940: /*
! 941: * Linux 'readdir' call. This code is mostly taken from the
! 942: * SunOS getdents call (see compat/sunos/sunos_misc.c), though
! 943: * an attempt has been made to keep it a little cleaner (failing
! 944: * miserably, because of the cruft needed if count 1 is passed).
! 945: *
! 946: * The d_off field should contain the offset of the next valid entry,
! 947: * but in Linux it has the offset of the entry itself. We emulate
! 948: * that bug here.
! 949: *
! 950: * Read in BSD-style entries, convert them, and copy them out.
! 951: *
! 952: * Note that this doesn't handle union-mounted filesystems.
! 953: */
! 954: int linux_readdir_callback(void *, struct dirent *, off_t);
! 955:
! 956: struct linux_readdir_callback_args {
! 957: caddr_t outp;
! 958: int resid;
! 959: int oldcall;
! 960: int is64bit;
! 961: };
! 962:
! 963: int
! 964: linux_readdir_callback(arg, bdp, cookie)
! 965: void *arg;
! 966: struct dirent *bdp;
! 967: off_t cookie;
! 968: {
! 969: struct linux_dirent64 idb64;
! 970: struct linux_dirent idb;
! 971: struct linux_readdir_callback_args *cb = arg;
! 972: int linux_reclen;
! 973: int error;
! 974:
! 975: if (cb->oldcall == 2)
! 976: return (ENOMEM);
! 977:
! 978: linux_reclen = (cb->is64bit) ?
! 979: LINUX_RECLEN(&idb64, bdp->d_namlen) :
! 980: LINUX_RECLEN(&idb, bdp->d_namlen);
! 981:
! 982: if (cb->resid < linux_reclen)
! 983: return (ENOMEM);
! 984:
! 985: if (cb->is64bit) {
! 986: idb64.d_ino = (linux_ino64_t)bdp->d_fileno;
! 987: idb64.d_off = (linux_off64_t)cookie;
! 988: idb64.d_reclen = (u_short)linux_reclen;
! 989: idb64.d_type = bdp->d_type;
! 990: strlcpy(idb64.d_name, bdp->d_name, sizeof(idb64.d_name));
! 991: error = copyout((caddr_t)&idb64, cb->outp, linux_reclen);
! 992: } else {
! 993: idb.d_ino = (linux_ino_t)bdp->d_fileno;
! 994: if (cb->oldcall) {
! 995: /*
! 996: * The old readdir() call misuses the offset
! 997: * and reclen fields.
! 998: */
! 999: idb.d_off = (linux_off_t)linux_reclen;
! 1000: idb.d_reclen = (u_short)bdp->d_namlen;
! 1001: } else {
! 1002: idb.d_off = (linux_off_t)cookie;
! 1003: idb.d_reclen = (u_short)linux_reclen;
! 1004: }
! 1005: strlcpy(idb.d_name, bdp->d_name, sizeof(idb.d_name));
! 1006: error = copyout((caddr_t)&idb, cb->outp, linux_reclen);
! 1007: }
! 1008: if (error)
! 1009: return (error);
! 1010:
! 1011: /* advance output past Linux-shaped entry */
! 1012: cb->outp += linux_reclen;
! 1013: cb->resid -= linux_reclen;
! 1014:
! 1015: if (cb->oldcall == 1)
! 1016: ++cb->oldcall;
! 1017:
! 1018: return (0);
! 1019: }
! 1020:
! 1021: int
! 1022: linux_sys_getdents64(p, v, retval)
! 1023: struct proc *p;
! 1024: void *v;
! 1025: register_t *retval;
! 1026: {
! 1027: return getdents_common(p, v, retval, 1);
! 1028: }
! 1029:
! 1030: int
! 1031: linux_sys_getdents(p, v, retval)
! 1032: struct proc *p;
! 1033: void *v;
! 1034: register_t *retval;
! 1035: {
! 1036: return getdents_common(p, v, retval, 0);
! 1037: }
! 1038:
! 1039: static int
! 1040: getdents_common(p, v, retval, is64bit)
! 1041: struct proc *p;
! 1042: void *v;
! 1043: register_t *retval;
! 1044: int is64bit;
! 1045: {
! 1046: struct linux_sys_getdents_args /* {
! 1047: syscallarg(int) fd;
! 1048: syscallarg(void *) dirent;
! 1049: syscallarg(unsigned) count;
! 1050: } */ *uap = v;
! 1051: struct linux_readdir_callback_args args;
! 1052: struct file *fp;
! 1053: int error;
! 1054: int nbytes = SCARG(uap, count);
! 1055:
! 1056: if ((error = getvnode(p->p_fd, SCARG(uap, fd), &fp)) != 0)
! 1057: return (error);
! 1058:
! 1059: if (nbytes == 1) { /* emulating old, broken behaviour */
! 1060: /* readdir(2) case. Always struct dirent. */
! 1061: if (is64bit) {
! 1062: FRELE(fp);
! 1063: return (EINVAL);
! 1064: }
! 1065: nbytes = sizeof(struct linux_dirent);
! 1066: args.oldcall = 1;
! 1067: } else {
! 1068: args.oldcall = 0;
! 1069: }
! 1070:
! 1071: args.resid = nbytes;
! 1072: args.outp = (caddr_t)SCARG(uap, dirent);
! 1073: args.is64bit = is64bit;
! 1074:
! 1075: if ((error = readdir_with_callback(fp, &fp->f_offset, nbytes,
! 1076: linux_readdir_callback, &args)) != 0)
! 1077: goto exit;
! 1078:
! 1079: *retval = nbytes - args.resid;
! 1080:
! 1081: exit:
! 1082: FRELE(fp);
! 1083: return (error);
! 1084: }
! 1085:
! 1086: /*
! 1087: * Not sure why the arguments to this older version of select() were put
! 1088: * into a structure, because there are 5, and that can all be handled
! 1089: * in registers on the i386 like Linux wants to.
! 1090: */
! 1091: int
! 1092: linux_sys_oldselect(p, v, retval)
! 1093: struct proc *p;
! 1094: void *v;
! 1095: register_t *retval;
! 1096: {
! 1097: struct linux_sys_oldselect_args /* {
! 1098: syscallarg(struct linux_select *) lsp;
! 1099: } */ *uap = v;
! 1100: struct linux_select ls;
! 1101: int error;
! 1102:
! 1103: if ((error = copyin(SCARG(uap, lsp), &ls, sizeof(ls))))
! 1104: return error;
! 1105:
! 1106: return linux_select1(p, retval, ls.nfds, ls.readfds, ls.writefds,
! 1107: ls.exceptfds, ls.timeout);
! 1108: }
! 1109:
! 1110: /*
! 1111: * Even when just using registers to pass arguments to syscalls you can
! 1112: * have 5 of them on the i386. So this newer version of select() does
! 1113: * this.
! 1114: */
! 1115: int
! 1116: linux_sys_select(p, v, retval)
! 1117: struct proc *p;
! 1118: void *v;
! 1119: register_t *retval;
! 1120: {
! 1121: struct linux_sys_select_args /* {
! 1122: syscallarg(int) nfds;
! 1123: syscallarg(fd_set *) readfds;
! 1124: syscallarg(fd_set *) writefds;
! 1125: syscallarg(fd_set *) exceptfds;
! 1126: syscallarg(struct timeval *) timeout;
! 1127: } */ *uap = v;
! 1128:
! 1129: return linux_select1(p, retval, SCARG(uap, nfds), SCARG(uap, readfds),
! 1130: SCARG(uap, writefds), SCARG(uap, exceptfds), SCARG(uap, timeout));
! 1131: }
! 1132:
! 1133: /*
! 1134: * Common code for the old and new versions of select(). A couple of
! 1135: * things are important:
! 1136: * 1) return the amount of time left in the 'timeout' parameter
! 1137: * 2) select never returns ERESTART on Linux, always return EINTR
! 1138: */
! 1139: int
! 1140: linux_select1(p, retval, nfds, readfds, writefds, exceptfds, timeout)
! 1141: struct proc *p;
! 1142: register_t *retval;
! 1143: int nfds;
! 1144: fd_set *readfds, *writefds, *exceptfds;
! 1145: struct timeval *timeout;
! 1146: {
! 1147: struct sys_select_args bsa;
! 1148: struct timeval tv0, tv1, utv, *tvp;
! 1149: caddr_t sg;
! 1150: int error;
! 1151:
! 1152: SCARG(&bsa, nd) = nfds;
! 1153: SCARG(&bsa, in) = readfds;
! 1154: SCARG(&bsa, ou) = writefds;
! 1155: SCARG(&bsa, ex) = exceptfds;
! 1156: SCARG(&bsa, tv) = timeout;
! 1157:
! 1158: /*
! 1159: * Store current time for computation of the amount of
! 1160: * time left.
! 1161: */
! 1162: if (timeout) {
! 1163: if ((error = copyin(timeout, &utv, sizeof(utv))))
! 1164: return error;
! 1165: if (itimerfix(&utv)) {
! 1166: /*
! 1167: * The timeval was invalid. Convert it to something
! 1168: * valid that will act as it does under Linux.
! 1169: */
! 1170: sg = stackgap_init(p->p_emul);
! 1171: tvp = stackgap_alloc(&sg, sizeof(utv));
! 1172: utv.tv_sec += utv.tv_usec / 1000000;
! 1173: utv.tv_usec %= 1000000;
! 1174: if (utv.tv_usec < 0) {
! 1175: utv.tv_sec -= 1;
! 1176: utv.tv_usec += 1000000;
! 1177: }
! 1178: if (utv.tv_sec < 0)
! 1179: timerclear(&utv);
! 1180: if ((error = copyout(&utv, tvp, sizeof(utv))))
! 1181: return error;
! 1182: SCARG(&bsa, tv) = tvp;
! 1183: }
! 1184: microtime(&tv0);
! 1185: }
! 1186:
! 1187: error = sys_select(p, &bsa, retval);
! 1188: if (error) {
! 1189: /*
! 1190: * See fs/select.c in the Linux kernel. Without this,
! 1191: * Maelstrom doesn't work.
! 1192: */
! 1193: if (error == ERESTART)
! 1194: error = EINTR;
! 1195: return error;
! 1196: }
! 1197:
! 1198: if (timeout) {
! 1199: if (*retval) {
! 1200: /*
! 1201: * Compute how much time was left of the timeout,
! 1202: * by subtracting the current time and the time
! 1203: * before we started the call, and subtracting
! 1204: * that result from the user-supplied value.
! 1205: */
! 1206: microtime(&tv1);
! 1207: timersub(&tv1, &tv0, &tv1);
! 1208: timersub(&utv, &tv1, &utv);
! 1209: if (utv.tv_sec < 0)
! 1210: timerclear(&utv);
! 1211: } else
! 1212: timerclear(&utv);
! 1213: if ((error = copyout(&utv, timeout, sizeof(utv))))
! 1214: return error;
! 1215: }
! 1216:
! 1217: return 0;
! 1218: }
! 1219:
! 1220: /*
! 1221: * Get the process group of a certain process. Look it up
! 1222: * and return the value.
! 1223: */
! 1224: int
! 1225: linux_sys_getpgid(p, v, retval)
! 1226: struct proc *p;
! 1227: void *v;
! 1228: register_t *retval;
! 1229: {
! 1230: struct linux_sys_getpgid_args /* {
! 1231: syscallarg(int) pid;
! 1232: } */ *uap = v;
! 1233: struct proc *targp;
! 1234:
! 1235: if (SCARG(uap, pid) != 0 && SCARG(uap, pid) != p->p_pid) {
! 1236: if ((targp = pfind(SCARG(uap, pid))) == 0)
! 1237: return ESRCH;
! 1238: }
! 1239: else
! 1240: targp = p;
! 1241:
! 1242: retval[0] = targp->p_pgid;
! 1243: return 0;
! 1244: }
! 1245:
! 1246: /*
! 1247: * Set the 'personality' (emulation mode) for the current process. Only
! 1248: * accept the Linux personality here (0). This call is needed because
! 1249: * the Linux ELF crt0 issues it in an ugly kludge to make sure that
! 1250: * ELF binaries run in Linux mode, not SVR4 mode.
! 1251: */
! 1252: int
! 1253: linux_sys_personality(p, v, retval)
! 1254: struct proc *p;
! 1255: void *v;
! 1256: register_t *retval;
! 1257: {
! 1258: struct linux_sys_personality_args /* {
! 1259: syscallarg(int) per;
! 1260: } */ *uap = v;
! 1261:
! 1262: if (SCARG(uap, per) != 0)
! 1263: return EINVAL;
! 1264: retval[0] = 0;
! 1265: return 0;
! 1266: }
! 1267:
! 1268: /*
! 1269: * The calls are here because of type conversions.
! 1270: */
! 1271: int
! 1272: linux_sys_setreuid16(p, v, retval)
! 1273: struct proc *p;
! 1274: void *v;
! 1275: register_t *retval;
! 1276: {
! 1277: struct linux_sys_setreuid16_args /* {
! 1278: syscallarg(int) ruid;
! 1279: syscallarg(int) euid;
! 1280: } */ *uap = v;
! 1281: struct sys_setreuid_args bsa;
! 1282:
! 1283: SCARG(&bsa, ruid) = ((linux_uid_t)SCARG(uap, ruid) == (linux_uid_t)-1) ?
! 1284: (uid_t)-1 : SCARG(uap, ruid);
! 1285: SCARG(&bsa, euid) = ((linux_uid_t)SCARG(uap, euid) == (linux_uid_t)-1) ?
! 1286: (uid_t)-1 : SCARG(uap, euid);
! 1287:
! 1288: return sys_setreuid(p, &bsa, retval);
! 1289: }
! 1290:
! 1291: int
! 1292: linux_sys_setregid16(p, v, retval)
! 1293: struct proc *p;
! 1294: void *v;
! 1295: register_t *retval;
! 1296: {
! 1297: struct linux_sys_setregid16_args /* {
! 1298: syscallarg(int) rgid;
! 1299: syscallarg(int) egid;
! 1300: } */ *uap = v;
! 1301: struct sys_setregid_args bsa;
! 1302:
! 1303: SCARG(&bsa, rgid) = ((linux_gid_t)SCARG(uap, rgid) == (linux_gid_t)-1) ?
! 1304: (uid_t)-1 : SCARG(uap, rgid);
! 1305: SCARG(&bsa, egid) = ((linux_gid_t)SCARG(uap, egid) == (linux_gid_t)-1) ?
! 1306: (uid_t)-1 : SCARG(uap, egid);
! 1307:
! 1308: return sys_setregid(p, &bsa, retval);
! 1309: }
! 1310:
! 1311: int
! 1312: linux_sys_getsid(p, v, retval)
! 1313: struct proc *p;
! 1314: void *v;
! 1315: register_t *retval;
! 1316: {
! 1317: struct linux_sys_getsid_args /* {
! 1318: syscallarg(int) pid;
! 1319: } */ *uap = v;
! 1320: struct proc *p1;
! 1321: pid_t pid;
! 1322:
! 1323: pid = (pid_t)SCARG(uap, pid);
! 1324:
! 1325: if (pid == 0) {
! 1326: retval[0] = (int)p->p_session; /* XXX Oh well */
! 1327: return 0;
! 1328: }
! 1329:
! 1330: p1 = pfind((int)pid);
! 1331: if (p1 == NULL)
! 1332: return ESRCH;
! 1333:
! 1334: retval[0] = (int)p1->p_session;
! 1335: return 0;
! 1336: }
! 1337:
! 1338: int
! 1339: linux_sys___sysctl(p, v, retval)
! 1340: struct proc *p;
! 1341: void *v;
! 1342: register_t *retval;
! 1343: {
! 1344: struct linux_sys___sysctl_args /* {
! 1345: syscallarg(struct linux___sysctl *) lsp;
! 1346: } */ *uap = v;
! 1347: struct linux___sysctl ls;
! 1348: struct sys___sysctl_args bsa;
! 1349: int error;
! 1350:
! 1351: if ((error = copyin(SCARG(uap, lsp), &ls, sizeof ls)))
! 1352: return error;
! 1353: SCARG(&bsa, name) = ls.name;
! 1354: SCARG(&bsa, namelen) = ls.namelen;
! 1355: SCARG(&bsa, old) = ls.old;
! 1356: SCARG(&bsa, oldlenp) = ls.oldlenp;
! 1357: SCARG(&bsa, new) = ls.new;
! 1358: SCARG(&bsa, newlen) = ls.newlen;
! 1359:
! 1360: return sys___sysctl(p, &bsa, retval);
! 1361: }
! 1362:
! 1363: /*
! 1364: * We have nonexistent fsuid equal to uid.
! 1365: * If modification is requested, refuse.
! 1366: */
! 1367: int
! 1368: linux_sys_setfsuid(p, v, retval)
! 1369: struct proc *p;
! 1370: void *v;
! 1371: register_t *retval;
! 1372: {
! 1373: struct linux_sys_setfsuid_args /* {
! 1374: syscallarg(uid_t) uid;
! 1375: } */ *uap = v;
! 1376: uid_t uid;
! 1377:
! 1378: uid = SCARG(uap, uid);
! 1379: if (p->p_cred->p_ruid != uid)
! 1380: return sys_nosys(p, v, retval);
! 1381: else
! 1382: return (0);
! 1383: }
! 1384:
! 1385: int
! 1386: linux_sys_getfsuid(p, v, retval)
! 1387: struct proc *p;
! 1388: void *v;
! 1389: register_t *retval;
! 1390: {
! 1391: return sys_getuid(p, v, retval);
! 1392: }
! 1393:
! 1394:
! 1395: int
! 1396: linux_sys_nice(p, v, retval)
! 1397: struct proc *p;
! 1398: void *v;
! 1399: register_t *retval;
! 1400: {
! 1401: struct linux_sys_nice_args /* {
! 1402: syscallarg(int) incr;
! 1403: } */ *uap = v;
! 1404: struct sys_setpriority_args bsa;
! 1405:
! 1406: SCARG(&bsa, which) = PRIO_PROCESS;
! 1407: SCARG(&bsa, who) = 0;
! 1408: SCARG(&bsa, prio) = SCARG(uap, incr);
! 1409: return sys_setpriority(p, &bsa, retval);
! 1410: }
! 1411:
! 1412: int
! 1413: linux_sys_stime(p, v, retval)
! 1414: struct proc *p;
! 1415: void *v;
! 1416: register_t *retval;
! 1417: {
! 1418: struct linux_sys_time_args /* {
! 1419: linux_time_t *t;
! 1420: } */ *uap = v;
! 1421: struct timespec ats;
! 1422: linux_time_t tt;
! 1423: int error;
! 1424:
! 1425: if ((error = suser(p, 0)) != 0)
! 1426: return (error);
! 1427:
! 1428: if ((error = copyin(SCARG(uap, t), &tt, sizeof(tt))) != 0)
! 1429: return (error);
! 1430:
! 1431: ats.tv_sec = tt;
! 1432: ats.tv_nsec = 0;
! 1433:
! 1434: error = settime(&ats);
! 1435:
! 1436: return (error);
! 1437: }
! 1438:
! 1439: int
! 1440: linux_sys_getpid(p, v, retval)
! 1441: struct proc *p;
! 1442: void *v;
! 1443: register_t *retval;
! 1444: {
! 1445:
! 1446: *retval = p->p_pid;
! 1447: return (0);
! 1448: }
! 1449:
! 1450: int
! 1451: linux_sys_getuid(p, v, retval)
! 1452: struct proc *p;
! 1453: void *v;
! 1454: register_t *retval;
! 1455: {
! 1456:
! 1457: *retval = p->p_cred->p_ruid;
! 1458: return (0);
! 1459: }
! 1460:
! 1461: int
! 1462: linux_sys_getgid(p, v, retval)
! 1463: struct proc *p;
! 1464: void *v;
! 1465: register_t *retval;
! 1466: {
! 1467:
! 1468: *retval = p->p_cred->p_rgid;
! 1469: return (0);
! 1470: }
! 1471:
! 1472:
! 1473: /*
! 1474: * sysinfo()
! 1475: */
! 1476: /* ARGSUSED */
! 1477: int
! 1478: linux_sys_sysinfo(p, v, retval)
! 1479: struct proc *p;
! 1480: void *v;
! 1481: register_t *retval;
! 1482: {
! 1483: struct linux_sys_sysinfo_args /* {
! 1484: syscallarg(struct linux_sysinfo *) sysinfo;
! 1485: } */ *uap = v;
! 1486: struct linux_sysinfo si;
! 1487: struct loadavg *la;
! 1488: extern int bufpages;
! 1489: struct timeval tv;
! 1490:
! 1491: getmicrouptime(&tv);
! 1492: si.uptime = tv.tv_sec;
! 1493: la = &averunnable;
! 1494: si.loads[0] = la->ldavg[0] * LINUX_SYSINFO_LOADS_SCALE / la->fscale;
! 1495: si.loads[1] = la->ldavg[1] * LINUX_SYSINFO_LOADS_SCALE / la->fscale;
! 1496: si.loads[2] = la->ldavg[2] * LINUX_SYSINFO_LOADS_SCALE / la->fscale;
! 1497: si.totalram = ctob(physmem);
! 1498: si.freeram = uvmexp.free * uvmexp.pagesize;
! 1499: si.sharedram = 0;/* XXX */
! 1500: si.bufferram = bufpages * PAGE_SIZE;
! 1501: si.totalswap = uvmexp.swpages * PAGE_SIZE;
! 1502: si.freeswap = (uvmexp.swpages - uvmexp.swpginuse) * PAGE_SIZE;
! 1503: si.procs = nprocs;
! 1504: /* The following are only present in newer Linux kernels. */
! 1505: si.totalbig = 0;
! 1506: si.freebig = 0;
! 1507: si.mem_unit = 1;
! 1508:
! 1509: return (copyout(&si, SCARG(uap, sysinfo), sizeof(si)));
! 1510: }
CVSweb