fedora core 6 1.2949 + vserver 2.2.0
[linux-2.6.git] / kernel / vserver / signal.c
1 /*
2  *  linux/kernel/vserver/signal.c
3  *
4  *  Virtual Server: Signal Support
5  *
6  *  Copyright (C) 2003-2007  Herbert Pƶtzl
7  *
8  *  V0.01  broken out from vcontext V0.05
9  *  V0.02  changed vcmds to vxi arg
10  *  V0.03  adjusted siginfo for kill
11  *
12  */
13
14 #include <linux/sched.h>
15
16 #include <asm/errno.h>
17 #include <asm/uaccess.h>
18
19 #include <linux/vs_context.h>
20 #include <linux/vserver/signal_cmd.h>
21
22
23 int vx_info_kill(struct vx_info *vxi, int pid, int sig)
24 {
25         int retval, count=0;
26         struct task_struct *p;
27         struct siginfo *sip = SEND_SIG_PRIV;
28
29         retval = -ESRCH;
30         vxdprintk(VXD_CBIT(misc, 4),
31                 "vx_info_kill(%p[#%d],%d,%d)*",
32                 vxi, vxi->vx_id, pid, sig);
33         read_lock(&tasklist_lock);
34         switch (pid) {
35         case  0:
36         case -1:
37                 for_each_process(p) {
38                         int err = 0;
39
40                         if (vx_task_xid(p) != vxi->vx_id || p->pid <= 1 ||
41                                 (pid && vxi->vx_initpid == p->pid))
42                                 continue;
43
44                         err = group_send_sig_info(sig, sip, p);
45                         ++count;
46                         if (err != -EPERM)
47                                 retval = err;
48                 }
49                 break;
50
51         case 1:
52                 if (vxi->vx_initpid) {
53                         pid = vxi->vx_initpid;
54                         /* for now, only SIGINT to private init ... */
55                         if (!vx_info_flags(vxi, VXF_STATE_ADMIN, 0) &&
56                                 /* ... as long as there are tasks left */
57                                 (atomic_read(&vxi->vx_tasks) > 1))
58                                 sig = SIGINT;
59                 }
60                 /* fallthrough */
61         default:
62                 p = find_task_by_real_pid(pid);
63                 if (p) {
64                         if (vx_task_xid(p) == vxi->vx_id)
65                                 retval = group_send_sig_info(sig, sip, p);
66                 }
67                 break;
68         }
69         read_unlock(&tasklist_lock);
70         vxdprintk(VXD_CBIT(misc, 4),
71                 "vx_info_kill(%p[#%d],%d,%d,%ld) = %d",
72                 vxi, vxi->vx_id, pid, sig, (long)sip, retval);
73         return retval;
74 }
75
76 int vc_ctx_kill(struct vx_info *vxi, void __user *data)
77 {
78         struct vcmd_ctx_kill_v0 vc_data;
79
80         if (copy_from_user (&vc_data, data, sizeof(vc_data)))
81                 return -EFAULT;
82
83         /* special check to allow guest shutdown */
84         if (!vx_info_flags(vxi, VXF_STATE_ADMIN, 0) &&
85                 /* forbid killall pid=0 when init is present */
86                 (((vc_data.pid < 1) && vxi->vx_initpid) ||
87                 (vc_data.pid > 1)))
88                 return -EACCES;
89
90         return vx_info_kill(vxi, vc_data.pid, vc_data.sig);
91 }
92
93
94 static int __wait_exit(struct vx_info *vxi)
95 {
96         DECLARE_WAITQUEUE(wait, current);
97         int ret = 0;
98
99         add_wait_queue(&vxi->vx_wait, &wait);
100         set_current_state(TASK_INTERRUPTIBLE);
101
102 wait:
103         if (vx_info_state(vxi,
104                 VXS_SHUTDOWN|VXS_HASHED|VXS_HELPER) == VXS_SHUTDOWN)
105                 goto out;
106         if (signal_pending(current)) {
107                 ret = -ERESTARTSYS;
108                 goto out;
109         }
110         schedule();
111         goto wait;
112
113 out:
114         set_current_state(TASK_RUNNING);
115         remove_wait_queue(&vxi->vx_wait, &wait);
116         return ret;
117 }
118
119
120
121 int vc_wait_exit(struct vx_info *vxi, void __user *data)
122 {
123         struct vcmd_wait_exit_v0 vc_data;
124         int ret;
125
126         ret = __wait_exit(vxi);
127         vc_data.reboot_cmd = vxi->reboot_cmd;
128         vc_data.exit_code = vxi->exit_code;
129
130         if (copy_to_user (data, &vc_data, sizeof(vc_data)))
131                 ret = -EFAULT;
132         return ret;
133 }
134