78abeb070d3f5db349545a547ba132318c5abe04
[linux-2.6.git] / kernel / vserver / helper.c
1 /*
2  *  linux/kernel/vserver/helper.c
3  *
4  *  Virtual Context Support
5  *
6  *  Copyright (C) 2004-2007  Herbert Pƶtzl
7  *
8  *  V0.01  basic helper
9  *
10  */
11
12 #include <linux/errno.h>
13 #include <linux/kmod.h>
14 #include <linux/sched.h>
15 #include <linux/reboot.h>
16 #include <linux/vs_base.h>
17 #include <linux/vs_context.h>
18 #include <linux/vs_network.h>
19 #include <linux/vserver/signal.h>
20
21 #include <asm/uaccess.h>
22 #include <asm/unistd.h>
23
24
25 char vshelper_path[255] = "/sbin/vshelper";
26
27
28 static int do_vshelper(char *name, char *argv[], char *envp[], int sync)
29 {
30         int ret;
31
32         if ((ret = call_usermodehelper(name, argv, envp, sync))) {
33                 printk( KERN_WARNING
34                         "%s: (%s %s) returned %s with %d\n",
35                         name, argv[1], argv[2],
36                         sync?"sync":"async", ret);
37         }
38         vxdprintk(VXD_CBIT(switch, 4),
39                 "%s: (%s %s) returned %s with %d",
40                 name, argv[1], argv[2], sync?"sync":"async", ret);
41         return ret;
42 }
43
44 /*
45  *      vshelper path is set via /proc/sys
46  *      invoked by vserver sys_reboot(), with
47  *      the following arguments
48  *
49  *      argv [0] = vshelper_path;
50  *      argv [1] = action: "restart", "halt", "poweroff", ...
51  *      argv [2] = context identifier
52  *
53  *      envp [*] = type-specific parameters
54  */
55
56 long vs_reboot_helper(struct vx_info *vxi, int cmd, void __user *arg)
57 {
58         char id_buf[8], cmd_buf[16];
59         char uid_buf[16], pid_buf[16];
60         int ret;
61
62         char *argv[] = {vshelper_path, NULL, id_buf, 0};
63         char *envp[] = {"HOME=/", "TERM=linux",
64                         "PATH=/sbin:/usr/sbin:/bin:/usr/bin",
65                         uid_buf, pid_buf, cmd_buf, 0};
66
67         if (vx_info_state(vxi, VXS_HELPER))
68                 return -EAGAIN;
69         vxi->vx_state |= VXS_HELPER;
70
71         snprintf(id_buf, sizeof(id_buf)-1, "%d", vxi->vx_id);
72
73         snprintf(cmd_buf, sizeof(cmd_buf)-1, "VS_CMD=%08x", cmd);
74         snprintf(uid_buf, sizeof(uid_buf)-1, "VS_UID=%d", current->uid);
75         snprintf(pid_buf, sizeof(pid_buf)-1, "VS_PID=%d", current->pid);
76
77         switch (cmd) {
78         case LINUX_REBOOT_CMD_RESTART:
79                 argv[1] = "restart";
80                 break;
81
82         case LINUX_REBOOT_CMD_HALT:
83                 argv[1] = "halt";
84                 break;
85
86         case LINUX_REBOOT_CMD_POWER_OFF:
87                 argv[1] = "poweroff";
88                 break;
89
90         case LINUX_REBOOT_CMD_SW_SUSPEND:
91                 argv[1] = "swsusp";
92                 break;
93
94         default:
95                 vxi->vx_state &= ~VXS_HELPER;
96                 return 0;
97         }
98
99 #ifndef CONFIG_VSERVER_LEGACY
100         ret = do_vshelper(vshelper_path, argv, envp, 1);
101 #else
102         ret = do_vshelper(vshelper_path, argv, envp, 0);
103 #endif
104         vxi->vx_state &= ~VXS_HELPER;
105         __wakeup_vx_info(vxi);
106         return (ret) ? -EPERM : 0;
107 }
108
109
110 long vs_reboot(unsigned int cmd, void __user * arg)
111 {
112         struct vx_info *vxi = current->vx_info;
113         long ret = 0;
114
115         vxdprintk(VXD_CBIT(misc, 5),
116                 "vs_reboot(%p[#%d],%d)",
117                 vxi, vxi?vxi->vx_id:0, cmd);
118
119         ret = vs_reboot_helper(vxi, cmd, arg);
120         if (ret)
121                 return ret;
122
123         vxi->reboot_cmd = cmd;
124         if (vx_info_flags(vxi, VXF_REBOOT_KILL, 0)) {
125                 switch (cmd) {
126                 case LINUX_REBOOT_CMD_RESTART:
127                 case LINUX_REBOOT_CMD_HALT:
128                 case LINUX_REBOOT_CMD_POWER_OFF:
129                         vx_info_kill(vxi, 0, SIGKILL);
130                         vx_info_kill(vxi, 1, SIGKILL);
131                 default:
132                         break;
133                 }
134         }
135         return 0;
136 }
137
138
139 /*
140  *      argv [0] = vshelper_path;
141  *      argv [1] = action: "startup", "shutdown"
142  *      argv [2] = context identifier
143  *
144  *      envp [*] = type-specific parameters
145  */
146
147 long vs_state_change(struct vx_info *vxi, unsigned int cmd)
148 {
149         char id_buf[8], cmd_buf[16];
150         char *argv[] = {vshelper_path, NULL, id_buf, 0};
151         char *envp[] = {"HOME=/", "TERM=linux",
152                         "PATH=/sbin:/usr/sbin:/bin:/usr/bin", cmd_buf, 0};
153
154         if (!vx_info_flags(vxi, VXF_SC_HELPER, 0))
155                 return 0;
156
157         snprintf(id_buf, sizeof(id_buf)-1, "%d", vxi->vx_id);
158         snprintf(cmd_buf, sizeof(cmd_buf)-1, "VS_CMD=%08x", cmd);
159
160         switch (cmd) {
161         case VSC_STARTUP:
162                 argv[1] = "startup";
163                 break;
164         case VSC_SHUTDOWN:
165                 argv[1] = "shutdown";
166                 break;
167         default:
168                 return 0;
169         }
170
171         return do_vshelper(vshelper_path, argv, envp, 1);
172 }
173
174
175 /*
176  *      argv [0] = vshelper_path;
177  *      argv [1] = action: "netup", "netdown"
178  *      argv [2] = context identifier
179  *
180  *      envp [*] = type-specific parameters
181  */
182
183 long vs_net_change(struct nx_info *nxi, unsigned int cmd)
184 {
185         char id_buf[8], cmd_buf[16];
186         char *argv[] = {vshelper_path, NULL, id_buf, 0};
187         char *envp[] = {"HOME=/", "TERM=linux",
188                         "PATH=/sbin:/usr/sbin:/bin:/usr/bin", cmd_buf, 0};
189
190         if (!nx_info_flags(nxi, NXF_SC_HELPER, 0))
191                 return 0;
192
193         snprintf(id_buf, sizeof(id_buf)-1, "%d", nxi->nx_id);
194         snprintf(cmd_buf, sizeof(cmd_buf)-1, "VS_CMD=%08x", cmd);
195
196         switch (cmd) {
197         case VSC_NETUP:
198                 argv[1] = "netup";
199                 break;
200         case VSC_NETDOWN:
201                 argv[1] = "netdown";
202                 break;
203         default:
204                 return 0;
205         }
206
207         return do_vshelper(vshelper_path, argv, envp, 1);
208 }
209