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