*
* Virtual Server: Signal Support
*
- * Copyright (C) 2003-2004 Herbert Pötzl
+ * Copyright (C) 2003-2007 Herbert Pötzl
*
* V0.01 broken out from vcontext V0.05
+ * V0.02 changed vcmds to vxi arg
+ * V0.03 adjusted siginfo for kill
*
*/
-#include <linux/config.h>
#include <linux/sched.h>
#include <asm/errno.h>
#include <asm/uaccess.h>
-#include <linux/vinline.h>
-#include <linux/vserver/signal.h>
+#include <linux/vs_context.h>
+#include <linux/vserver/signal_cmd.h>
-int vc_ctx_kill(uint32_t id, void __user *data)
+int vx_info_kill(struct vx_info *vxi, int pid, int sig)
{
int retval, count=0;
- struct vcmd_ctx_kill_v0 vc_data;
- struct siginfo info;
struct task_struct *p;
- struct vx_info *vxi;
-
- if (!vx_check(0, VX_ADMIN))
- return -ENOSYS;
- if (copy_from_user (&vc_data, data, sizeof(vc_data)))
- return -EFAULT;
-
- info.si_signo = vc_data.sig;
- info.si_errno = 0;
- info.si_code = SI_USER;
- info.si_pid = current->pid;
- info.si_uid = current->uid;
-
- vxi = locate_vx_info(id);
- if (!vxi)
- return -ESRCH;
+ struct siginfo *sip = SEND_SIG_PRIV;
retval = -ESRCH;
+ vxdprintk(VXD_CBIT(misc, 4),
+ "vx_info_kill(%p[#%d],%d,%d)*",
+ vxi, vxi->vx_id, pid, sig);
read_lock(&tasklist_lock);
- switch (vc_data.pid) {
- case -1:
+ switch (pid) {
case 0:
+ case -1:
for_each_process(p) {
int err = 0;
- if (vx_task_xid(p) != id || p->pid <= 1 ||
- (vc_data.pid && vxi->vx_initpid == p->pid) ||
- !thread_group_leader(p))
+ if (vx_task_xid(p) != vxi->vx_id || p->pid <= 1 ||
+ (pid && vxi->vx_initpid == p->pid))
continue;
- err = send_sig_info(vc_data.sig, &info, p);
+ err = group_send_sig_info(sig, sip, p);
++count;
if (err != -EPERM)
retval = err;
}
break;
-
+
+ case 1:
+ if (vxi->vx_initpid) {
+ pid = vxi->vx_initpid;
+ /* for now, only SIGINT to private init ... */
+ if (!vx_info_flags(vxi, VXF_STATE_ADMIN, 0) &&
+ /* ... as long as there are tasks left */
+ (atomic_read(&vxi->vx_tasks) > 1))
+ sig = SIGINT;
+ }
+ /* fallthrough */
default:
- p = find_task_by_pid(vc_data.pid);
+ p = find_task_by_real_pid(pid);
if (p) {
- if (!thread_group_leader(p)) {
- struct task_struct *tg;
-
- tg = find_task_by_pid(p->tgid);
- if (tg)
- p = tg;
- }
- if ((id == -1) || (vx_task_xid(p) == id))
- retval = send_sig_info(vc_data.sig, &info, p);
+ if (vx_task_xid(p) == vxi->vx_id)
+ retval = group_send_sig_info(sig, sip, p);
}
break;
}
read_unlock(&tasklist_lock);
- put_vx_info(vxi);
+ vxdprintk(VXD_CBIT(misc, 4),
+ "vx_info_kill(%p[#%d],%d,%d,%ld) = %d",
+ vxi, vxi->vx_id, pid, sig, (long)sip, retval);
return retval;
}
+int vc_ctx_kill(struct vx_info *vxi, void __user *data)
+{
+ struct vcmd_ctx_kill_v0 vc_data;
+
+ if (copy_from_user (&vc_data, data, sizeof(vc_data)))
+ return -EFAULT;
+
+ /* special check to allow guest shutdown */
+ if (!vx_info_flags(vxi, VXF_STATE_ADMIN, 0) &&
+ /* forbid killall pid=0 when init is present */
+ (((vc_data.pid < 1) && vxi->vx_initpid) ||
+ (vc_data.pid > 1)))
+ return -EACCES;
+
+ return vx_info_kill(vxi, vc_data.pid, vc_data.sig);
+}
+
+
+static int __wait_exit(struct vx_info *vxi)
+{
+ DECLARE_WAITQUEUE(wait, current);
+ int ret = 0;
+
+ add_wait_queue(&vxi->vx_wait, &wait);
+ set_current_state(TASK_INTERRUPTIBLE);
+
+wait:
+ if (vx_info_state(vxi,
+ VXS_SHUTDOWN|VXS_HASHED|VXS_HELPER) == VXS_SHUTDOWN)
+ goto out;
+ if (signal_pending(current)) {
+ ret = -ERESTARTSYS;
+ goto out;
+ }
+ schedule();
+ goto wait;
+
+out:
+ set_current_state(TASK_RUNNING);
+ remove_wait_queue(&vxi->vx_wait, &wait);
+ return ret;
+}
+
+
+
+int vc_wait_exit(struct vx_info *vxi, void __user *data)
+{
+ struct vcmd_wait_exit_v0 vc_data;
+ int ret;
+
+ ret = __wait_exit(vxi);
+ vc_data.reboot_cmd = vxi->reboot_cmd;
+ vc_data.exit_code = vxi->exit_code;
+
+ if (copy_to_user (data, &vc_data, sizeof(vc_data)))
+ ret = -EFAULT;
+ return ret;
+}