2007-03-14 15:44:39 +03:00
|
|
|
/* $NetBSD: linux_misc.c,v 1.168 2007/03/14 12:44:39 njoly Exp $ */
|
1998-10-01 08:05:54 +04:00
|
|
|
|
|
|
|
/*-
|
1999-05-14 03:42:34 +04:00
|
|
|
* Copyright (c) 1995, 1998, 1999 The NetBSD Foundation, Inc.
|
1998-10-01 08:05:54 +04:00
|
|
|
* All rights reserved.
|
|
|
|
*
|
|
|
|
* This code is derived from software contributed to The NetBSD Foundation
|
1999-05-14 03:42:34 +04:00
|
|
|
* by Frank van der Linden and Eric Haszlakiewicz; by Jason R. Thorpe
|
|
|
|
* of the Numerical Aerospace Simulation Facility, NASA Ames Research Center.
|
1998-10-01 08:05:54 +04:00
|
|
|
*
|
|
|
|
* Redistribution and use in source and binary forms, with or without
|
|
|
|
* modification, are permitted provided that the following conditions
|
|
|
|
* are met:
|
|
|
|
* 1. Redistributions of source code must retain the above copyright
|
|
|
|
* notice, this list of conditions and the following disclaimer.
|
|
|
|
* 2. Redistributions in binary form must reproduce the above copyright
|
|
|
|
* notice, this list of conditions and the following disclaimer in the
|
|
|
|
* documentation and/or other materials provided with the distribution.
|
|
|
|
* 3. All advertising materials mentioning features or use of this software
|
|
|
|
* must display the following acknowledgement:
|
|
|
|
* This product includes software developed by the NetBSD
|
|
|
|
* Foundation, Inc. and its contributors.
|
|
|
|
* 4. Neither the name of The NetBSD Foundation nor the names of its
|
|
|
|
* contributors may be used to endorse or promote products derived
|
|
|
|
* from this software without specific prior written permission.
|
|
|
|
*
|
|
|
|
* THIS SOFTWARE IS PROVIDED BY THE NETBSD FOUNDATION, INC. AND CONTRIBUTORS
|
|
|
|
* ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED
|
|
|
|
* TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
|
|
|
|
* PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE FOUNDATION OR CONTRIBUTORS
|
|
|
|
* BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
|
|
|
|
* CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
|
|
|
|
* SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
|
|
|
|
* INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
|
|
|
|
* CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
|
|
|
|
* ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
|
|
|
|
* POSSIBILITY OF SUCH DAMAGE.
|
|
|
|
*/
|
1995-03-01 02:24:35 +03:00
|
|
|
|
|
|
|
/*
|
|
|
|
* Linux compatibility module. Try to deal with various Linux system calls.
|
|
|
|
*/
|
|
|
|
|
1998-10-01 08:05:54 +04:00
|
|
|
/*
|
|
|
|
* These functions have been moved to multiarch to allow
|
2005-02-27 01:58:54 +03:00
|
|
|
* selection of which machines include them to be
|
1998-10-01 08:05:54 +04:00
|
|
|
* determined by the individual files.linux_<arch> files.
|
|
|
|
*
|
|
|
|
* Function in multiarch:
|
|
|
|
* linux_sys_break : linux_break.c
|
|
|
|
* linux_sys_alarm : linux_misc_notalpha.c
|
1999-05-14 22:44:50 +04:00
|
|
|
* linux_sys_getresgid : linux_misc_notalpha.c
|
1998-10-01 08:05:54 +04:00
|
|
|
* linux_sys_nice : linux_misc_notalpha.c
|
|
|
|
* linux_sys_readdir : linux_misc_notalpha.c
|
1999-05-14 22:44:50 +04:00
|
|
|
* linux_sys_setresgid : linux_misc_notalpha.c
|
1998-10-01 08:05:54 +04:00
|
|
|
* linux_sys_time : linux_misc_notalpha.c
|
|
|
|
* linux_sys_utime : linux_misc_notalpha.c
|
|
|
|
* linux_sys_waitpid : linux_misc_notalpha.c
|
|
|
|
* linux_sys_old_mmap : linux_oldmmap.c
|
|
|
|
* linux_sys_oldolduname : linux_oldolduname.c
|
|
|
|
* linux_sys_oldselect : linux_oldselect.c
|
|
|
|
* linux_sys_olduname : linux_olduname.c
|
|
|
|
* linux_sys_pipe : linux_pipe.c
|
|
|
|
*/
|
|
|
|
|
2001-11-13 05:07:52 +03:00
|
|
|
#include <sys/cdefs.h>
|
2007-03-14 15:44:39 +03:00
|
|
|
__KERNEL_RCSID(0, "$NetBSD: linux_misc.c,v 1.168 2007/03/14 12:44:39 njoly Exp $");
|
2006-08-30 15:14:39 +04:00
|
|
|
|
2006-08-30 21:14:34 +04:00
|
|
|
#if defined(_KERNEL_OPT)
|
2006-08-30 15:14:39 +04:00
|
|
|
#include "opt_ptrace.h"
|
2006-08-30 21:14:34 +04:00
|
|
|
#endif
|
2001-11-13 05:07:52 +03:00
|
|
|
|
1995-03-01 02:24:35 +03:00
|
|
|
#include <sys/param.h>
|
|
|
|
#include <sys/systm.h>
|
|
|
|
#include <sys/namei.h>
|
|
|
|
#include <sys/proc.h>
|
1996-08-10 13:08:26 +04:00
|
|
|
#include <sys/dirent.h>
|
1995-03-01 02:24:35 +03:00
|
|
|
#include <sys/file.h>
|
|
|
|
#include <sys/stat.h>
|
|
|
|
#include <sys/filedesc.h>
|
|
|
|
#include <sys/ioctl.h>
|
|
|
|
#include <sys/kernel.h>
|
|
|
|
#include <sys/malloc.h>
|
|
|
|
#include <sys/mbuf.h>
|
|
|
|
#include <sys/mman.h>
|
|
|
|
#include <sys/mount.h>
|
2000-03-19 01:23:13 +03:00
|
|
|
#include <sys/reboot.h>
|
1995-03-01 02:24:35 +03:00
|
|
|
#include <sys/resource.h>
|
|
|
|
#include <sys/resourcevar.h>
|
|
|
|
#include <sys/signal.h>
|
|
|
|
#include <sys/signalvar.h>
|
|
|
|
#include <sys/socket.h>
|
|
|
|
#include <sys/time.h>
|
|
|
|
#include <sys/times.h>
|
|
|
|
#include <sys/vnode.h>
|
|
|
|
#include <sys/uio.h>
|
|
|
|
#include <sys/wait.h>
|
|
|
|
#include <sys/utsname.h>
|
|
|
|
#include <sys/unistd.h>
|
2000-12-02 00:14:42 +03:00
|
|
|
#include <sys/swap.h> /* for SWAP_ON */
|
|
|
|
#include <sys/sysctl.h> /* for KERN_DOMAINNAME */
|
2006-05-15 01:19:33 +04:00
|
|
|
#include <sys/kauth.h>
|
1995-03-01 02:24:35 +03:00
|
|
|
|
2000-11-01 23:56:30 +03:00
|
|
|
#include <sys/ptrace.h>
|
|
|
|
#include <machine/ptrace.h>
|
|
|
|
|
2006-09-02 01:20:46 +04:00
|
|
|
#include <sys/syscall.h>
|
1995-03-01 02:24:35 +03:00
|
|
|
#include <sys/syscallargs.h>
|
|
|
|
|
2005-11-07 17:17:45 +03:00
|
|
|
#include <compat/linux/common/linux_machdep.h>
|
1998-10-04 00:17:36 +04:00
|
|
|
#include <compat/linux/common/linux_types.h>
|
|
|
|
#include <compat/linux/common/linux_signal.h>
|
|
|
|
|
1995-03-01 02:24:35 +03:00
|
|
|
#include <compat/linux/linux_syscallargs.h>
|
1998-10-04 00:17:36 +04:00
|
|
|
|
|
|
|
#include <compat/linux/common/linux_fcntl.h>
|
|
|
|
#include <compat/linux/common/linux_mmap.h>
|
|
|
|
#include <compat/linux/common/linux_dirent.h>
|
|
|
|
#include <compat/linux/common/linux_util.h>
|
|
|
|
#include <compat/linux/common/linux_misc.h>
|
2006-02-09 22:18:56 +03:00
|
|
|
#ifndef COMPAT_LINUX32
|
|
|
|
#include <compat/linux/common/linux_limit.h>
|
|
|
|
#endif
|
1999-12-16 18:09:49 +03:00
|
|
|
#include <compat/linux/common/linux_ptrace.h>
|
2000-03-19 01:23:13 +03:00
|
|
|
#include <compat/linux/common/linux_reboot.h>
|
2001-03-15 22:18:20 +03:00
|
|
|
#include <compat/linux/common/linux_emuldata.h>
|
1999-12-16 18:09:49 +03:00
|
|
|
|
2006-02-09 22:18:56 +03:00
|
|
|
#ifndef COMPAT_LINUX32
|
2000-11-01 23:56:30 +03:00
|
|
|
const int linux_ptrace_request_map[] = {
|
1999-12-16 18:09:49 +03:00
|
|
|
LINUX_PTRACE_TRACEME, PT_TRACE_ME,
|
|
|
|
LINUX_PTRACE_PEEKTEXT, PT_READ_I,
|
|
|
|
LINUX_PTRACE_PEEKDATA, PT_READ_D,
|
|
|
|
LINUX_PTRACE_POKETEXT, PT_WRITE_I,
|
|
|
|
LINUX_PTRACE_POKEDATA, PT_WRITE_D,
|
|
|
|
LINUX_PTRACE_CONT, PT_CONTINUE,
|
|
|
|
LINUX_PTRACE_KILL, PT_KILL,
|
|
|
|
LINUX_PTRACE_ATTACH, PT_ATTACH,
|
|
|
|
LINUX_PTRACE_DETACH, PT_DETACH,
|
2006-02-09 22:18:56 +03:00
|
|
|
# ifdef PT_STEP
|
2000-11-01 23:56:30 +03:00
|
|
|
LINUX_PTRACE_SINGLESTEP, PT_STEP,
|
2006-02-09 22:18:56 +03:00
|
|
|
# endif
|
1999-12-16 18:09:49 +03:00
|
|
|
-1
|
|
|
|
};
|
1995-03-01 02:24:35 +03:00
|
|
|
|
2004-09-20 22:41:07 +04:00
|
|
|
const struct linux_mnttypes linux_fstypes[] = {
|
2002-02-20 20:03:03 +03:00
|
|
|
{ MOUNT_FFS, LINUX_DEFAULT_SUPER_MAGIC },
|
|
|
|
{ MOUNT_NFS, LINUX_NFS_SUPER_MAGIC },
|
|
|
|
{ MOUNT_MFS, LINUX_DEFAULT_SUPER_MAGIC },
|
|
|
|
{ MOUNT_MSDOS, LINUX_MSDOS_SUPER_MAGIC },
|
|
|
|
{ MOUNT_LFS, LINUX_DEFAULT_SUPER_MAGIC },
|
|
|
|
{ MOUNT_FDESC, LINUX_DEFAULT_SUPER_MAGIC },
|
|
|
|
{ MOUNT_PORTAL, LINUX_DEFAULT_SUPER_MAGIC },
|
|
|
|
{ MOUNT_NULL, LINUX_DEFAULT_SUPER_MAGIC },
|
2005-02-27 01:58:54 +03:00
|
|
|
{ MOUNT_OVERLAY, LINUX_DEFAULT_SUPER_MAGIC },
|
2002-02-20 20:03:03 +03:00
|
|
|
{ MOUNT_UMAP, LINUX_DEFAULT_SUPER_MAGIC },
|
|
|
|
{ MOUNT_KERNFS, LINUX_DEFAULT_SUPER_MAGIC },
|
|
|
|
{ MOUNT_PROCFS, LINUX_PROC_SUPER_MAGIC },
|
|
|
|
{ MOUNT_AFS, LINUX_DEFAULT_SUPER_MAGIC },
|
|
|
|
{ MOUNT_CD9660, LINUX_ISOFS_SUPER_MAGIC },
|
|
|
|
{ MOUNT_UNION, LINUX_DEFAULT_SUPER_MAGIC },
|
|
|
|
{ MOUNT_ADOSFS, LINUX_ADFS_SUPER_MAGIC },
|
|
|
|
{ MOUNT_EXT2FS, LINUX_EXT2_SUPER_MAGIC },
|
|
|
|
{ MOUNT_CFS, LINUX_DEFAULT_SUPER_MAGIC },
|
|
|
|
{ MOUNT_CODA, LINUX_CODA_SUPER_MAGIC },
|
|
|
|
{ MOUNT_FILECORE, LINUX_DEFAULT_SUPER_MAGIC },
|
|
|
|
{ MOUNT_NTFS, LINUX_DEFAULT_SUPER_MAGIC },
|
2004-11-13 10:19:27 +03:00
|
|
|
{ MOUNT_SMBFS, LINUX_SMB_SUPER_MAGIC },
|
2005-09-10 23:20:48 +04:00
|
|
|
{ MOUNT_PTYFS, LINUX_DEVPTS_SUPER_MAGIC },
|
|
|
|
{ MOUNT_TMPFS, LINUX_DEFAULT_SUPER_MAGIC }
|
2002-02-20 20:03:03 +03:00
|
|
|
};
|
2004-09-20 22:41:07 +04:00
|
|
|
const int linux_fstypes_cnt = sizeof(linux_fstypes) / sizeof(linux_fstypes[0]);
|
2002-02-20 20:03:03 +03:00
|
|
|
|
2006-02-09 22:18:56 +03:00
|
|
|
# ifdef DEBUG_LINUX
|
2002-03-22 20:14:18 +03:00
|
|
|
#define DPRINTF(a) uprintf a
|
2006-02-09 22:18:56 +03:00
|
|
|
# else
|
2002-03-22 20:14:18 +03:00
|
|
|
#define DPRINTF(a)
|
2006-02-09 22:18:56 +03:00
|
|
|
# endif
|
2002-03-22 20:14:18 +03:00
|
|
|
|
1998-10-01 08:05:54 +04:00
|
|
|
/* Local linux_misc.c functions: */
|
2004-04-21 05:05:31 +04:00
|
|
|
static void bsd_to_linux_statfs __P((const struct statvfs *,
|
|
|
|
struct linux_statfs *));
|
2003-06-24 01:25:56 +04:00
|
|
|
static void linux_to_bsd_mmap_args __P((struct sys_mmap_args *,
|
|
|
|
const struct linux_sys_mmap_args *));
|
2004-08-29 18:08:06 +04:00
|
|
|
static int linux_mmap __P((struct lwp *, struct linux_sys_mmap_args *,
|
|
|
|
register_t *, off_t));
|
|
|
|
|
1996-04-05 03:56:01 +04:00
|
|
|
|
1995-03-01 02:24:35 +03:00
|
|
|
/*
|
|
|
|
* The information on a terminated (or stopped) process needs
|
|
|
|
* to be converted in order for Linux binaries to get a valid signal
|
|
|
|
* number out of it.
|
|
|
|
*/
|
1998-10-01 08:05:54 +04:00
|
|
|
void
|
1998-12-16 13:21:50 +03:00
|
|
|
bsd_to_linux_wstat(st)
|
|
|
|
int *st;
|
1995-03-01 02:24:35 +03:00
|
|
|
{
|
1995-10-07 09:25:19 +03:00
|
|
|
|
1998-12-16 13:21:50 +03:00
|
|
|
int sig;
|
|
|
|
|
|
|
|
if (WIFSIGNALED(*st)) {
|
|
|
|
sig = WTERMSIG(*st);
|
|
|
|
if (sig >= 0 && sig < NSIG)
|
2002-04-01 02:22:43 +04:00
|
|
|
*st= (*st& ~0177) | native_to_linux_signo[sig];
|
1998-12-16 13:21:50 +03:00
|
|
|
} else if (WIFSTOPPED(*st)) {
|
|
|
|
sig = WSTOPSIG(*st);
|
|
|
|
if (sig >= 0 && sig < NSIG)
|
2002-04-01 02:22:43 +04:00
|
|
|
*st = (*st & ~0xff00) |
|
|
|
|
(native_to_linux_signo[sig] << 8);
|
1998-12-16 13:21:50 +03:00
|
|
|
}
|
1995-03-01 02:24:35 +03:00
|
|
|
}
|
|
|
|
|
|
|
|
/*
|
2004-10-07 23:30:28 +04:00
|
|
|
* wait4(2). Passed on to the NetBSD call, surrounded by code to
|
|
|
|
* reserve some space for a NetBSD-style wait status, and converting
|
|
|
|
* it to what Linux wants.
|
1995-03-01 02:24:35 +03:00
|
|
|
*/
|
|
|
|
int
|
2003-01-18 11:02:46 +03:00
|
|
|
linux_sys_wait4(l, v, retval)
|
|
|
|
struct lwp *l;
|
1995-09-20 02:37:27 +04:00
|
|
|
void *v;
|
|
|
|
register_t *retval;
|
|
|
|
{
|
1995-10-07 09:25:19 +03:00
|
|
|
struct linux_sys_wait4_args /* {
|
1995-03-01 02:24:35 +03:00
|
|
|
syscallarg(int) pid;
|
|
|
|
syscallarg(int *) status;
|
|
|
|
syscallarg(int) options;
|
|
|
|
syscallarg(struct rusage *) rusage;
|
1995-09-20 02:37:27 +04:00
|
|
|
} */ *uap = v;
|
2003-01-18 11:02:46 +03:00
|
|
|
struct proc *p = l->l_proc;
|
1995-10-07 09:25:19 +03:00
|
|
|
struct sys_wait4_args w4a;
|
1999-05-13 05:00:50 +04:00
|
|
|
int error, *status, tstat, options, linux_options;
|
2007-03-04 08:59:00 +03:00
|
|
|
void *sg;
|
1995-03-01 02:24:35 +03:00
|
|
|
|
1995-08-22 03:15:51 +04:00
|
|
|
if (SCARG(uap, status) != NULL) {
|
2002-03-16 23:43:48 +03:00
|
|
|
sg = stackgap_init(p, 0);
|
|
|
|
status = (int *) stackgap_alloc(p, &sg, sizeof *status);
|
1995-08-22 03:15:51 +04:00
|
|
|
} else
|
|
|
|
status = NULL;
|
1995-03-01 02:24:35 +03:00
|
|
|
|
1999-05-13 05:00:50 +04:00
|
|
|
linux_options = SCARG(uap, options);
|
|
|
|
options = 0;
|
2004-10-07 23:30:28 +04:00
|
|
|
if (linux_options & ~(LINUX_WAIT4_KNOWNFLAGS))
|
1999-05-13 05:00:50 +04:00
|
|
|
return (EINVAL);
|
|
|
|
|
|
|
|
if (linux_options & LINUX_WAIT4_WNOHANG)
|
|
|
|
options |= WNOHANG;
|
|
|
|
if (linux_options & LINUX_WAIT4_WUNTRACED)
|
|
|
|
options |= WUNTRACED;
|
2001-07-18 23:11:14 +04:00
|
|
|
if (linux_options & LINUX_WAIT4_WALL)
|
|
|
|
options |= WALLSIG;
|
1999-05-13 05:00:50 +04:00
|
|
|
if (linux_options & LINUX_WAIT4_WCLONE)
|
|
|
|
options |= WALTSIG;
|
2006-02-09 22:18:56 +03:00
|
|
|
# ifdef DIAGNOSTIC
|
2004-10-07 23:30:28 +04:00
|
|
|
if (linux_options & LINUX_WAIT4_WNOTHREAD)
|
|
|
|
printf("WARNING: %s: linux process %d.%d called "
|
|
|
|
"waitpid with __WNOTHREAD set!",
|
|
|
|
__FILE__, p->p_pid, l->l_lid);
|
|
|
|
|
2006-02-09 22:18:56 +03:00
|
|
|
# endif
|
1999-05-13 05:00:50 +04:00
|
|
|
|
1995-03-01 02:24:35 +03:00
|
|
|
SCARG(&w4a, pid) = SCARG(uap, pid);
|
|
|
|
SCARG(&w4a, status) = status;
|
1999-05-13 05:00:50 +04:00
|
|
|
SCARG(&w4a, options) = options;
|
1995-03-01 02:24:35 +03:00
|
|
|
SCARG(&w4a, rusage) = SCARG(uap, rusage);
|
|
|
|
|
2003-01-18 11:02:46 +03:00
|
|
|
if ((error = sys_wait4(l, &w4a, retval)))
|
1995-03-01 02:24:35 +03:00
|
|
|
return error;
|
|
|
|
|
2007-02-10 00:55:00 +03:00
|
|
|
sigdelset(&p->p_sigpend.sp_set, SIGCHLD); /* XXXAD ksiginfo leak */
|
1995-09-08 01:48:59 +04:00
|
|
|
|
1995-08-22 03:15:51 +04:00
|
|
|
if (status != NULL) {
|
|
|
|
if ((error = copyin(status, &tstat, sizeof tstat)))
|
|
|
|
return error;
|
|
|
|
|
|
|
|
bsd_to_linux_wstat(&tstat);
|
|
|
|
return copyout(&tstat, SCARG(uap, status), sizeof tstat);
|
|
|
|
}
|
1995-03-01 02:24:35 +03:00
|
|
|
|
1995-08-22 03:15:51 +04:00
|
|
|
return 0;
|
1995-03-01 02:24:35 +03:00
|
|
|
}
|
|
|
|
|
|
|
|
/*
|
|
|
|
* Linux brk(2). The check if the new address is >= the old one is
|
|
|
|
* done in the kernel in Linux. NetBSD does it in the library.
|
|
|
|
*/
|
|
|
|
int
|
2003-01-18 11:02:46 +03:00
|
|
|
linux_sys_brk(l, v, retval)
|
|
|
|
struct lwp *l;
|
1995-09-20 02:37:27 +04:00
|
|
|
void *v;
|
1995-03-01 02:24:35 +03:00
|
|
|
register_t *retval;
|
|
|
|
{
|
1995-10-07 09:25:19 +03:00
|
|
|
struct linux_sys_brk_args /* {
|
1995-09-20 02:37:27 +04:00
|
|
|
syscallarg(char *) nsize;
|
|
|
|
} */ *uap = v;
|
2003-01-18 11:02:46 +03:00
|
|
|
struct proc *p = l->l_proc;
|
1995-03-01 02:24:35 +03:00
|
|
|
char *nbrk = SCARG(uap, nsize);
|
1995-10-07 09:25:19 +03:00
|
|
|
struct sys_obreak_args oba;
|
1995-03-01 02:24:35 +03:00
|
|
|
struct vmspace *vm = p->p_vmspace;
|
2001-03-16 02:23:26 +03:00
|
|
|
struct linux_emuldata *ed = (struct linux_emuldata*)p->p_emuldata;
|
1995-03-01 02:24:35 +03:00
|
|
|
|
|
|
|
SCARG(&oba, nsize) = nbrk;
|
|
|
|
|
2007-03-04 08:59:00 +03:00
|
|
|
if ((void *) nbrk > vm->vm_daddr && sys_obreak(l, &oba, retval) == 0)
|
2004-08-08 13:40:50 +04:00
|
|
|
ed->s->p_break = (char*)nbrk;
|
2005-02-27 01:58:54 +03:00
|
|
|
else
|
2004-08-08 13:40:50 +04:00
|
|
|
nbrk = ed->s->p_break;
|
2001-03-16 02:23:26 +03:00
|
|
|
|
|
|
|
retval[0] = (register_t)nbrk;
|
1995-03-01 02:24:35 +03:00
|
|
|
|
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
|
|
|
|
/*
|
2004-09-19 20:50:11 +04:00
|
|
|
* Convert NetBSD statvfs structure to Linux statfs structure.
|
|
|
|
* Linux doesn't have f_flag, and we can't set f_frsize due
|
|
|
|
* to glibc statvfs() bug (see below).
|
1995-03-06 02:23:37 +03:00
|
|
|
*/
|
|
|
|
static void
|
|
|
|
bsd_to_linux_statfs(bsp, lsp)
|
2004-04-21 05:05:31 +04:00
|
|
|
const struct statvfs *bsp;
|
1995-03-06 02:23:37 +03:00
|
|
|
struct linux_statfs *lsp;
|
|
|
|
{
|
2002-02-20 20:03:03 +03:00
|
|
|
int i;
|
|
|
|
|
2004-09-20 22:41:07 +04:00
|
|
|
for (i = 0; i < linux_fstypes_cnt; i++) {
|
|
|
|
if (strcmp(bsp->f_fstypename, linux_fstypes[i].bsd) == 0) {
|
|
|
|
lsp->l_ftype = linux_fstypes[i].linux;
|
2002-02-20 20:03:03 +03:00
|
|
|
break;
|
2004-09-20 22:41:07 +04:00
|
|
|
}
|
|
|
|
}
|
2002-02-20 20:03:03 +03:00
|
|
|
|
2004-09-20 22:41:07 +04:00
|
|
|
if (i == linux_fstypes_cnt) {
|
2002-03-22 20:14:18 +03:00
|
|
|
DPRINTF(("unhandled fstype in linux emulation: %s\n",
|
|
|
|
bsp->f_fstypename));
|
2002-02-20 20:03:03 +03:00
|
|
|
lsp->l_ftype = LINUX_DEFAULT_SUPER_MAGIC;
|
|
|
|
}
|
1995-10-07 09:25:19 +03:00
|
|
|
|
2004-09-19 20:50:11 +04:00
|
|
|
/*
|
|
|
|
* The sizes are expressed in number of blocks. The block
|
|
|
|
* size used for the size is f_frsize for POSIX-compliant
|
|
|
|
* statvfs. Linux statfs uses f_bsize as the block size
|
|
|
|
* (f_frsize used to not be available in Linux struct statfs).
|
|
|
|
* However, glibc 2.3.3 statvfs() wrapper fails to adjust the block
|
|
|
|
* counts for different f_frsize if f_frsize is provided by the kernel.
|
|
|
|
* POSIX conforming apps thus get wrong size if f_frsize
|
|
|
|
* is different to f_bsize. Thus, we just pretend we don't
|
|
|
|
* support f_frsize.
|
|
|
|
*/
|
|
|
|
|
2004-09-14 00:09:44 +04:00
|
|
|
lsp->l_fbsize = bsp->f_frsize;
|
2004-09-19 20:50:11 +04:00
|
|
|
lsp->l_ffrsize = 0; /* compat */
|
1995-03-06 02:23:37 +03:00
|
|
|
lsp->l_fblocks = bsp->f_blocks;
|
|
|
|
lsp->l_fbfree = bsp->f_bfree;
|
|
|
|
lsp->l_fbavail = bsp->f_bavail;
|
|
|
|
lsp->l_ffiles = bsp->f_files;
|
|
|
|
lsp->l_fffree = bsp->f_ffree;
|
2002-02-20 20:03:03 +03:00
|
|
|
/* Linux sets the fsid to 0..., we don't */
|
2004-04-21 05:05:31 +04:00
|
|
|
lsp->l_ffsid.val[0] = bsp->f_fsidx.__fsid_val[0];
|
|
|
|
lsp->l_ffsid.val[1] = bsp->f_fsidx.__fsid_val[1];
|
2004-09-14 00:09:44 +04:00
|
|
|
lsp->l_fnamelen = bsp->f_namemax;
|
2002-02-20 20:03:03 +03:00
|
|
|
(void)memset(lsp->l_fspare, 0, sizeof(lsp->l_fspare));
|
1995-03-06 02:23:37 +03:00
|
|
|
}
|
|
|
|
|
|
|
|
/*
|
|
|
|
* Implement the fs stat functions. Straightforward.
|
1995-03-01 02:24:35 +03:00
|
|
|
*/
|
|
|
|
int
|
2003-01-18 11:02:46 +03:00
|
|
|
linux_sys_statfs(l, v, retval)
|
|
|
|
struct lwp *l;
|
1995-09-20 02:37:27 +04:00
|
|
|
void *v;
|
|
|
|
register_t *retval;
|
|
|
|
{
|
1995-10-07 09:25:19 +03:00
|
|
|
struct linux_sys_statfs_args /* {
|
1999-02-09 23:37:19 +03:00
|
|
|
syscallarg(const char *) path;
|
1995-03-01 02:24:35 +03:00
|
|
|
syscallarg(struct linux_statfs *) sp;
|
1995-09-20 02:37:27 +04:00
|
|
|
} */ *uap = v;
|
2003-01-18 11:02:46 +03:00
|
|
|
struct proc *p = l->l_proc;
|
2006-05-10 15:05:34 +04:00
|
|
|
struct statvfs *btmp, *bsp;
|
1995-03-06 02:23:37 +03:00
|
|
|
struct linux_statfs ltmp;
|
2004-04-21 06:27:34 +04:00
|
|
|
struct sys_statvfs1_args bsa;
|
2007-03-04 08:59:00 +03:00
|
|
|
void *sg;
|
1995-03-06 02:23:37 +03:00
|
|
|
int error;
|
|
|
|
|
2002-03-16 23:43:48 +03:00
|
|
|
sg = stackgap_init(p, 0);
|
2006-05-10 15:05:34 +04:00
|
|
|
bsp = stackgap_alloc(p, &sg, sizeof (struct statvfs));
|
1995-03-06 02:23:37 +03:00
|
|
|
|
2005-12-11 15:16:03 +03:00
|
|
|
CHECK_ALT_EXIST(l, &sg, SCARG(uap, path));
|
1995-03-06 02:23:37 +03:00
|
|
|
|
|
|
|
SCARG(&bsa, path) = SCARG(uap, path);
|
|
|
|
SCARG(&bsa, buf) = bsp;
|
2004-04-21 06:37:20 +04:00
|
|
|
SCARG(&bsa, flags) = ST_WAIT;
|
1995-03-06 02:23:37 +03:00
|
|
|
|
2004-04-21 06:37:20 +04:00
|
|
|
if ((error = sys_statvfs1(l, &bsa, retval)))
|
1995-03-06 02:23:37 +03:00
|
|
|
return error;
|
|
|
|
|
2006-05-10 15:05:34 +04:00
|
|
|
btmp = STATVFSBUF_GET();
|
|
|
|
error = copyin(bsp, btmp, sizeof(*btmp));
|
|
|
|
if (error) {
|
|
|
|
goto out;
|
|
|
|
}
|
|
|
|
bsd_to_linux_statfs(btmp, <mp);
|
|
|
|
error = copyout(<mp, SCARG(uap, sp), sizeof ltmp);
|
|
|
|
out:
|
|
|
|
STATVFSBUF_PUT(btmp);
|
|
|
|
return error;
|
1995-03-01 02:24:35 +03:00
|
|
|
}
|
|
|
|
|
|
|
|
int
|
2003-01-18 11:02:46 +03:00
|
|
|
linux_sys_fstatfs(l, v, retval)
|
|
|
|
struct lwp *l;
|
1995-09-20 02:37:27 +04:00
|
|
|
void *v;
|
|
|
|
register_t *retval;
|
|
|
|
{
|
1995-10-07 09:25:19 +03:00
|
|
|
struct linux_sys_fstatfs_args /* {
|
1995-03-06 02:23:37 +03:00
|
|
|
syscallarg(int) fd;
|
1995-03-01 02:24:35 +03:00
|
|
|
syscallarg(struct linux_statfs *) sp;
|
1995-09-20 02:37:27 +04:00
|
|
|
} */ *uap = v;
|
2003-01-18 11:02:46 +03:00
|
|
|
struct proc *p = l->l_proc;
|
2006-05-10 15:05:34 +04:00
|
|
|
struct statvfs *btmp, *bsp;
|
1995-03-06 02:23:37 +03:00
|
|
|
struct linux_statfs ltmp;
|
2004-04-21 06:37:20 +04:00
|
|
|
struct sys_fstatvfs1_args bsa;
|
2007-03-04 08:59:00 +03:00
|
|
|
void *sg;
|
1995-03-06 02:23:37 +03:00
|
|
|
int error;
|
|
|
|
|
2002-03-16 23:43:48 +03:00
|
|
|
sg = stackgap_init(p, 0);
|
2006-05-10 15:05:34 +04:00
|
|
|
bsp = stackgap_alloc(p, &sg, sizeof (struct statvfs));
|
1995-03-06 02:23:37 +03:00
|
|
|
|
|
|
|
SCARG(&bsa, fd) = SCARG(uap, fd);
|
|
|
|
SCARG(&bsa, buf) = bsp;
|
2004-04-21 06:37:20 +04:00
|
|
|
SCARG(&bsa, flags) = ST_WAIT;
|
1995-03-06 02:23:37 +03:00
|
|
|
|
2004-04-21 06:37:20 +04:00
|
|
|
if ((error = sys_fstatvfs1(l, &bsa, retval)))
|
1995-03-06 02:23:37 +03:00
|
|
|
return error;
|
|
|
|
|
2006-05-10 15:05:34 +04:00
|
|
|
btmp = STATVFSBUF_GET();
|
|
|
|
error = copyin(bsp, btmp, sizeof(*btmp));
|
|
|
|
if (error) {
|
|
|
|
goto out;
|
|
|
|
}
|
|
|
|
bsd_to_linux_statfs(btmp, <mp);
|
|
|
|
error = copyout(<mp, SCARG(uap, sp), sizeof ltmp);
|
|
|
|
out:
|
|
|
|
STATVFSBUF_PUT(btmp);
|
|
|
|
return error;
|
1995-03-01 02:24:35 +03:00
|
|
|
}
|
|
|
|
|
|
|
|
/*
|
|
|
|
* uname(). Just copy the info from the various strings stored in the
|
|
|
|
* kernel, and put it in the Linux utsname structure. That structure
|
|
|
|
* is almost the same as the NetBSD one, only it has fields 65 characters
|
|
|
|
* long, and an extra domainname field.
|
|
|
|
*/
|
|
|
|
int
|
2006-11-16 04:32:37 +03:00
|
|
|
linux_sys_uname(struct lwp *l, void *v, register_t *retval)
|
1995-03-01 02:24:35 +03:00
|
|
|
{
|
1995-10-07 09:25:19 +03:00
|
|
|
struct linux_sys_uname_args /* {
|
1995-09-20 02:37:27 +04:00
|
|
|
syscallarg(struct linux_utsname *) up;
|
|
|
|
} */ *uap = v;
|
1995-08-21 07:42:09 +04:00
|
|
|
struct linux_utsname luts;
|
1995-03-01 02:24:35 +03:00
|
|
|
|
2000-12-30 00:07:16 +03:00
|
|
|
strncpy(luts.l_sysname, linux_sysname, sizeof(luts.l_sysname));
|
1995-08-21 07:42:09 +04:00
|
|
|
strncpy(luts.l_nodename, hostname, sizeof(luts.l_nodename));
|
2000-12-30 00:07:16 +03:00
|
|
|
strncpy(luts.l_release, linux_release, sizeof(luts.l_release));
|
|
|
|
strncpy(luts.l_version, linux_version, sizeof(luts.l_version));
|
2006-02-09 22:18:56 +03:00
|
|
|
# ifdef LINUX_UNAME_ARCH
|
2005-11-04 19:58:14 +03:00
|
|
|
strncpy(luts.l_machine, LINUX_UNAME_ARCH, sizeof(luts.l_machine));
|
2006-02-09 22:18:56 +03:00
|
|
|
# else
|
1995-08-21 07:42:09 +04:00
|
|
|
strncpy(luts.l_machine, machine, sizeof(luts.l_machine));
|
2006-02-09 22:18:56 +03:00
|
|
|
# endif
|
1995-08-21 07:42:09 +04:00
|
|
|
strncpy(luts.l_domainname, domainname, sizeof(luts.l_domainname));
|
1995-03-01 02:24:35 +03:00
|
|
|
|
1995-08-21 07:42:09 +04:00
|
|
|
return copyout(&luts, SCARG(uap, up), sizeof(luts));
|
|
|
|
}
|
|
|
|
|
1998-10-01 08:05:54 +04:00
|
|
|
/* Used directly on: alpha, mips, ppc, sparc, sparc64 */
|
|
|
|
/* Used indirectly on: arm, i386, m68k */
|
1995-03-01 02:24:35 +03:00
|
|
|
|
|
|
|
/*
|
1998-10-01 08:05:54 +04:00
|
|
|
* New type Linux mmap call.
|
|
|
|
* Only called directly on machines with >= 6 free regs.
|
1995-03-01 02:24:35 +03:00
|
|
|
*/
|
|
|
|
int
|
2003-01-18 11:02:46 +03:00
|
|
|
linux_sys_mmap(l, v, retval)
|
|
|
|
struct lwp *l;
|
1995-09-20 02:37:27 +04:00
|
|
|
void *v;
|
1995-03-01 02:24:35 +03:00
|
|
|
register_t *retval;
|
|
|
|
{
|
1995-10-07 09:25:19 +03:00
|
|
|
struct linux_sys_mmap_args /* {
|
1998-10-01 08:05:54 +04:00
|
|
|
syscallarg(unsigned long) addr;
|
|
|
|
syscallarg(size_t) len;
|
|
|
|
syscallarg(int) prot;
|
|
|
|
syscallarg(int) flags;
|
|
|
|
syscallarg(int) fd;
|
2001-09-08 11:09:43 +04:00
|
|
|
syscallarg(linux_off_t) offset;
|
1995-09-20 02:37:27 +04:00
|
|
|
} */ *uap = v;
|
2003-06-24 01:25:56 +04:00
|
|
|
|
2002-12-16 22:37:03 +03:00
|
|
|
if (SCARG(uap, offset) & PAGE_MASK)
|
|
|
|
return EINVAL;
|
|
|
|
|
2004-08-29 18:08:06 +04:00
|
|
|
return linux_mmap(l, uap, retval, SCARG(uap, offset));
|
2003-06-24 01:25:56 +04:00
|
|
|
}
|
|
|
|
|
|
|
|
/*
|
|
|
|
* Guts of most architectures' mmap64() implementations. This shares
|
|
|
|
* its list of arguments with linux_sys_mmap().
|
|
|
|
*
|
|
|
|
* The difference in linux_sys_mmap2() is that "offset" is actually
|
|
|
|
* (offset / pagesize), not an absolute byte count. This translation
|
|
|
|
* to pagesize offsets is done inside glibc between the mmap64() call
|
|
|
|
* point, and the actual syscall.
|
|
|
|
*/
|
|
|
|
int
|
|
|
|
linux_sys_mmap2(l, v, retval)
|
|
|
|
struct lwp *l;
|
|
|
|
void *v;
|
|
|
|
register_t *retval;
|
|
|
|
{
|
|
|
|
struct linux_sys_mmap2_args /* {
|
|
|
|
syscallarg(unsigned long) addr;
|
|
|
|
syscallarg(size_t) len;
|
|
|
|
syscallarg(int) prot;
|
|
|
|
syscallarg(int) flags;
|
|
|
|
syscallarg(int) fd;
|
|
|
|
syscallarg(linux_off_t) offset;
|
|
|
|
} */ *uap = v;
|
2004-08-29 18:08:06 +04:00
|
|
|
|
|
|
|
return linux_mmap(l, uap, retval,
|
|
|
|
((off_t)SCARG(uap, offset)) << PAGE_SHIFT);
|
|
|
|
}
|
|
|
|
|
|
|
|
/*
|
|
|
|
* Massage arguments and call system mmap(2).
|
|
|
|
*/
|
|
|
|
static int
|
|
|
|
linux_mmap(l, uap, retval, offset)
|
|
|
|
struct lwp *l;
|
|
|
|
struct linux_sys_mmap_args *uap;
|
|
|
|
register_t *retval;
|
|
|
|
off_t offset;
|
|
|
|
{
|
2003-06-24 01:25:56 +04:00
|
|
|
struct sys_mmap_args cma;
|
2004-08-29 18:08:06 +04:00
|
|
|
int error;
|
|
|
|
size_t mmoff=0;
|
|
|
|
|
|
|
|
if (SCARG(uap, flags) & LINUX_MAP_GROWSDOWN) {
|
|
|
|
/*
|
|
|
|
* Request for stack-like memory segment. On linux, this
|
|
|
|
* works by mmap()ping (small) segment, which is automatically
|
|
|
|
* extended when page fault happens below the currently
|
|
|
|
* allocated area. We emulate this by allocating (typically
|
|
|
|
* bigger) segment sized at current stack size limit, and
|
|
|
|
* offsetting the requested and returned address accordingly.
|
|
|
|
* Since physical pages are only allocated on-demand, this
|
|
|
|
* is effectively identical.
|
|
|
|
*/
|
|
|
|
rlim_t ssl = l->l_proc->p_rlimit[RLIMIT_STACK].rlim_cur;
|
|
|
|
|
|
|
|
if (SCARG(uap, len) < ssl) {
|
|
|
|
/* Compute the address offset */
|
|
|
|
mmoff = round_page(ssl) - SCARG(uap, len);
|
|
|
|
|
|
|
|
if (SCARG(uap, addr))
|
|
|
|
SCARG(uap, addr) -= mmoff;
|
|
|
|
|
|
|
|
SCARG(uap, len) = (size_t) ssl;
|
|
|
|
}
|
|
|
|
}
|
2003-06-24 01:25:56 +04:00
|
|
|
|
|
|
|
linux_to_bsd_mmap_args(&cma, uap);
|
2004-08-29 18:08:06 +04:00
|
|
|
SCARG(&cma, pos) = offset;
|
|
|
|
|
|
|
|
error = sys_mmap(l, &cma, retval);
|
|
|
|
if (error)
|
|
|
|
return (error);
|
|
|
|
|
|
|
|
/* Shift the returned address for stack-like segment if necessary */
|
|
|
|
if (SCARG(uap, flags) & LINUX_MAP_GROWSDOWN && mmoff)
|
|
|
|
retval[0] += mmoff;
|
2003-06-24 01:25:56 +04:00
|
|
|
|
2004-08-29 18:08:06 +04:00
|
|
|
return (0);
|
2003-06-24 01:25:56 +04:00
|
|
|
}
|
|
|
|
|
|
|
|
static void
|
|
|
|
linux_to_bsd_mmap_args(cma, uap)
|
|
|
|
struct sys_mmap_args *cma;
|
|
|
|
const struct linux_sys_mmap_args *uap;
|
|
|
|
{
|
2003-06-24 01:32:33 +04:00
|
|
|
int flags = MAP_TRYFIXED, fl = SCARG(uap, flags);
|
2005-02-27 01:58:54 +03:00
|
|
|
|
2002-03-22 18:21:28 +03:00
|
|
|
flags |= cvtto_bsd_mask(fl, LINUX_MAP_SHARED, MAP_SHARED);
|
|
|
|
flags |= cvtto_bsd_mask(fl, LINUX_MAP_PRIVATE, MAP_PRIVATE);
|
|
|
|
flags |= cvtto_bsd_mask(fl, LINUX_MAP_FIXED, MAP_FIXED);
|
|
|
|
flags |= cvtto_bsd_mask(fl, LINUX_MAP_ANON, MAP_ANON);
|
1998-10-01 08:05:54 +04:00
|
|
|
/* XXX XAX ERH: Any other flags here? There are more defined... */
|
|
|
|
|
2003-06-24 01:25:56 +04:00
|
|
|
SCARG(cma, addr) = (void *)SCARG(uap, addr);
|
|
|
|
SCARG(cma, len) = SCARG(uap, len);
|
|
|
|
SCARG(cma, prot) = SCARG(uap, prot);
|
|
|
|
if (SCARG(cma, prot) & VM_PROT_WRITE) /* XXX */
|
|
|
|
SCARG(cma, prot) |= VM_PROT_READ;
|
|
|
|
SCARG(cma, flags) = flags;
|
|
|
|
SCARG(cma, fd) = flags & MAP_ANON ? -1 : SCARG(uap, fd);
|
|
|
|
SCARG(cma, pad) = 0;
|
2002-02-15 19:47:58 +03:00
|
|
|
}
|
|
|
|
|
2006-01-21 16:34:15 +03:00
|
|
|
#define LINUX_MREMAP_MAYMOVE 1
|
|
|
|
#define LINUX_MREMAP_FIXED 2
|
|
|
|
|
1997-10-10 10:25:34 +04:00
|
|
|
int
|
2003-01-18 11:02:46 +03:00
|
|
|
linux_sys_mremap(l, v, retval)
|
|
|
|
struct lwp *l;
|
1997-10-10 10:25:34 +04:00
|
|
|
void *v;
|
|
|
|
register_t *retval;
|
|
|
|
{
|
|
|
|
struct linux_sys_mremap_args /* {
|
|
|
|
syscallarg(void *) old_address;
|
|
|
|
syscallarg(size_t) old_size;
|
|
|
|
syscallarg(size_t) new_size;
|
|
|
|
syscallarg(u_long) flags;
|
|
|
|
} */ *uap = v;
|
1998-07-03 03:26:58 +04:00
|
|
|
|
2006-01-21 16:34:15 +03:00
|
|
|
struct proc *p;
|
|
|
|
struct vm_map *map;
|
|
|
|
vaddr_t oldva;
|
|
|
|
vaddr_t newva;
|
|
|
|
size_t oldsize;
|
|
|
|
size_t newsize;
|
|
|
|
int flags;
|
|
|
|
int uvmflags;
|
|
|
|
int error;
|
1997-10-10 10:25:34 +04:00
|
|
|
|
2006-01-21 16:34:15 +03:00
|
|
|
flags = SCARG(uap, flags);
|
|
|
|
oldva = (vaddr_t)SCARG(uap, old_address);
|
|
|
|
oldsize = round_page(SCARG(uap, old_size));
|
|
|
|
newsize = round_page(SCARG(uap, new_size));
|
2006-01-31 17:02:55 +03:00
|
|
|
if ((flags & ~(LINUX_MREMAP_FIXED|LINUX_MREMAP_MAYMOVE)) != 0) {
|
|
|
|
error = EINVAL;
|
|
|
|
goto done;
|
|
|
|
}
|
2006-01-21 16:34:15 +03:00
|
|
|
if ((flags & LINUX_MREMAP_FIXED) != 0) {
|
2006-01-31 17:02:55 +03:00
|
|
|
if ((flags & LINUX_MREMAP_MAYMOVE) == 0) {
|
|
|
|
error = EINVAL;
|
|
|
|
goto done;
|
|
|
|
}
|
2006-01-21 16:34:15 +03:00
|
|
|
#if 0 /* notyet */
|
|
|
|
newva = SCARG(uap, new_address);
|
|
|
|
uvmflags = UVM_MREMAP_FIXED;
|
|
|
|
#else /* notyet */
|
|
|
|
error = EOPNOTSUPP;
|
|
|
|
goto done;
|
|
|
|
#endif /* notyet */
|
|
|
|
} else if ((flags & LINUX_MREMAP_MAYMOVE) != 0) {
|
|
|
|
uvmflags = 0;
|
|
|
|
} else {
|
|
|
|
newva = oldva;
|
|
|
|
uvmflags = UVM_MREMAP_FIXED;
|
1998-07-03 03:26:58 +04:00
|
|
|
}
|
2006-01-21 16:34:15 +03:00
|
|
|
p = l->l_proc;
|
|
|
|
map = &p->p_vmspace->vm_map;
|
|
|
|
error = uvm_mremap(map, oldva, oldsize, map, &newva, newsize, p,
|
|
|
|
uvmflags);
|
|
|
|
|
|
|
|
done:
|
|
|
|
*retval = (error != 0) ? 0 : (register_t)newva;
|
|
|
|
return error;
|
1997-10-10 10:25:34 +04:00
|
|
|
}
|
|
|
|
|
1995-12-18 17:35:08 +03:00
|
|
|
int
|
2003-01-18 11:02:46 +03:00
|
|
|
linux_sys_msync(l, v, retval)
|
|
|
|
struct lwp *l;
|
1995-12-18 17:35:08 +03:00
|
|
|
void *v;
|
|
|
|
register_t *retval;
|
|
|
|
{
|
|
|
|
struct linux_sys_msync_args /* {
|
2007-03-04 08:59:00 +03:00
|
|
|
syscallarg(void *) addr;
|
1995-12-18 17:35:08 +03:00
|
|
|
syscallarg(int) len;
|
|
|
|
syscallarg(int) fl;
|
|
|
|
} */ *uap = v;
|
|
|
|
|
1997-10-21 04:57:38 +04:00
|
|
|
struct sys___msync13_args bma;
|
1995-12-18 17:35:08 +03:00
|
|
|
|
|
|
|
/* flags are ignored */
|
|
|
|
SCARG(&bma, addr) = SCARG(uap, addr);
|
|
|
|
SCARG(&bma, len) = SCARG(uap, len);
|
1997-10-21 04:57:38 +04:00
|
|
|
SCARG(&bma, flags) = SCARG(uap, fl);
|
1995-12-18 17:35:08 +03:00
|
|
|
|
2003-01-18 11:02:46 +03:00
|
|
|
return sys___msync13(l, &bma, retval);
|
1995-12-18 17:35:08 +03:00
|
|
|
}
|
|
|
|
|
2002-03-22 18:21:28 +03:00
|
|
|
int
|
2006-11-16 04:32:37 +03:00
|
|
|
linux_sys_mprotect(struct lwp *l, void *v, register_t *retval)
|
2002-03-22 18:21:28 +03:00
|
|
|
{
|
|
|
|
struct linux_sys_mprotect_args /* {
|
|
|
|
syscallarg(const void *) start;
|
|
|
|
syscallarg(unsigned long) len;
|
|
|
|
syscallarg(int) prot;
|
|
|
|
} */ *uap = v;
|
|
|
|
struct vm_map_entry *entry;
|
2005-10-30 19:25:50 +03:00
|
|
|
struct vm_map *map;
|
|
|
|
struct proc *p;
|
|
|
|
vaddr_t end, start, len, stacklim;
|
|
|
|
int prot, grows;
|
2002-03-22 18:21:28 +03:00
|
|
|
|
2005-10-30 19:25:50 +03:00
|
|
|
start = (vaddr_t)SCARG(uap, start);
|
2002-03-22 18:21:28 +03:00
|
|
|
len = round_page(SCARG(uap, len));
|
2005-10-30 19:25:50 +03:00
|
|
|
prot = SCARG(uap, prot);
|
|
|
|
grows = prot & (LINUX_PROT_GROWSDOWN | LINUX_PROT_GROWSUP);
|
|
|
|
prot &= ~grows;
|
2002-03-22 18:21:28 +03:00
|
|
|
end = start + len;
|
|
|
|
|
2005-10-30 19:25:50 +03:00
|
|
|
if (start & PAGE_MASK)
|
|
|
|
return EINVAL;
|
2002-03-22 18:21:28 +03:00
|
|
|
if (end < start)
|
|
|
|
return EINVAL;
|
2005-10-30 19:25:50 +03:00
|
|
|
if (end == start)
|
2002-03-22 18:21:28 +03:00
|
|
|
return 0;
|
|
|
|
|
2005-10-30 19:25:50 +03:00
|
|
|
if (prot & ~(PROT_READ | PROT_WRITE | PROT_EXEC))
|
|
|
|
return EINVAL;
|
|
|
|
if (grows == (LINUX_PROT_GROWSDOWN | LINUX_PROT_GROWSUP))
|
2002-03-22 18:21:28 +03:00
|
|
|
return EINVAL;
|
|
|
|
|
2005-10-30 19:25:50 +03:00
|
|
|
p = l->l_proc;
|
|
|
|
map = &p->p_vmspace->vm_map;
|
2002-03-22 18:21:28 +03:00
|
|
|
vm_map_lock(map);
|
2006-02-09 22:18:56 +03:00
|
|
|
# ifdef notdef
|
2002-03-22 18:21:28 +03:00
|
|
|
VM_MAP_RANGE_CHECK(map, start, end);
|
2006-02-09 22:18:56 +03:00
|
|
|
# endif
|
2002-03-22 18:21:28 +03:00
|
|
|
if (!uvm_map_lookup_entry(map, start, &entry) || entry->start > start) {
|
|
|
|
vm_map_unlock(map);
|
2004-08-02 02:44:10 +04:00
|
|
|
return ENOMEM;
|
2002-03-22 18:21:28 +03:00
|
|
|
}
|
2005-10-30 19:25:50 +03:00
|
|
|
|
|
|
|
/*
|
|
|
|
* Approximate the behaviour of PROT_GROWS{DOWN,UP}.
|
|
|
|
*/
|
|
|
|
|
|
|
|
stacklim = (vaddr_t)p->p_limit->pl_rlimit[RLIMIT_STACK].rlim_cur;
|
|
|
|
if (grows & LINUX_PROT_GROWSDOWN) {
|
|
|
|
if (USRSTACK - stacklim <= start && start < USRSTACK) {
|
|
|
|
start = USRSTACK - stacklim;
|
|
|
|
} else {
|
|
|
|
start = entry->start;
|
|
|
|
}
|
|
|
|
} else if (grows & LINUX_PROT_GROWSUP) {
|
|
|
|
if (USRSTACK <= end && end < USRSTACK + stacklim) {
|
|
|
|
end = USRSTACK + stacklim;
|
|
|
|
} else {
|
|
|
|
end = entry->end;
|
|
|
|
}
|
|
|
|
}
|
2002-03-22 18:21:28 +03:00
|
|
|
vm_map_unlock(map);
|
|
|
|
return uvm_map_protect(map, start, end, prot, FALSE);
|
|
|
|
}
|
|
|
|
|
1995-03-01 02:24:35 +03:00
|
|
|
/*
|
|
|
|
* This code is partly stolen from src/lib/libc/compat-43/times.c
|
|
|
|
*/
|
|
|
|
|
2002-11-13 18:20:04 +03:00
|
|
|
#define CONVTCK(r) (r.tv_sec * hz + r.tv_usec / (1000000 / hz))
|
1995-03-01 02:24:35 +03:00
|
|
|
|
|
|
|
int
|
2003-01-18 11:02:46 +03:00
|
|
|
linux_sys_times(l, v, retval)
|
|
|
|
struct lwp *l;
|
1995-09-20 02:37:27 +04:00
|
|
|
void *v;
|
1995-03-01 02:24:35 +03:00
|
|
|
register_t *retval;
|
|
|
|
{
|
1995-10-07 09:25:19 +03:00
|
|
|
struct linux_sys_times_args /* {
|
1995-09-20 02:37:27 +04:00
|
|
|
syscallarg(struct times *) tms;
|
|
|
|
} */ *uap = v;
|
2003-01-18 11:02:46 +03:00
|
|
|
struct proc *p = l->l_proc;
|
1995-03-01 02:24:35 +03:00
|
|
|
struct timeval t;
|
2006-06-08 02:33:33 +04:00
|
|
|
int error;
|
1995-03-01 02:24:35 +03:00
|
|
|
|
2002-11-13 11:27:10 +03:00
|
|
|
if (SCARG(uap, tms)) {
|
|
|
|
struct linux_tms ltms;
|
|
|
|
struct rusage ru;
|
1995-03-01 02:24:35 +03:00
|
|
|
|
2007-02-10 00:55:00 +03:00
|
|
|
mutex_enter(&p->p_smutex);
|
|
|
|
calcru(p, &ru.ru_utime, &ru.ru_stime, NULL, NULL);
|
2002-11-13 11:27:10 +03:00
|
|
|
ltms.ltms_utime = CONVTCK(ru.ru_utime);
|
|
|
|
ltms.ltms_stime = CONVTCK(ru.ru_stime);
|
|
|
|
ltms.ltms_cutime = CONVTCK(p->p_stats->p_cru.ru_utime);
|
|
|
|
ltms.ltms_cstime = CONVTCK(p->p_stats->p_cru.ru_stime);
|
2007-02-10 00:55:00 +03:00
|
|
|
mutex_exit(&p->p_smutex);
|
2002-11-13 11:27:10 +03:00
|
|
|
|
|
|
|
if ((error = copyout(<ms, SCARG(uap, tms), sizeof ltms)))
|
|
|
|
return error;
|
|
|
|
}
|
1995-03-01 02:24:35 +03:00
|
|
|
|
2006-06-08 02:33:33 +04:00
|
|
|
getmicrouptime(&t);
|
1995-03-01 02:24:35 +03:00
|
|
|
|
|
|
|
retval[0] = ((linux_clock_t)(CONVTCK(t)));
|
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
|
2002-11-13 18:20:04 +03:00
|
|
|
#undef CONVTCK
|
|
|
|
|
1995-03-01 02:24:35 +03:00
|
|
|
/*
|
|
|
|
* Linux 'readdir' call. This code is mostly taken from the
|
|
|
|
* SunOS getdents call (see compat/sunos/sunos_misc.c), though
|
|
|
|
* an attempt has been made to keep it a little cleaner (failing
|
|
|
|
* miserably, because of the cruft needed if count 1 is passed).
|
|
|
|
*
|
1995-08-24 00:17:28 +04:00
|
|
|
* The d_off field should contain the offset of the next valid entry,
|
|
|
|
* but in Linux it has the offset of the entry itself. We emulate
|
|
|
|
* that bug here.
|
|
|
|
*
|
1995-03-01 02:24:35 +03:00
|
|
|
* Read in BSD-style entries, convert them, and copy them out.
|
|
|
|
*
|
|
|
|
* Note that this doesn't handle union-mounted filesystems.
|
|
|
|
*/
|
|
|
|
int
|
2003-01-18 11:02:46 +03:00
|
|
|
linux_sys_getdents(l, v, retval)
|
|
|
|
struct lwp *l;
|
1995-09-20 02:37:27 +04:00
|
|
|
void *v;
|
|
|
|
register_t *retval;
|
|
|
|
{
|
1998-10-01 08:05:54 +04:00
|
|
|
struct linux_sys_getdents_args /* {
|
1995-03-01 02:24:35 +03:00
|
|
|
syscallarg(int) fd;
|
1998-10-01 08:05:54 +04:00
|
|
|
syscallarg(struct linux_dirent *) dent;
|
1995-03-01 02:24:35 +03:00
|
|
|
syscallarg(unsigned int) count;
|
1995-09-20 02:37:27 +04:00
|
|
|
} */ *uap = v;
|
2000-03-30 15:24:16 +04:00
|
|
|
struct dirent *bdp;
|
1995-03-01 02:24:35 +03:00
|
|
|
struct vnode *vp;
|
2007-03-04 08:59:00 +03:00
|
|
|
char *inp, *tbuf; /* BSD-format */
|
1996-04-05 03:56:01 +04:00
|
|
|
int len, reclen; /* BSD-format */
|
2007-03-04 08:59:00 +03:00
|
|
|
char *outp; /* Linux-format */
|
1996-04-05 03:56:01 +04:00
|
|
|
int resid, linux_reclen = 0; /* Linux-format */
|
1995-03-01 02:24:35 +03:00
|
|
|
struct file *fp;
|
|
|
|
struct uio auio;
|
|
|
|
struct iovec aiov;
|
|
|
|
struct linux_dirent idb;
|
|
|
|
off_t off; /* true file offset */
|
1995-08-24 00:17:28 +04:00
|
|
|
int buflen, error, eofflag, nbytes, oldcall;
|
1995-03-01 02:24:35 +03:00
|
|
|
struct vattr va;
|
1998-03-03 16:44:48 +03:00
|
|
|
off_t *cookiebuf = NULL, *cookie;
|
1995-10-09 14:23:57 +03:00
|
|
|
int ncookies;
|
1995-03-01 02:24:35 +03:00
|
|
|
|
1999-05-06 00:01:01 +04:00
|
|
|
/* getvnode() will use the descriptor for us */
|
2006-07-24 02:06:03 +04:00
|
|
|
if ((error = getvnode(l->l_proc->p_fd, SCARG(uap, fd), &fp)) != 0)
|
1995-03-01 02:24:35 +03:00
|
|
|
return (error);
|
|
|
|
|
1999-05-06 00:01:01 +04:00
|
|
|
if ((fp->f_flag & FREAD) == 0) {
|
|
|
|
error = EBADF;
|
|
|
|
goto out1;
|
|
|
|
}
|
1995-03-01 02:24:35 +03:00
|
|
|
|
1995-06-11 02:19:06 +04:00
|
|
|
vp = (struct vnode *)fp->f_data;
|
1999-05-06 00:01:01 +04:00
|
|
|
if (vp->v_type != VDIR) {
|
|
|
|
error = EINVAL;
|
|
|
|
goto out1;
|
|
|
|
}
|
1995-03-01 02:24:35 +03:00
|
|
|
|
2006-07-24 02:06:03 +04:00
|
|
|
if ((error = VOP_GETATTR(vp, &va, l->l_cred, l)))
|
1999-05-06 00:01:01 +04:00
|
|
|
goto out1;
|
1995-03-01 02:24:35 +03:00
|
|
|
|
|
|
|
nbytes = SCARG(uap, count);
|
1995-08-24 00:17:28 +04:00
|
|
|
if (nbytes == 1) { /* emulating old, broken behaviour */
|
2002-04-10 22:19:34 +04:00
|
|
|
nbytes = sizeof (idb);
|
1995-06-11 02:19:06 +04:00
|
|
|
buflen = max(va.va_blocksize, nbytes);
|
1995-08-24 00:17:28 +04:00
|
|
|
oldcall = 1;
|
1995-06-11 02:19:06 +04:00
|
|
|
} else {
|
|
|
|
buflen = min(MAXBSIZE, nbytes);
|
1997-10-10 05:42:21 +04:00
|
|
|
if (buflen < va.va_blocksize)
|
|
|
|
buflen = va.va_blocksize;
|
1995-08-24 00:17:28 +04:00
|
|
|
oldcall = 0;
|
1995-06-11 02:19:06 +04:00
|
|
|
}
|
2005-05-30 02:08:16 +04:00
|
|
|
tbuf = malloc(buflen, M_TEMP, M_WAITOK);
|
1997-10-10 05:42:21 +04:00
|
|
|
|
1998-03-01 05:20:01 +03:00
|
|
|
vn_lock(vp, LK_EXCLUSIVE | LK_RETRY);
|
1995-03-01 02:24:35 +03:00
|
|
|
off = fp->f_offset;
|
|
|
|
again:
|
2005-05-30 02:08:16 +04:00
|
|
|
aiov.iov_base = tbuf;
|
1995-03-01 02:24:35 +03:00
|
|
|
aiov.iov_len = buflen;
|
|
|
|
auio.uio_iov = &aiov;
|
|
|
|
auio.uio_iovcnt = 1;
|
|
|
|
auio.uio_rw = UIO_READ;
|
|
|
|
auio.uio_resid = buflen;
|
|
|
|
auio.uio_offset = off;
|
2006-03-01 15:38:10 +03:00
|
|
|
UIO_SETUP_SYSSPACE(&auio);
|
1995-03-01 02:24:35 +03:00
|
|
|
/*
|
|
|
|
* First we read into the malloc'ed buffer, then
|
|
|
|
* we massage it into user space, one record at a time.
|
|
|
|
*/
|
1998-03-01 05:20:01 +03:00
|
|
|
error = VOP_READDIR(vp, &auio, fp->f_cred, &eofflag, &cookiebuf,
|
|
|
|
&ncookies);
|
1995-03-01 02:24:35 +03:00
|
|
|
if (error)
|
|
|
|
goto out;
|
|
|
|
|
2005-05-30 02:08:16 +04:00
|
|
|
inp = tbuf;
|
2007-03-04 08:59:00 +03:00
|
|
|
outp = (void *)SCARG(uap, dent);
|
1995-03-01 02:24:35 +03:00
|
|
|
resid = nbytes;
|
1997-10-11 02:16:04 +04:00
|
|
|
if ((len = buflen - auio.uio_resid) == 0)
|
1995-03-01 02:24:35 +03:00
|
|
|
goto eof;
|
|
|
|
|
1995-10-09 14:23:57 +03:00
|
|
|
for (cookie = cookiebuf; len > 0; len -= reclen) {
|
1995-06-11 02:19:06 +04:00
|
|
|
bdp = (struct dirent *)inp;
|
|
|
|
reclen = bdp->d_reclen;
|
1995-03-01 02:24:35 +03:00
|
|
|
if (reclen & 3)
|
|
|
|
panic("linux_readdir");
|
|
|
|
if (bdp->d_fileno == 0) {
|
|
|
|
inp += reclen; /* it is a hole; squish it out */
|
2005-04-19 23:00:25 +04:00
|
|
|
if (cookie)
|
|
|
|
off = *cookie++;
|
|
|
|
else
|
|
|
|
off += reclen;
|
1995-03-01 02:24:35 +03:00
|
|
|
continue;
|
|
|
|
}
|
1995-10-07 09:25:19 +03:00
|
|
|
linux_reclen = LINUX_RECLEN(&idb, bdp->d_namlen);
|
|
|
|
if (reclen > len || resid < linux_reclen) {
|
1995-03-01 02:24:35 +03:00
|
|
|
/* entry too big for buffer, so just stop */
|
|
|
|
outp++;
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
/*
|
|
|
|
* Massage in place to make a Linux-shaped dirent (otherwise
|
|
|
|
* we have to worry about touching user memory outside of
|
|
|
|
* the copyout() call).
|
|
|
|
*/
|
2002-04-10 22:19:34 +04:00
|
|
|
idb.d_ino = bdp->d_fileno;
|
1995-08-24 00:17:28 +04:00
|
|
|
/*
|
1995-10-07 09:25:19 +03:00
|
|
|
* The old readdir() call misuses the offset and reclen fields.
|
1995-08-24 00:17:28 +04:00
|
|
|
*/
|
1995-10-09 14:23:57 +03:00
|
|
|
if (oldcall) {
|
|
|
|
idb.d_off = (linux_off_t)linux_reclen;
|
|
|
|
idb.d_reclen = (u_short)bdp->d_namlen;
|
|
|
|
} else {
|
2002-05-10 18:49:38 +04:00
|
|
|
if (sizeof (idb.d_off) <= 4 && (off >> 32) != 0) {
|
1997-10-10 05:42:21 +04:00
|
|
|
compat_offseterr(vp, "linux_getdents");
|
|
|
|
error = EINVAL;
|
|
|
|
goto out;
|
|
|
|
}
|
1995-10-09 14:23:57 +03:00
|
|
|
idb.d_off = (linux_off_t)off;
|
|
|
|
idb.d_reclen = (u_short)linux_reclen;
|
|
|
|
}
|
1995-06-11 02:19:06 +04:00
|
|
|
strcpy(idb.d_name, bdp->d_name);
|
2007-03-04 08:59:00 +03:00
|
|
|
if ((error = copyout((void *)&idb, outp, linux_reclen)))
|
1995-03-01 02:24:35 +03:00
|
|
|
goto out;
|
|
|
|
/* advance past this real entry */
|
|
|
|
inp += reclen;
|
2005-04-19 23:00:25 +04:00
|
|
|
if (cookie)
|
|
|
|
off = *cookie++; /* each entry points to itself */
|
|
|
|
else
|
|
|
|
off += reclen;
|
1995-03-01 02:24:35 +03:00
|
|
|
/* advance output past Linux-shaped entry */
|
1995-10-07 09:25:19 +03:00
|
|
|
outp += linux_reclen;
|
|
|
|
resid -= linux_reclen;
|
1995-08-24 00:17:28 +04:00
|
|
|
if (oldcall)
|
1995-03-01 02:24:35 +03:00
|
|
|
break;
|
|
|
|
}
|
|
|
|
|
|
|
|
/* if we squished out the whole block, try again */
|
2007-03-04 08:59:00 +03:00
|
|
|
if (outp == (void *)SCARG(uap, dent))
|
1995-03-01 02:24:35 +03:00
|
|
|
goto again;
|
|
|
|
fp->f_offset = off; /* update the vnode offset */
|
|
|
|
|
1995-08-24 00:17:28 +04:00
|
|
|
if (oldcall)
|
1995-10-07 09:25:19 +03:00
|
|
|
nbytes = resid + linux_reclen;
|
1995-03-01 02:24:35 +03:00
|
|
|
|
2002-04-10 22:19:34 +04:00
|
|
|
eof:
|
|
|
|
*retval = nbytes - resid;
|
|
|
|
out:
|
|
|
|
VOP_UNLOCK(vp, 0);
|
|
|
|
if (cookiebuf)
|
|
|
|
free(cookiebuf, M_TEMP);
|
2005-05-30 02:08:16 +04:00
|
|
|
free(tbuf, M_TEMP);
|
2002-04-10 22:19:34 +04:00
|
|
|
out1:
|
2005-12-11 15:16:03 +03:00
|
|
|
FILE_UNUSE(fp, l);
|
1995-03-01 02:24:35 +03:00
|
|
|
return error;
|
|
|
|
}
|
|
|
|
|
1995-08-24 00:17:28 +04:00
|
|
|
/*
|
|
|
|
* Even when just using registers to pass arguments to syscalls you can
|
|
|
|
* have 5 of them on the i386. So this newer version of select() does
|
|
|
|
* this.
|
|
|
|
*/
|
|
|
|
int
|
2003-01-18 11:02:46 +03:00
|
|
|
linux_sys_select(l, v, retval)
|
|
|
|
struct lwp *l;
|
1995-09-20 02:37:27 +04:00
|
|
|
void *v;
|
|
|
|
register_t *retval;
|
|
|
|
{
|
1995-10-07 09:25:19 +03:00
|
|
|
struct linux_sys_select_args /* {
|
1995-08-24 00:17:28 +04:00
|
|
|
syscallarg(int) nfds;
|
|
|
|
syscallarg(fd_set *) readfds;
|
|
|
|
syscallarg(fd_set *) writefds;
|
|
|
|
syscallarg(fd_set *) exceptfds;
|
|
|
|
syscallarg(struct timeval *) timeout;
|
1995-09-20 02:37:27 +04:00
|
|
|
} */ *uap = v;
|
|
|
|
|
2003-01-18 11:02:46 +03:00
|
|
|
return linux_select1(l, retval, SCARG(uap, nfds), SCARG(uap, readfds),
|
1995-08-24 00:17:28 +04:00
|
|
|
SCARG(uap, writefds), SCARG(uap, exceptfds), SCARG(uap, timeout));
|
|
|
|
}
|
|
|
|
|
|
|
|
/*
|
|
|
|
* Common code for the old and new versions of select(). A couple of
|
|
|
|
* things are important:
|
|
|
|
* 1) return the amount of time left in the 'timeout' parameter
|
|
|
|
* 2) select never returns ERESTART on Linux, always return EINTR
|
|
|
|
*/
|
|
|
|
int
|
2003-01-18 11:02:46 +03:00
|
|
|
linux_select1(l, retval, nfds, readfds, writefds, exceptfds, timeout)
|
|
|
|
struct lwp *l;
|
1995-08-24 00:17:28 +04:00
|
|
|
register_t *retval;
|
|
|
|
int nfds;
|
|
|
|
fd_set *readfds, *writefds, *exceptfds;
|
|
|
|
struct timeval *timeout;
|
|
|
|
{
|
1995-10-07 09:25:19 +03:00
|
|
|
struct sys_select_args bsa;
|
2003-01-18 11:02:46 +03:00
|
|
|
struct proc *p = l->l_proc;
|
1995-08-24 00:17:28 +04:00
|
|
|
struct timeval tv0, tv1, utv, *tvp;
|
2007-03-04 08:59:00 +03:00
|
|
|
void *sg;
|
1995-08-24 00:17:28 +04:00
|
|
|
int error;
|
|
|
|
|
|
|
|
SCARG(&bsa, nd) = nfds;
|
|
|
|
SCARG(&bsa, in) = readfds;
|
|
|
|
SCARG(&bsa, ou) = writefds;
|
|
|
|
SCARG(&bsa, ex) = exceptfds;
|
|
|
|
SCARG(&bsa, tv) = timeout;
|
1995-03-01 02:24:35 +03:00
|
|
|
|
1995-06-12 01:51:38 +04:00
|
|
|
/*
|
|
|
|
* Store current time for computation of the amount of
|
|
|
|
* time left.
|
|
|
|
*/
|
1995-08-24 00:17:28 +04:00
|
|
|
if (timeout) {
|
|
|
|
if ((error = copyin(timeout, &utv, sizeof(utv))))
|
1995-08-16 08:29:49 +04:00
|
|
|
return error;
|
|
|
|
if (itimerfix(&utv)) {
|
|
|
|
/*
|
|
|
|
* The timeval was invalid. Convert it to something
|
|
|
|
* valid that will act as it does under Linux.
|
|
|
|
*/
|
2002-03-16 23:43:48 +03:00
|
|
|
sg = stackgap_init(p, 0);
|
|
|
|
tvp = stackgap_alloc(p, &sg, sizeof(utv));
|
1995-08-16 08:29:49 +04:00
|
|
|
utv.tv_sec += utv.tv_usec / 1000000;
|
|
|
|
utv.tv_usec %= 1000000;
|
|
|
|
if (utv.tv_usec < 0) {
|
|
|
|
utv.tv_sec -= 1;
|
|
|
|
utv.tv_usec += 1000000;
|
|
|
|
}
|
|
|
|
if (utv.tv_sec < 0)
|
|
|
|
timerclear(&utv);
|
|
|
|
if ((error = copyout(&utv, tvp, sizeof(utv))))
|
|
|
|
return error;
|
|
|
|
SCARG(&bsa, tv) = tvp;
|
|
|
|
}
|
1995-06-12 01:51:38 +04:00
|
|
|
microtime(&tv0);
|
1995-08-16 08:29:49 +04:00
|
|
|
}
|
1995-06-12 01:51:38 +04:00
|
|
|
|
2003-01-18 11:02:46 +03:00
|
|
|
error = sys_select(l, &bsa, retval);
|
1995-08-13 21:51:40 +04:00
|
|
|
if (error) {
|
|
|
|
/*
|
|
|
|
* See fs/select.c in the Linux kernel. Without this,
|
|
|
|
* Maelstrom doesn't work.
|
|
|
|
*/
|
|
|
|
if (error == ERESTART)
|
|
|
|
error = EINTR;
|
1995-06-12 01:51:38 +04:00
|
|
|
return error;
|
1995-08-13 21:51:40 +04:00
|
|
|
}
|
1995-06-12 01:51:38 +04:00
|
|
|
|
1995-08-24 00:17:28 +04:00
|
|
|
if (timeout) {
|
1995-08-16 08:50:17 +04:00
|
|
|
if (*retval) {
|
1995-06-12 01:51:38 +04:00
|
|
|
/*
|
1995-08-16 08:29:49 +04:00
|
|
|
* Compute how much time was left of the timeout,
|
1995-06-12 01:51:38 +04:00
|
|
|
* by subtracting the current time and the time
|
|
|
|
* before we started the call, and subtracting
|
|
|
|
* that result from the user-supplied value.
|
|
|
|
*/
|
|
|
|
microtime(&tv1);
|
|
|
|
timersub(&tv1, &tv0, &tv1);
|
|
|
|
timersub(&utv, &tv1, &utv);
|
1995-08-16 08:50:17 +04:00
|
|
|
if (utv.tv_sec < 0)
|
|
|
|
timerclear(&utv);
|
|
|
|
} else
|
|
|
|
timerclear(&utv);
|
1995-08-24 00:17:28 +04:00
|
|
|
if ((error = copyout(&utv, timeout, sizeof(utv))))
|
1995-06-12 01:51:38 +04:00
|
|
|
return error;
|
|
|
|
}
|
1995-08-16 08:29:49 +04:00
|
|
|
|
1995-06-12 01:51:38 +04:00
|
|
|
return 0;
|
1995-03-01 02:24:35 +03:00
|
|
|
}
|
|
|
|
|
|
|
|
/*
|
|
|
|
* Get the process group of a certain process. Look it up
|
|
|
|
* and return the value.
|
|
|
|
*/
|
|
|
|
int
|
2003-01-18 11:02:46 +03:00
|
|
|
linux_sys_getpgid(l, v, retval)
|
|
|
|
struct lwp *l;
|
1995-09-20 02:37:27 +04:00
|
|
|
void *v;
|
1995-03-01 02:24:35 +03:00
|
|
|
register_t *retval;
|
|
|
|
{
|
1995-10-07 09:25:19 +03:00
|
|
|
struct linux_sys_getpgid_args /* {
|
1995-09-20 02:37:27 +04:00
|
|
|
syscallarg(int) pid;
|
|
|
|
} */ *uap = v;
|
2003-01-18 11:02:46 +03:00
|
|
|
struct proc *p = l->l_proc;
|
1995-03-01 02:24:35 +03:00
|
|
|
struct proc *targp;
|
|
|
|
|
1996-04-05 03:56:01 +04:00
|
|
|
if (SCARG(uap, pid) != 0 && SCARG(uap, pid) != p->p_pid) {
|
1995-03-01 02:24:35 +03:00
|
|
|
if ((targp = pfind(SCARG(uap, pid))) == 0)
|
|
|
|
return ESRCH;
|
1996-04-05 03:56:01 +04:00
|
|
|
}
|
1995-03-01 02:24:35 +03:00
|
|
|
else
|
|
|
|
targp = p;
|
|
|
|
|
|
|
|
retval[0] = targp->p_pgid;
|
|
|
|
return 0;
|
|
|
|
}
|
1995-06-11 18:56:47 +04:00
|
|
|
|
|
|
|
/*
|
|
|
|
* Set the 'personality' (emulation mode) for the current process. Only
|
|
|
|
* accept the Linux personality here (0). This call is needed because
|
|
|
|
* the Linux ELF crt0 issues it in an ugly kludge to make sure that
|
|
|
|
* ELF binaries run in Linux mode, not SVR4 mode.
|
|
|
|
*/
|
|
|
|
int
|
2006-11-16 04:32:37 +03:00
|
|
|
linux_sys_personality(struct lwp *l, void *v, register_t *retval)
|
1995-06-11 18:56:47 +04:00
|
|
|
{
|
1995-10-07 09:25:19 +03:00
|
|
|
struct linux_sys_personality_args /* {
|
1995-09-20 02:37:27 +04:00
|
|
|
syscallarg(int) per;
|
|
|
|
} */ *uap = v;
|
|
|
|
|
1995-06-11 18:56:47 +04:00
|
|
|
if (SCARG(uap, per) != 0)
|
|
|
|
return EINVAL;
|
|
|
|
retval[0] = 0;
|
|
|
|
return 0;
|
|
|
|
}
|
2006-02-09 22:18:56 +03:00
|
|
|
#endif /* !COMPAT_LINUX32 */
|
1995-09-08 01:48:59 +04:00
|
|
|
|
2006-02-09 22:18:56 +03:00
|
|
|
#if defined(__i386__) || defined(__m68k__) || defined(COMPAT_LINUX32)
|
1995-09-08 01:48:59 +04:00
|
|
|
/*
|
|
|
|
* The calls are here because of type conversions.
|
|
|
|
*/
|
|
|
|
int
|
2003-01-18 11:02:46 +03:00
|
|
|
linux_sys_setreuid16(l, v, retval)
|
|
|
|
struct lwp *l;
|
1995-09-20 02:37:27 +04:00
|
|
|
void *v;
|
|
|
|
register_t *retval;
|
|
|
|
{
|
2000-12-18 17:40:02 +03:00
|
|
|
struct linux_sys_setreuid16_args /* {
|
1995-09-08 01:48:59 +04:00
|
|
|
syscallarg(int) ruid;
|
|
|
|
syscallarg(int) euid;
|
1995-09-20 02:37:27 +04:00
|
|
|
} */ *uap = v;
|
1996-06-23 15:13:32 +04:00
|
|
|
struct sys_setreuid_args bsa;
|
2005-02-27 01:58:54 +03:00
|
|
|
|
1995-09-08 01:48:59 +04:00
|
|
|
SCARG(&bsa, ruid) = ((linux_uid_t)SCARG(uap, ruid) == (linux_uid_t)-1) ?
|
|
|
|
(uid_t)-1 : SCARG(uap, ruid);
|
|
|
|
SCARG(&bsa, euid) = ((linux_uid_t)SCARG(uap, euid) == (linux_uid_t)-1) ?
|
|
|
|
(uid_t)-1 : SCARG(uap, euid);
|
|
|
|
|
2003-01-18 11:02:46 +03:00
|
|
|
return sys_setreuid(l, &bsa, retval);
|
1995-09-08 01:48:59 +04:00
|
|
|
}
|
|
|
|
|
|
|
|
int
|
2003-01-18 11:02:46 +03:00
|
|
|
linux_sys_setregid16(l, v, retval)
|
|
|
|
struct lwp *l;
|
1995-09-20 02:37:27 +04:00
|
|
|
void *v;
|
|
|
|
register_t *retval;
|
|
|
|
{
|
2000-12-18 17:40:02 +03:00
|
|
|
struct linux_sys_setregid16_args /* {
|
1995-09-08 01:48:59 +04:00
|
|
|
syscallarg(int) rgid;
|
|
|
|
syscallarg(int) egid;
|
1995-09-20 02:37:27 +04:00
|
|
|
} */ *uap = v;
|
1996-06-23 15:13:32 +04:00
|
|
|
struct sys_setregid_args bsa;
|
2005-02-27 01:58:54 +03:00
|
|
|
|
1995-09-08 01:48:59 +04:00
|
|
|
SCARG(&bsa, rgid) = ((linux_gid_t)SCARG(uap, rgid) == (linux_gid_t)-1) ?
|
|
|
|
(uid_t)-1 : SCARG(uap, rgid);
|
|
|
|
SCARG(&bsa, egid) = ((linux_gid_t)SCARG(uap, egid) == (linux_gid_t)-1) ?
|
|
|
|
(uid_t)-1 : SCARG(uap, egid);
|
|
|
|
|
2003-01-18 11:02:46 +03:00
|
|
|
return sys_setregid(l, &bsa, retval);
|
1995-09-08 01:48:59 +04:00
|
|
|
}
|
2000-12-28 01:01:42 +03:00
|
|
|
|
|
|
|
int
|
2003-01-18 11:02:46 +03:00
|
|
|
linux_sys_setresuid16(l, v, retval)
|
|
|
|
struct lwp *l;
|
2000-12-28 01:01:42 +03:00
|
|
|
void *v;
|
|
|
|
register_t *retval;
|
|
|
|
{
|
|
|
|
struct linux_sys_setresuid16_args /* {
|
|
|
|
syscallarg(uid_t) ruid;
|
|
|
|
syscallarg(uid_t) euid;
|
|
|
|
syscallarg(uid_t) suid;
|
|
|
|
} */ *uap = v;
|
|
|
|
struct linux_sys_setresuid16_args lsa;
|
|
|
|
|
|
|
|
SCARG(&lsa, ruid) = ((linux_uid_t)SCARG(uap, ruid) == (linux_uid_t)-1) ?
|
|
|
|
(uid_t)-1 : SCARG(uap, ruid);
|
|
|
|
SCARG(&lsa, euid) = ((linux_uid_t)SCARG(uap, euid) == (linux_uid_t)-1) ?
|
|
|
|
(uid_t)-1 : SCARG(uap, euid);
|
|
|
|
SCARG(&lsa, suid) = ((linux_uid_t)SCARG(uap, suid) == (linux_uid_t)-1) ?
|
|
|
|
(uid_t)-1 : SCARG(uap, suid);
|
|
|
|
|
2003-01-18 11:02:46 +03:00
|
|
|
return linux_sys_setresuid(l, &lsa, retval);
|
2000-12-28 01:01:42 +03:00
|
|
|
}
|
|
|
|
|
|
|
|
int
|
2003-01-18 11:02:46 +03:00
|
|
|
linux_sys_setresgid16(l, v, retval)
|
|
|
|
struct lwp *l;
|
2000-12-28 01:01:42 +03:00
|
|
|
void *v;
|
|
|
|
register_t *retval;
|
|
|
|
{
|
|
|
|
struct linux_sys_setresgid16_args /* {
|
|
|
|
syscallarg(gid_t) rgid;
|
|
|
|
syscallarg(gid_t) egid;
|
|
|
|
syscallarg(gid_t) sgid;
|
|
|
|
} */ *uap = v;
|
|
|
|
struct linux_sys_setresgid16_args lsa;
|
|
|
|
|
|
|
|
SCARG(&lsa, rgid) = ((linux_gid_t)SCARG(uap, rgid) == (linux_gid_t)-1) ?
|
|
|
|
(gid_t)-1 : SCARG(uap, rgid);
|
|
|
|
SCARG(&lsa, egid) = ((linux_gid_t)SCARG(uap, egid) == (linux_gid_t)-1) ?
|
|
|
|
(gid_t)-1 : SCARG(uap, egid);
|
|
|
|
SCARG(&lsa, sgid) = ((linux_gid_t)SCARG(uap, sgid) == (linux_gid_t)-1) ?
|
|
|
|
(gid_t)-1 : SCARG(uap, sgid);
|
|
|
|
|
2003-01-18 11:02:46 +03:00
|
|
|
return linux_sys_setresgid(l, &lsa, retval);
|
2000-12-28 01:01:42 +03:00
|
|
|
}
|
|
|
|
|
|
|
|
int
|
2003-01-18 11:02:46 +03:00
|
|
|
linux_sys_getgroups16(l, v, retval)
|
|
|
|
struct lwp *l;
|
2000-12-28 01:01:42 +03:00
|
|
|
void *v;
|
|
|
|
register_t *retval;
|
|
|
|
{
|
|
|
|
struct linux_sys_getgroups16_args /* {
|
|
|
|
syscallarg(int) gidsetsize;
|
|
|
|
syscallarg(linux_gid_t *) gidset;
|
|
|
|
} */ *uap = v;
|
2003-01-18 11:02:46 +03:00
|
|
|
struct proc *p = l->l_proc;
|
2007-03-04 08:59:00 +03:00
|
|
|
void *sg;
|
2000-12-28 01:01:42 +03:00
|
|
|
int n, error, i;
|
|
|
|
struct sys_getgroups_args bsa;
|
|
|
|
gid_t *bset, *kbset;
|
|
|
|
linux_gid_t *lset;
|
2006-07-24 02:06:03 +04:00
|
|
|
kauth_cred_t pc = l->l_cred;
|
2000-12-28 01:01:42 +03:00
|
|
|
|
|
|
|
n = SCARG(uap, gidsetsize);
|
|
|
|
if (n < 0)
|
|
|
|
return EINVAL;
|
|
|
|
error = 0;
|
|
|
|
bset = kbset = NULL;
|
|
|
|
lset = NULL;
|
|
|
|
if (n > 0) {
|
2006-05-15 01:19:33 +04:00
|
|
|
n = min(kauth_cred_ngroups(pc), n);
|
2002-03-16 23:43:48 +03:00
|
|
|
sg = stackgap_init(p, 0);
|
|
|
|
bset = stackgap_alloc(p, &sg, n * sizeof (gid_t));
|
2000-12-28 01:01:42 +03:00
|
|
|
kbset = malloc(n * sizeof (gid_t), M_TEMP, M_WAITOK);
|
|
|
|
lset = malloc(n * sizeof (linux_gid_t), M_TEMP, M_WAITOK);
|
|
|
|
if (bset == NULL || kbset == NULL || lset == NULL)
|
2006-03-17 09:01:14 +03:00
|
|
|
{
|
|
|
|
error = ENOMEM;
|
|
|
|
goto out;
|
|
|
|
}
|
2000-12-28 01:01:42 +03:00
|
|
|
SCARG(&bsa, gidsetsize) = n;
|
|
|
|
SCARG(&bsa, gidset) = bset;
|
2003-01-18 11:02:46 +03:00
|
|
|
error = sys_getgroups(l, &bsa, retval);
|
2000-12-28 01:01:42 +03:00
|
|
|
if (error != 0)
|
|
|
|
goto out;
|
|
|
|
error = copyin(bset, kbset, n * sizeof (gid_t));
|
|
|
|
if (error != 0)
|
|
|
|
goto out;
|
|
|
|
for (i = 0; i < n; i++)
|
|
|
|
lset[i] = (linux_gid_t)kbset[i];
|
|
|
|
error = copyout(lset, SCARG(uap, gidset),
|
|
|
|
n * sizeof (linux_gid_t));
|
|
|
|
} else
|
2006-05-15 01:19:33 +04:00
|
|
|
*retval = kauth_cred_ngroups(pc);
|
2000-12-28 01:01:42 +03:00
|
|
|
out:
|
|
|
|
if (kbset != NULL)
|
|
|
|
free(kbset, M_TEMP);
|
|
|
|
if (lset != NULL)
|
|
|
|
free(lset, M_TEMP);
|
|
|
|
return error;
|
|
|
|
}
|
|
|
|
|
|
|
|
int
|
2003-01-18 11:02:46 +03:00
|
|
|
linux_sys_setgroups16(l, v, retval)
|
|
|
|
struct lwp *l;
|
2000-12-28 01:01:42 +03:00
|
|
|
void *v;
|
|
|
|
register_t *retval;
|
|
|
|
{
|
|
|
|
struct linux_sys_setgroups16_args /* {
|
|
|
|
syscallarg(int) gidsetsize;
|
|
|
|
syscallarg(linux_gid_t *) gidset;
|
|
|
|
} */ *uap = v;
|
2003-01-18 11:02:46 +03:00
|
|
|
struct proc *p = l->l_proc;
|
2007-03-04 08:59:00 +03:00
|
|
|
void *sg;
|
2000-12-28 01:01:42 +03:00
|
|
|
int n;
|
|
|
|
int error, i;
|
|
|
|
struct sys_setgroups_args bsa;
|
|
|
|
gid_t *bset, *kbset;
|
|
|
|
linux_gid_t *lset;
|
|
|
|
|
|
|
|
n = SCARG(uap, gidsetsize);
|
|
|
|
if (n < 0 || n > NGROUPS)
|
|
|
|
return EINVAL;
|
2002-03-16 23:43:48 +03:00
|
|
|
sg = stackgap_init(p, 0);
|
|
|
|
bset = stackgap_alloc(p, &sg, n * sizeof (gid_t));
|
2000-12-28 01:01:42 +03:00
|
|
|
lset = malloc(n * sizeof (linux_gid_t), M_TEMP, M_WAITOK);
|
2002-04-03 14:17:01 +04:00
|
|
|
kbset = malloc(n * sizeof (gid_t), M_TEMP, M_WAITOK);
|
2006-03-17 09:01:14 +03:00
|
|
|
if (bset == NULL || kbset == NULL || lset == NULL)
|
|
|
|
{
|
|
|
|
error = ENOMEM;
|
|
|
|
goto out;
|
|
|
|
}
|
2000-12-28 01:01:42 +03:00
|
|
|
error = copyin(SCARG(uap, gidset), lset, n * sizeof (linux_gid_t));
|
|
|
|
if (error != 0)
|
|
|
|
goto out;
|
|
|
|
for (i = 0; i < n; i++)
|
|
|
|
kbset[i] = (gid_t)lset[i];
|
|
|
|
error = copyout(kbset, bset, n * sizeof (gid_t));
|
|
|
|
if (error != 0)
|
|
|
|
goto out;
|
|
|
|
SCARG(&bsa, gidsetsize) = n;
|
|
|
|
SCARG(&bsa, gidset) = bset;
|
2003-01-18 11:02:46 +03:00
|
|
|
error = sys_setgroups(l, &bsa, retval);
|
2005-02-27 01:58:54 +03:00
|
|
|
|
2000-12-28 01:01:42 +03:00
|
|
|
out:
|
|
|
|
if (lset != NULL)
|
|
|
|
free(lset, M_TEMP);
|
|
|
|
if (kbset != NULL)
|
|
|
|
free(kbset, M_TEMP);
|
|
|
|
|
|
|
|
return error;
|
|
|
|
}
|
|
|
|
|
2006-02-09 22:18:56 +03:00
|
|
|
#endif /* __i386__ || __m68k__ || COMPAT_LINUX32 */
|
1996-05-20 05:59:09 +04:00
|
|
|
|
2006-02-09 22:18:56 +03:00
|
|
|
#ifndef COMPAT_LINUX32
|
2000-02-03 13:02:59 +03:00
|
|
|
/*
|
2000-02-17 15:34:26 +03:00
|
|
|
* We have nonexistent fsuid equal to uid.
|
|
|
|
* If modification is requested, refuse.
|
2000-02-03 13:02:59 +03:00
|
|
|
*/
|
|
|
|
int
|
2003-01-18 11:02:46 +03:00
|
|
|
linux_sys_setfsuid(l, v, retval)
|
|
|
|
struct lwp *l;
|
2000-02-03 13:02:59 +03:00
|
|
|
void *v;
|
|
|
|
register_t *retval;
|
|
|
|
{
|
|
|
|
struct linux_sys_setfsuid_args /* {
|
|
|
|
syscallarg(uid_t) uid;
|
|
|
|
} */ *uap = v;
|
|
|
|
uid_t uid;
|
|
|
|
|
|
|
|
uid = SCARG(uap, uid);
|
2006-07-24 02:06:03 +04:00
|
|
|
if (kauth_cred_getuid(l->l_cred) != uid)
|
2003-01-18 11:02:46 +03:00
|
|
|
return sys_nosys(l, v, retval);
|
2000-02-03 13:02:59 +03:00
|
|
|
else
|
|
|
|
return (0);
|
|
|
|
}
|
|
|
|
|
2000-03-18 23:42:14 +03:00
|
|
|
/* XXX XXX XXX */
|
2006-02-09 22:18:56 +03:00
|
|
|
# ifndef alpha
|
2000-02-03 13:02:59 +03:00
|
|
|
int
|
2003-01-18 11:02:46 +03:00
|
|
|
linux_sys_getfsuid(l, v, retval)
|
|
|
|
struct lwp *l;
|
2000-03-18 23:42:14 +03:00
|
|
|
void *v;
|
|
|
|
register_t *retval;
|
2000-02-03 13:02:59 +03:00
|
|
|
{
|
2003-01-18 11:02:46 +03:00
|
|
|
return sys_getuid(l, v, retval);
|
2000-02-03 13:02:59 +03:00
|
|
|
}
|
2006-02-09 22:18:56 +03:00
|
|
|
# endif
|
2000-02-03 13:02:59 +03:00
|
|
|
|
1999-05-14 22:44:50 +04:00
|
|
|
int
|
2006-11-16 04:32:37 +03:00
|
|
|
linux_sys_setresuid(struct lwp *l, void *v, register_t *retval)
|
1999-05-14 22:44:50 +04:00
|
|
|
{
|
|
|
|
struct linux_sys_setresuid_args /* {
|
|
|
|
syscallarg(uid_t) ruid;
|
|
|
|
syscallarg(uid_t) euid;
|
|
|
|
syscallarg(uid_t) suid;
|
|
|
|
} */ *uap = v;
|
|
|
|
|
|
|
|
/*
|
|
|
|
* Note: These checks are a little different than the NetBSD
|
|
|
|
* setreuid(2) call performs. This precisely follows the
|
|
|
|
* behavior of the Linux kernel.
|
|
|
|
*/
|
|
|
|
|
2003-03-05 21:44:46 +03:00
|
|
|
return do_setresuid(l, SCARG(uap, ruid), SCARG(uap, euid),
|
|
|
|
SCARG(uap, suid),
|
|
|
|
ID_R_EQ_R | ID_R_EQ_E | ID_R_EQ_S |
|
|
|
|
ID_E_EQ_R | ID_E_EQ_E | ID_E_EQ_S |
|
|
|
|
ID_S_EQ_R | ID_S_EQ_E | ID_S_EQ_S );
|
1999-05-14 22:44:50 +04:00
|
|
|
}
|
|
|
|
|
|
|
|
int
|
2006-11-16 04:32:37 +03:00
|
|
|
linux_sys_getresuid(struct lwp *l, void *v, register_t *retval)
|
1999-05-14 22:44:50 +04:00
|
|
|
{
|
|
|
|
struct linux_sys_getresuid_args /* {
|
|
|
|
syscallarg(uid_t *) ruid;
|
|
|
|
syscallarg(uid_t *) euid;
|
|
|
|
syscallarg(uid_t *) suid;
|
|
|
|
} */ *uap = v;
|
2006-07-24 02:06:03 +04:00
|
|
|
kauth_cred_t pc = l->l_cred;
|
1999-05-14 22:44:50 +04:00
|
|
|
int error;
|
2006-05-15 01:19:33 +04:00
|
|
|
uid_t uid;
|
1999-05-14 22:44:50 +04:00
|
|
|
|
|
|
|
/*
|
|
|
|
* Linux copies these values out to userspace like so:
|
|
|
|
*
|
|
|
|
* 1. Copy out ruid.
|
|
|
|
* 2. If that succeeds, copy out euid.
|
|
|
|
* 3. If both of those succeed, copy out suid.
|
|
|
|
*/
|
2006-05-15 01:19:33 +04:00
|
|
|
uid = kauth_cred_getuid(pc);
|
|
|
|
if ((error = copyout(&uid, SCARG(uap, ruid), sizeof(uid_t))) != 0)
|
1999-05-14 22:44:50 +04:00
|
|
|
return (error);
|
|
|
|
|
2006-05-15 01:19:33 +04:00
|
|
|
uid = kauth_cred_geteuid(pc);
|
|
|
|
if ((error = copyout(&uid, SCARG(uap, euid), sizeof(uid_t))) != 0)
|
1999-05-14 22:44:50 +04:00
|
|
|
return (error);
|
|
|
|
|
2006-05-15 01:19:33 +04:00
|
|
|
uid = kauth_cred_getsvuid(pc);
|
|
|
|
|
|
|
|
return (copyout(&uid, SCARG(uap, suid), sizeof(uid_t)));
|
1999-05-14 22:44:50 +04:00
|
|
|
}
|
1999-12-16 18:09:49 +03:00
|
|
|
|
|
|
|
int
|
2003-01-18 11:02:46 +03:00
|
|
|
linux_sys_ptrace(l, v, retval)
|
|
|
|
struct lwp *l;
|
1999-12-16 18:09:49 +03:00
|
|
|
void *v;
|
|
|
|
register_t *retval;
|
|
|
|
{
|
2006-09-02 01:20:46 +04:00
|
|
|
#if defined(PTRACE) || defined(_LKM)
|
1999-12-16 18:09:49 +03:00
|
|
|
struct linux_sys_ptrace_args /* {
|
2001-05-20 13:29:10 +04:00
|
|
|
i386, m68k, powerpc: T=int
|
2005-05-03 20:26:27 +04:00
|
|
|
alpha, amd64: T=long
|
2000-03-18 23:42:14 +03:00
|
|
|
syscallarg(T) request;
|
|
|
|
syscallarg(T) pid;
|
|
|
|
syscallarg(T) addr;
|
|
|
|
syscallarg(T) data;
|
1999-12-16 18:09:49 +03:00
|
|
|
} */ *uap = v;
|
2000-11-01 23:56:30 +03:00
|
|
|
const int *ptr;
|
|
|
|
int request;
|
2001-05-28 01:17:16 +04:00
|
|
|
int error;
|
2006-09-02 01:20:46 +04:00
|
|
|
#ifdef _LKM
|
|
|
|
#define sys_ptrace (*sysent[SYS_ptrace].sy_call)
|
|
|
|
#endif
|
1999-12-16 18:09:49 +03:00
|
|
|
|
|
|
|
ptr = linux_ptrace_request_map;
|
|
|
|
request = SCARG(uap, request);
|
|
|
|
while (*ptr != -1)
|
|
|
|
if (*ptr++ == request) {
|
|
|
|
struct sys_ptrace_args pta;
|
|
|
|
|
|
|
|
SCARG(&pta, req) = *ptr;
|
|
|
|
SCARG(&pta, pid) = SCARG(uap, pid);
|
2007-03-04 08:59:00 +03:00
|
|
|
SCARG(&pta, addr) = (void *)SCARG(uap, addr);
|
1999-12-16 18:09:49 +03:00
|
|
|
SCARG(&pta, data) = SCARG(uap, data);
|
|
|
|
|
2000-11-01 23:56:30 +03:00
|
|
|
/*
|
|
|
|
* Linux ptrace(PTRACE_CONT, pid, 0, 0) means actually
|
2001-06-02 15:46:09 +04:00
|
|
|
* to continue where the process left off previously.
|
2007-03-04 08:59:00 +03:00
|
|
|
* The same thing is achieved by addr == (void *) 1
|
2001-06-02 15:46:09 +04:00
|
|
|
* on NetBSD, so rewrite 'addr' appropriately.
|
2000-11-01 23:56:30 +03:00
|
|
|
*/
|
|
|
|
if (request == LINUX_PTRACE_CONT && SCARG(uap, addr)==0)
|
2007-03-04 08:59:00 +03:00
|
|
|
SCARG(&pta, addr) = (void *) 1;
|
2005-02-27 01:58:54 +03:00
|
|
|
|
2003-01-18 11:02:46 +03:00
|
|
|
error = sys_ptrace(l, &pta, retval);
|
2005-02-27 01:58:54 +03:00
|
|
|
if (error)
|
2001-06-04 11:44:39 +04:00
|
|
|
return error;
|
|
|
|
switch (request) {
|
|
|
|
case LINUX_PTRACE_PEEKTEXT:
|
|
|
|
case LINUX_PTRACE_PEEKDATA:
|
2005-02-27 01:58:54 +03:00
|
|
|
error = copyout (retval,
|
2007-03-04 08:59:00 +03:00
|
|
|
(void *)SCARG(uap, data),
|
2005-05-03 20:26:27 +04:00
|
|
|
sizeof *retval);
|
2001-06-04 11:44:39 +04:00
|
|
|
*retval = SCARG(uap, data);
|
|
|
|
break;
|
2005-02-27 01:58:54 +03:00
|
|
|
default:
|
2001-06-04 11:44:39 +04:00
|
|
|
break;
|
|
|
|
}
|
2001-05-28 01:17:16 +04:00
|
|
|
return error;
|
1999-12-16 18:09:49 +03:00
|
|
|
}
|
|
|
|
else
|
|
|
|
ptr++;
|
|
|
|
|
2003-01-18 11:02:46 +03:00
|
|
|
return LINUX_SYS_PTRACE_ARCH(l, uap, retval);
|
2006-09-02 01:20:46 +04:00
|
|
|
#else
|
|
|
|
return ENOSYS;
|
|
|
|
#endif /* PTRACE || _LKM */
|
1999-12-16 18:09:49 +03:00
|
|
|
}
|
2000-03-19 01:23:13 +03:00
|
|
|
|
|
|
|
int
|
2003-01-18 11:02:46 +03:00
|
|
|
linux_sys_reboot(struct lwp *l, void *v, register_t *retval)
|
2000-03-19 01:23:13 +03:00
|
|
|
{
|
|
|
|
struct linux_sys_reboot_args /* {
|
|
|
|
syscallarg(int) magic1;
|
|
|
|
syscallarg(int) magic2;
|
|
|
|
syscallarg(int) cmd;
|
|
|
|
syscallarg(void *) arg;
|
|
|
|
} */ *uap = v;
|
|
|
|
struct sys_reboot_args /* {
|
|
|
|
syscallarg(int) opt;
|
|
|
|
syscallarg(char *) bootstr;
|
|
|
|
} */ sra;
|
|
|
|
int error;
|
|
|
|
|
2006-11-14 16:34:29 +03:00
|
|
|
if ((error = kauth_authorize_system(l->l_cred,
|
|
|
|
KAUTH_SYSTEM_REBOOT, 0, NULL, NULL, NULL)) != 0)
|
2000-03-19 01:23:13 +03:00
|
|
|
return(error);
|
|
|
|
|
|
|
|
if (SCARG(uap, magic1) != LINUX_REBOOT_MAGIC1)
|
|
|
|
return(EINVAL);
|
|
|
|
if (SCARG(uap, magic2) != LINUX_REBOOT_MAGIC2 &&
|
|
|
|
SCARG(uap, magic2) != LINUX_REBOOT_MAGIC2A &&
|
|
|
|
SCARG(uap, magic2) != LINUX_REBOOT_MAGIC2B)
|
|
|
|
return(EINVAL);
|
|
|
|
|
|
|
|
switch (SCARG(uap, cmd)) {
|
|
|
|
case LINUX_REBOOT_CMD_RESTART:
|
|
|
|
SCARG(&sra, opt) = RB_AUTOBOOT;
|
|
|
|
break;
|
|
|
|
case LINUX_REBOOT_CMD_HALT:
|
|
|
|
SCARG(&sra, opt) = RB_HALT;
|
|
|
|
break;
|
|
|
|
case LINUX_REBOOT_CMD_POWER_OFF:
|
|
|
|
SCARG(&sra, opt) = RB_HALT|RB_POWERDOWN;
|
|
|
|
break;
|
|
|
|
case LINUX_REBOOT_CMD_RESTART2:
|
|
|
|
/* Reboot with an argument. */
|
|
|
|
SCARG(&sra, opt) = RB_AUTOBOOT|RB_STRING;
|
|
|
|
SCARG(&sra, bootstr) = SCARG(uap, arg);
|
|
|
|
break;
|
|
|
|
case LINUX_REBOOT_CMD_CAD_ON:
|
|
|
|
return(EINVAL); /* We don't implement ctrl-alt-delete */
|
|
|
|
case LINUX_REBOOT_CMD_CAD_OFF:
|
|
|
|
return(0);
|
|
|
|
default:
|
|
|
|
return(EINVAL);
|
|
|
|
}
|
|
|
|
|
2003-01-18 11:02:46 +03:00
|
|
|
return(sys_reboot(l, &sra, retval));
|
2000-03-19 01:23:13 +03:00
|
|
|
}
|
2000-12-02 00:14:42 +03:00
|
|
|
|
|
|
|
/*
|
|
|
|
* Copy of compat_12_sys_swapon().
|
|
|
|
*/
|
|
|
|
int
|
2003-01-18 11:02:46 +03:00
|
|
|
linux_sys_swapon(l, v, retval)
|
|
|
|
struct lwp *l;
|
2000-12-02 00:14:42 +03:00
|
|
|
void *v;
|
|
|
|
register_t *retval;
|
|
|
|
{
|
|
|
|
struct sys_swapctl_args ua;
|
|
|
|
struct linux_sys_swapon_args /* {
|
|
|
|
syscallarg(const char *) name;
|
|
|
|
} */ *uap = v;
|
|
|
|
|
|
|
|
SCARG(&ua, cmd) = SWAP_ON;
|
2005-06-02 17:03:27 +04:00
|
|
|
SCARG(&ua, arg) = (void *)__UNCONST(SCARG(uap, name));
|
2000-12-02 00:14:42 +03:00
|
|
|
SCARG(&ua, misc) = 0; /* priority */
|
2003-01-18 11:02:46 +03:00
|
|
|
return (sys_swapctl(l, &ua, retval));
|
2000-12-02 00:14:42 +03:00
|
|
|
}
|
|
|
|
|
2000-12-02 19:43:50 +03:00
|
|
|
/*
|
|
|
|
* Stop swapping to the file or block device specified by path.
|
|
|
|
*/
|
|
|
|
int
|
2003-01-18 11:02:46 +03:00
|
|
|
linux_sys_swapoff(l, v, retval)
|
|
|
|
struct lwp *l;
|
2000-12-02 19:43:50 +03:00
|
|
|
void *v;
|
|
|
|
register_t *retval;
|
|
|
|
{
|
|
|
|
struct sys_swapctl_args ua;
|
|
|
|
struct linux_sys_swapoff_args /* {
|
|
|
|
syscallarg(const char *) path;
|
|
|
|
} */ *uap = v;
|
|
|
|
|
|
|
|
SCARG(&ua, cmd) = SWAP_OFF;
|
2005-05-30 02:08:16 +04:00
|
|
|
SCARG(&ua, arg) = __UNCONST(SCARG(uap, path)); /*XXXUNCONST*/
|
2003-01-18 11:02:46 +03:00
|
|
|
return (sys_swapctl(l, &ua, retval));
|
2000-12-02 19:43:50 +03:00
|
|
|
}
|
|
|
|
|
2000-12-02 00:14:42 +03:00
|
|
|
/*
|
|
|
|
* Copy of compat_09_sys_setdomainname()
|
|
|
|
*/
|
|
|
|
/* ARGSUSED */
|
|
|
|
int
|
2006-11-16 04:32:37 +03:00
|
|
|
linux_sys_setdomainname(struct lwp *l, void *v, register_t *retval)
|
2000-12-02 00:14:42 +03:00
|
|
|
{
|
|
|
|
struct linux_sys_setdomainname_args /* {
|
|
|
|
syscallarg(char *) domainname;
|
|
|
|
syscallarg(int) len;
|
|
|
|
} */ *uap = v;
|
Dynamic sysctl.
Gone are the old kern_sysctl(), cpu_sysctl(), hw_sysctl(),
vfs_sysctl(), etc, routines, along with sysctl_int() et al. Now all
nodes are registered with the tree, and nodes can be added (or
removed) easily, and I/O to and from the tree is handled generically.
Since the nodes are registered with the tree, the mapping from name to
number (and back again) can now be discovered, instead of having to be
hard coded. Adding new nodes to the tree is likewise much simpler --
the new infrastructure handles almost all the work for simple types,
and just about anything else can be done with a small helper function.
All existing nodes are where they were before (numerically speaking),
so all existing consumers of sysctl information should notice no
difference.
PS - I'm sorry, but there's a distinct lack of documentation at the
moment. I'm working on sysctl(3/8/9) right now, and I promise to
watch out for buses.
2003-12-04 22:38:21 +03:00
|
|
|
int name[2];
|
2000-12-02 00:14:42 +03:00
|
|
|
|
Dynamic sysctl.
Gone are the old kern_sysctl(), cpu_sysctl(), hw_sysctl(),
vfs_sysctl(), etc, routines, along with sysctl_int() et al. Now all
nodes are registered with the tree, and nodes can be added (or
removed) easily, and I/O to and from the tree is handled generically.
Since the nodes are registered with the tree, the mapping from name to
number (and back again) can now be discovered, instead of having to be
hard coded. Adding new nodes to the tree is likewise much simpler --
the new infrastructure handles almost all the work for simple types,
and just about anything else can be done with a small helper function.
All existing nodes are where they were before (numerically speaking),
so all existing consumers of sysctl information should notice no
difference.
PS - I'm sorry, but there's a distinct lack of documentation at the
moment. I'm working on sysctl(3/8/9) right now, and I promise to
watch out for buses.
2003-12-04 22:38:21 +03:00
|
|
|
name[0] = CTL_KERN;
|
|
|
|
name[1] = KERN_DOMAINNAME;
|
|
|
|
return (old_sysctl(&name[0], 2, 0, 0, SCARG(uap, domainname),
|
|
|
|
SCARG(uap, len), l));
|
2000-12-02 00:14:42 +03:00
|
|
|
}
|
2000-12-14 00:41:23 +03:00
|
|
|
|
|
|
|
/*
|
|
|
|
* sysinfo()
|
|
|
|
*/
|
|
|
|
/* ARGSUSED */
|
|
|
|
int
|
2006-11-16 04:32:37 +03:00
|
|
|
linux_sys_sysinfo(struct lwp *l, void *v, register_t *retval)
|
2000-12-14 00:41:23 +03:00
|
|
|
{
|
|
|
|
struct linux_sys_sysinfo_args /* {
|
|
|
|
syscallarg(struct linux_sysinfo *) arg;
|
|
|
|
} */ *uap = v;
|
|
|
|
struct linux_sysinfo si;
|
|
|
|
struct loadavg *la;
|
|
|
|
|
2006-06-08 02:33:33 +04:00
|
|
|
si.uptime = time_uptime;
|
2000-12-14 00:41:23 +03:00
|
|
|
la = &averunnable;
|
|
|
|
si.loads[0] = la->ldavg[0] * LINUX_SYSINFO_LOADS_SCALE / la->fscale;
|
|
|
|
si.loads[1] = la->ldavg[1] * LINUX_SYSINFO_LOADS_SCALE / la->fscale;
|
|
|
|
si.loads[2] = la->ldavg[2] * LINUX_SYSINFO_LOADS_SCALE / la->fscale;
|
2006-09-13 23:55:49 +04:00
|
|
|
si.totalram = ctob((u_long)physmem);
|
|
|
|
si.freeram = (u_long)uvmexp.free * uvmexp.pagesize;
|
2000-12-14 00:41:23 +03:00
|
|
|
si.sharedram = 0; /* XXX */
|
2006-09-13 23:55:49 +04:00
|
|
|
si.bufferram = (u_long)uvmexp.filepages * uvmexp.pagesize;
|
|
|
|
si.totalswap = (u_long)uvmexp.swpages * uvmexp.pagesize;
|
|
|
|
si.freeswap =
|
|
|
|
(u_long)(uvmexp.swpages - uvmexp.swpginuse) * uvmexp.pagesize;
|
2000-12-14 00:41:23 +03:00
|
|
|
si.procs = nprocs;
|
|
|
|
|
|
|
|
/* The following are only present in newer Linux kernels. */
|
|
|
|
si.totalbig = 0;
|
|
|
|
si.freebig = 0;
|
|
|
|
si.mem_unit = 1;
|
|
|
|
|
|
|
|
return (copyout(&si, SCARG(uap, arg), sizeof si));
|
|
|
|
}
|
2001-03-30 21:16:33 +04:00
|
|
|
|
2002-02-15 19:47:58 +03:00
|
|
|
int
|
2003-01-18 11:02:46 +03:00
|
|
|
linux_sys_getrlimit(l, v, retval)
|
|
|
|
struct lwp *l;
|
2002-02-15 19:47:58 +03:00
|
|
|
void *v;
|
|
|
|
register_t *retval;
|
|
|
|
{
|
|
|
|
struct linux_sys_getrlimit_args /* {
|
|
|
|
syscallarg(int) which;
|
2006-02-09 22:18:56 +03:00
|
|
|
# ifdef LINUX_LARGEFILE64
|
2005-11-23 19:14:57 +03:00
|
|
|
syscallarg(struct rlimit *) rlp;
|
2006-02-09 22:18:56 +03:00
|
|
|
# else
|
2002-02-15 19:47:58 +03:00
|
|
|
syscallarg(struct orlimit *) rlp;
|
2006-02-09 22:18:56 +03:00
|
|
|
# endif
|
2002-02-15 19:47:58 +03:00
|
|
|
} */ *uap = v;
|
2003-01-18 11:02:46 +03:00
|
|
|
struct proc *p = l->l_proc;
|
2007-03-04 08:59:00 +03:00
|
|
|
void *sg = stackgap_init(p, 0);
|
2002-02-15 19:47:58 +03:00
|
|
|
struct sys_getrlimit_args ap;
|
|
|
|
struct rlimit rl;
|
2006-02-09 22:18:56 +03:00
|
|
|
# ifdef LINUX_LARGEFILE64
|
2005-11-23 19:14:57 +03:00
|
|
|
struct rlimit orl;
|
2006-02-09 22:18:56 +03:00
|
|
|
# else
|
2002-02-15 19:47:58 +03:00
|
|
|
struct orlimit orl;
|
2006-02-09 22:18:56 +03:00
|
|
|
# endif
|
2002-02-15 19:47:58 +03:00
|
|
|
int error;
|
|
|
|
|
|
|
|
SCARG(&ap, which) = linux_to_bsd_limit(SCARG(uap, which));
|
|
|
|
if ((error = SCARG(&ap, which)) < 0)
|
|
|
|
return -error;
|
2002-03-16 23:43:48 +03:00
|
|
|
SCARG(&ap, rlp) = stackgap_alloc(p, &sg, sizeof rl);
|
2003-01-18 11:02:46 +03:00
|
|
|
if ((error = sys_getrlimit(l, &ap, retval)) != 0)
|
2002-02-15 19:47:58 +03:00
|
|
|
return error;
|
|
|
|
if ((error = copyin(SCARG(&ap, rlp), &rl, sizeof(rl))) != 0)
|
|
|
|
return error;
|
|
|
|
bsd_to_linux_rlimit(&orl, &rl);
|
2005-11-30 14:36:22 +03:00
|
|
|
|
2002-02-15 19:47:58 +03:00
|
|
|
return copyout(&orl, SCARG(uap, rlp), sizeof(orl));
|
|
|
|
}
|
|
|
|
|
|
|
|
int
|
2003-01-18 11:02:46 +03:00
|
|
|
linux_sys_setrlimit(l, v, retval)
|
|
|
|
struct lwp *l;
|
2002-02-15 19:47:58 +03:00
|
|
|
void *v;
|
|
|
|
register_t *retval;
|
|
|
|
{
|
|
|
|
struct linux_sys_setrlimit_args /* {
|
|
|
|
syscallarg(int) which;
|
2006-02-09 22:18:56 +03:00
|
|
|
# ifdef LINUX_LARGEFILE64
|
2005-11-23 19:14:57 +03:00
|
|
|
syscallarg(struct rlimit *) rlp;
|
2006-02-09 22:18:56 +03:00
|
|
|
# else
|
2002-02-15 19:47:58 +03:00
|
|
|
syscallarg(struct orlimit *) rlp;
|
2006-02-09 22:18:56 +03:00
|
|
|
# endif
|
2002-02-15 19:47:58 +03:00
|
|
|
} */ *uap = v;
|
2003-01-18 11:02:46 +03:00
|
|
|
struct proc *p = l->l_proc;
|
2007-03-04 08:59:00 +03:00
|
|
|
void *sg = stackgap_init(p, 0);
|
2005-05-30 02:08:16 +04:00
|
|
|
struct sys_getrlimit_args ap;
|
2002-02-15 19:47:58 +03:00
|
|
|
struct rlimit rl;
|
2006-02-09 22:18:56 +03:00
|
|
|
# ifdef LINUX_LARGEFILE64
|
2005-11-23 19:14:57 +03:00
|
|
|
struct rlimit orl;
|
2006-02-09 22:18:56 +03:00
|
|
|
# else
|
2002-02-15 19:47:58 +03:00
|
|
|
struct orlimit orl;
|
2006-02-09 22:18:56 +03:00
|
|
|
# endif
|
2002-02-15 19:47:58 +03:00
|
|
|
int error;
|
|
|
|
|
|
|
|
SCARG(&ap, which) = linux_to_bsd_limit(SCARG(uap, which));
|
2002-03-16 23:43:48 +03:00
|
|
|
SCARG(&ap, rlp) = stackgap_alloc(p, &sg, sizeof rl);
|
2002-02-15 19:47:58 +03:00
|
|
|
if ((error = SCARG(&ap, which)) < 0)
|
|
|
|
return -error;
|
|
|
|
if ((error = copyin(SCARG(uap, rlp), &orl, sizeof(orl))) != 0)
|
|
|
|
return error;
|
|
|
|
linux_to_bsd_rlimit(&rl, &orl);
|
2005-05-30 02:08:16 +04:00
|
|
|
if ((error = copyout(&rl, SCARG(&ap, rlp), sizeof(rl))) != 0)
|
2002-02-15 19:47:58 +03:00
|
|
|
return error;
|
2003-01-18 11:02:46 +03:00
|
|
|
return sys_setrlimit(l, &ap, retval);
|
2002-02-15 19:47:58 +03:00
|
|
|
}
|
|
|
|
|
2006-02-09 22:18:56 +03:00
|
|
|
# if !defined(__mips__) && !defined(__amd64__)
|
2002-02-18 02:56:35 +03:00
|
|
|
/* XXX: this doesn't look 100% common, at least mips doesn't have it */
|
2002-02-15 19:47:58 +03:00
|
|
|
int
|
2003-01-18 11:02:46 +03:00
|
|
|
linux_sys_ugetrlimit(l, v, retval)
|
|
|
|
struct lwp *l;
|
2002-02-15 19:47:58 +03:00
|
|
|
void *v;
|
|
|
|
register_t *retval;
|
|
|
|
{
|
2003-01-18 11:02:46 +03:00
|
|
|
return linux_sys_getrlimit(l, v, retval);
|
2002-02-15 19:47:58 +03:00
|
|
|
}
|
2006-02-09 22:18:56 +03:00
|
|
|
# endif
|
2002-02-15 19:47:58 +03:00
|
|
|
|
2001-03-30 21:16:33 +04:00
|
|
|
/*
|
|
|
|
* This gets called for unsupported syscalls. The difference to sys_nosys()
|
|
|
|
* is that process does not get SIGSYS, the call just returns with ENOSYS.
|
|
|
|
* This is the way Linux does it and glibc depends on this behaviour.
|
|
|
|
*/
|
|
|
|
int
|
2006-11-16 04:32:37 +03:00
|
|
|
linux_sys_nosys(struct lwp *l, void *v,
|
|
|
|
register_t *retval)
|
2001-03-30 21:16:33 +04:00
|
|
|
{
|
|
|
|
return (ENOSYS);
|
|
|
|
}
|
2006-02-09 22:18:56 +03:00
|
|
|
|
2006-06-11 01:18:11 +04:00
|
|
|
int
|
|
|
|
linux_sys_getpriority(l, v, retval)
|
|
|
|
struct lwp *l;
|
|
|
|
void *v;
|
|
|
|
register_t *retval;
|
|
|
|
{
|
|
|
|
struct linux_sys_getpriority_args /* {
|
|
|
|
syscallarg(int) which;
|
|
|
|
syscallarg(int) who;
|
|
|
|
} */ *uap = v;
|
|
|
|
struct sys_getpriority_args bsa;
|
|
|
|
int error;
|
|
|
|
|
|
|
|
SCARG(&bsa, which) = SCARG(uap, which);
|
|
|
|
SCARG(&bsa, who) = SCARG(uap, who);
|
|
|
|
|
|
|
|
if ((error = sys_getpriority(l, &bsa, retval)))
|
|
|
|
return error;
|
|
|
|
|
2006-06-13 20:54:56 +04:00
|
|
|
*retval = NZERO - *retval;
|
2006-06-11 01:18:11 +04:00
|
|
|
|
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
|
2006-02-09 22:18:56 +03:00
|
|
|
#endif /* !COMPAT_LINUX32 */
|