summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authornetchild <netchild@FreeBSD.org>2006-10-28 10:59:59 +0000
committernetchild <netchild@FreeBSD.org>2006-10-28 10:59:59 +0000
commit963ac453db05c1bc7038ec526ac5fc55192d4171 (patch)
tree35564ebb9838ad07de84ad6a3cd948742bc6dc50
parentd6a1b3d7dc16f096b80af154e8f00218f56c9e1a (diff)
downloadFreeBSD-src-963ac453db05c1bc7038ec526ac5fc55192d4171.zip
FreeBSD-src-963ac453db05c1bc7038ec526ac5fc55192d4171.tar.gz
MFP4:
Implement prctl(). Submitted by: rdivacky Tested with: LTP
-rw-r--r--sys/amd64/linux32/linux32_dummy.c1
-rw-r--r--sys/amd64/linux32/syscalls.master3
-rw-r--r--sys/compat/linux/linux_emul.c24
-rw-r--r--sys/compat/linux/linux_emul.h2
-rw-r--r--sys/compat/linux/linux_misc.c51
-rw-r--r--sys/compat/linux/linux_misc.h43
-rw-r--r--sys/i386/linux/linux_dummy.c1
-rw-r--r--sys/i386/linux/syscalls.master3
8 files changed, 123 insertions, 5 deletions
diff --git a/sys/amd64/linux32/linux32_dummy.c b/sys/amd64/linux32/linux32_dummy.c
index 2d1e4f5..fc4d551 100644
--- a/sys/amd64/linux32/linux32_dummy.c
+++ b/sys/amd64/linux32/linux32_dummy.c
@@ -53,7 +53,6 @@ DUMMY(bdflush);
DUMMY(sysfs);
DUMMY(query_module);
DUMMY(nfsservctl);
-DUMMY(prctl);
DUMMY(rt_sigtimedwait);
DUMMY(rt_sigqueueinfo);
DUMMY(capget);
diff --git a/sys/amd64/linux32/syscalls.master b/sys/amd64/linux32/syscalls.master
index 6836441..10e9999 100644
--- a/sys/amd64/linux32/syscalls.master
+++ b/sys/amd64/linux32/syscalls.master
@@ -298,7 +298,8 @@
l_gid16_t egid, l_gid16_t sgid); }
171 AUE_GETRESGID STD { int linux_getresgid16(l_gid16_t *rgid, \
l_gid16_t *egid, l_gid16_t *sgid); }
-172 AUE_PRCTL STD { int linux_prctl(void); }
+172 AUE_PRCTL STD { int linux_prctl(l_int option, l_int arg2, l_int arg3, \
+ l_int arg4, l_int arg5); }
173 AUE_NULL STD { int linux_rt_sigreturn( \
struct l_ucontext *ucp); }
174 AUE_NULL STD { int linux_rt_sigaction(l_int sig, \
diff --git a/sys/compat/linux/linux_emul.c b/sys/compat/linux/linux_emul.c
index 2f92ebd..a2471ac 100644
--- a/sys/compat/linux/linux_emul.c
+++ b/sys/compat/linux/linux_emul.c
@@ -84,6 +84,7 @@ linux_proc_init(struct thread *td, pid_t child, int flags)
/* non-exec call */
em = malloc(sizeof *em, M_LINUX, M_WAITOK | M_ZERO);
em->pid = child;
+ em->pdeath_signal = 0;
if (flags & CLONE_VM) {
/* handled later in the code */
} else {
@@ -151,6 +152,7 @@ linux_proc_exit(void *arg __unused, struct proc *p)
int error;
struct thread *td = FIRST_THREAD_IN_PROC(p);
int *child_clear_tid;
+ struct proc *q, *nq;
if (__predict_true(p->p_sysent != &elf_linux_sysvec))
return;
@@ -204,6 +206,26 @@ linux_proc_exit(void *arg __unused, struct proc *p)
/* clean the stuff up */
free(em, M_LINUX);
+
+ /* this is a little weird but rewritten from exit1() */
+ sx_xlock(&proctree_lock);
+ q = LIST_FIRST(&p->p_children);
+ for (; q != NULL; q = nq) {
+ nq = LIST_NEXT(q, p_sibling);
+ if (q->p_flag & P_WEXIT)
+ continue;
+ if (__predict_false(q->p_sysent != &elf_linux_sysvec))
+ continue;
+ em = em_find(q, EMUL_UNLOCKED);
+ KASSERT(em != NULL, ("linux_reparent: emuldata not found: %i\n", q->p_pid));
+ if (em->pdeath_signal != 0) {
+ PROC_LOCK(q);
+ psignal(q, em->pdeath_signal);
+ PROC_UNLOCK(q);
+ }
+ EMUL_UNLOCK(&emul_lock);
+ }
+ sx_xunlock(&proctree_lock);
}
/*
@@ -251,7 +273,7 @@ linux_schedtail(void *arg __unused, struct proc *p)
int error = 0;
int *child_set_tid;
- if (p->p_sysent != &elf_linux_sysvec)
+ if (__predict_true(p->p_sysent != &elf_linux_sysvec))
return;
retry:
diff --git a/sys/compat/linux/linux_emul.h b/sys/compat/linux/linux_emul.h
index 0c43175..ddc3e5b 100644
--- a/sys/compat/linux/linux_emul.h
+++ b/sys/compat/linux/linux_emul.h
@@ -50,6 +50,8 @@ struct linux_emuldata {
struct linux_emuldata_shared *shared;
+ int pdeath_signal; /* parent death signal */
+
LIST_ENTRY(linux_emuldata) threads; /* list of linux threads */
};
diff --git a/sys/compat/linux/linux_misc.c b/sys/compat/linux/linux_misc.c
index fe0b803..eedc185 100644
--- a/sys/compat/linux/linux_misc.c
+++ b/sys/compat/linux/linux_misc.c
@@ -76,6 +76,7 @@ __FBSDID("$FreeBSD$");
#include <compat/linux/linux_sysproto.h>
#include <compat/linux/linux_emul.h>
+#include <compat/linux/linux_misc.h>
#ifdef COMPAT_LINUX32
#include <machine/../linux32/linux.h>
@@ -86,6 +87,7 @@ __FBSDID("$FreeBSD$");
#endif
#include <compat/linux/linux_mib.h>
+#include <compat/linux/linux_signal.h>
#include <compat/linux/linux_util.h>
#ifdef __i386__
@@ -1546,3 +1548,52 @@ linux_exit_group(struct thread *td, struct linux_exit_group_args *args)
return (0);
}
+
+int
+linux_prctl(struct thread *td, struct linux_prctl_args *args)
+{
+ int error = 0;
+ struct proc *p = td->td_proc;
+ char comm[LINUX_MAX_COMM_LEN];
+ struct linux_emuldata *em;
+
+#ifdef DEBUG
+ if (ldebug(prctl))
+ printf(ARGS(prctl, "%d, %d, %d, %d, %d"), args->option, args->arg2,
+ args->arg3, args->arg4, args->arg5);
+#endif
+
+ switch (args->option) {
+ case LINUX_PR_SET_PDEATHSIG:
+ if (!LINUX_SIG_VALID(args->arg2))
+ return (EINVAL);
+ em = em_find(p, EMUL_UNLOCKED);
+ KASSERT(em != NULL, ("prctl: emuldata not found.\n"));
+ em->pdeath_signal = args->arg2;
+ EMUL_UNLOCK(&emul_lock);
+ break;
+ case LINUX_PR_GET_PDEATHSIG:
+ em = em_find(p, EMUL_UNLOCKED);
+ KASSERT(em != NULL, ("prctl: emuldata not found.\n"));
+ error = copyout(&em->pdeath_signal, (void *)(register_t) args->arg2, sizeof(em->pdeath_signal));
+ EMUL_UNLOCK(&emul_lock);
+ break;
+ case LINUX_PR_SET_NAME:
+ comm[LINUX_MAX_COMM_LEN-1] = 0;
+ error = copyin(comm, (void *)(register_t) args->arg2, LINUX_MAX_COMM_LEN-1);
+ if (error)
+ return (error);
+ PROC_LOCK(p);
+ strcpy(p->p_comm, comm);
+ PROC_UNLOCK(p);
+ break;
+ case LINUX_PR_GET_NAME:
+ error = copyout(&p->p_comm, (void *)(register_t) args->arg2, MAXCOMLEN+1);
+ break;
+ default:
+ error = EINVAL;
+ break;
+ }
+
+ return (error);
+}
diff --git a/sys/compat/linux/linux_misc.h b/sys/compat/linux/linux_misc.h
new file mode 100644
index 0000000..c2986c3
--- /dev/null
+++ b/sys/compat/linux/linux_misc.h
@@ -0,0 +1,43 @@
+/*-
+ * Copyright (c) 2006 Roman Divacky
+ * All rights reserved.
+ *
+ * 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
+ * in this position and unchanged.
+ * 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. The name of the author may not be used to endorse or promote products
+ * derived from this software without specific prior written permission
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``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 AUTHOR 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.
+ *
+ * $FreeBSD$
+ */
+
+#ifndef _LINUX_MISC_H_
+#define _LINUX_MISC_H_
+
+/* defines for prctl */
+#define LINUX_PR_SET_PDEATHSIG 1 /* Second arg is a signal */
+#define LINUX_PR_GET_PDEATHSIG 2 /* Second arg is a ptr to return the signal */
+#define LINUX_PR_SET_NAME 15 /* Set process name */
+#define LINUX_PR_GET_NAME 16 /* Get process name */
+
+#define LINUX_MAX_COMM_LEN 16 /* max length of the proc name */
+
+#endif /* _LINUX_MISC_H_ */
+
diff --git a/sys/i386/linux/linux_dummy.c b/sys/i386/linux/linux_dummy.c
index ccc548d..5f3afc4 100644
--- a/sys/i386/linux/linux_dummy.c
+++ b/sys/i386/linux/linux_dummy.c
@@ -56,7 +56,6 @@ DUMMY(sysfs);
DUMMY(vm86);
DUMMY(query_module);
DUMMY(nfsservctl);
-DUMMY(prctl);
DUMMY(rt_sigtimedwait);
DUMMY(rt_sigqueueinfo);
DUMMY(capget);
diff --git a/sys/i386/linux/syscalls.master b/sys/i386/linux/syscalls.master
index 6b00584..24c98be 100644
--- a/sys/i386/linux/syscalls.master
+++ b/sys/i386/linux/syscalls.master
@@ -301,7 +301,8 @@
l_gid16_t egid, l_gid16_t sgid); }
171 AUE_GETRESGID STD { int linux_getresgid16(l_gid16_t *rgid, \
l_gid16_t *egid, l_gid16_t *sgid); }
-172 AUE_PRCTL STD { int linux_prctl(void); }
+172 AUE_PRCTL STD { int linux_prctl(l_int option, l_int arg2, l_int arg3, \
+ l_int arg4, l_int arg5); }
173 AUE_NULL STD { int linux_rt_sigreturn( \
struct l_ucontext *ucp); }
174 AUE_NULL STD { int linux_rt_sigaction(l_int sig, \
OpenPOWER on IntegriCloud