Merge git://git.kernel.org/pub/scm/linux/kernel/git/herbert/crypto-2.6
[pandora-kernel.git] / arch / x86 / xen / manage.c
1 /*
2  * Handle extern requests for shutdown, reboot and sysrq
3  */
4 #include <linux/kernel.h>
5 #include <linux/err.h>
6 #include <linux/reboot.h>
7 #include <linux/sysrq.h>
8
9 #include <xen/xenbus.h>
10
11 #define SHUTDOWN_INVALID  -1
12 #define SHUTDOWN_POWEROFF  0
13 #define SHUTDOWN_SUSPEND   2
14 /* Code 3 is SHUTDOWN_CRASH, which we don't use because the domain can only
15  * report a crash, not be instructed to crash!
16  * HALT is the same as POWEROFF, as far as we're concerned.  The tools use
17  * the distinction when we return the reason code to them.
18  */
19 #define SHUTDOWN_HALT      4
20
21 /* Ignore multiple shutdown requests. */
22 static int shutting_down = SHUTDOWN_INVALID;
23
24 static void shutdown_handler(struct xenbus_watch *watch,
25                              const char **vec, unsigned int len)
26 {
27         char *str;
28         struct xenbus_transaction xbt;
29         int err;
30
31         if (shutting_down != SHUTDOWN_INVALID)
32                 return;
33
34  again:
35         err = xenbus_transaction_start(&xbt);
36         if (err)
37                 return;
38
39         str = (char *)xenbus_read(xbt, "control", "shutdown", NULL);
40         /* Ignore read errors and empty reads. */
41         if (XENBUS_IS_ERR_READ(str)) {
42                 xenbus_transaction_end(xbt, 1);
43                 return;
44         }
45
46         xenbus_write(xbt, "control", "shutdown", "");
47
48         err = xenbus_transaction_end(xbt, 0);
49         if (err == -EAGAIN) {
50                 kfree(str);
51                 goto again;
52         }
53
54         if (strcmp(str, "poweroff") == 0 ||
55             strcmp(str, "halt") == 0)
56                 orderly_poweroff(false);
57         else if (strcmp(str, "reboot") == 0)
58                 ctrl_alt_del();
59         else {
60                 printk(KERN_INFO "Ignoring shutdown request: %s\n", str);
61                 shutting_down = SHUTDOWN_INVALID;
62         }
63
64         kfree(str);
65 }
66
67 static void sysrq_handler(struct xenbus_watch *watch, const char **vec,
68                           unsigned int len)
69 {
70         char sysrq_key = '\0';
71         struct xenbus_transaction xbt;
72         int err;
73
74  again:
75         err = xenbus_transaction_start(&xbt);
76         if (err)
77                 return;
78         if (!xenbus_scanf(xbt, "control", "sysrq", "%c", &sysrq_key)) {
79                 printk(KERN_ERR "Unable to read sysrq code in "
80                        "control/sysrq\n");
81                 xenbus_transaction_end(xbt, 1);
82                 return;
83         }
84
85         if (sysrq_key != '\0')
86                 xenbus_printf(xbt, "control", "sysrq", "%c", '\0');
87
88         err = xenbus_transaction_end(xbt, 0);
89         if (err == -EAGAIN)
90                 goto again;
91
92         if (sysrq_key != '\0')
93                 handle_sysrq(sysrq_key, NULL);
94 }
95
96 static struct xenbus_watch shutdown_watch = {
97         .node = "control/shutdown",
98         .callback = shutdown_handler
99 };
100
101 static struct xenbus_watch sysrq_watch = {
102         .node = "control/sysrq",
103         .callback = sysrq_handler
104 };
105
106 static int setup_shutdown_watcher(void)
107 {
108         int err;
109
110         err = register_xenbus_watch(&shutdown_watch);
111         if (err) {
112                 printk(KERN_ERR "Failed to set shutdown watcher\n");
113                 return err;
114         }
115
116         err = register_xenbus_watch(&sysrq_watch);
117         if (err) {
118                 printk(KERN_ERR "Failed to set sysrq watcher\n");
119                 return err;
120         }
121
122         return 0;
123 }
124
125 static int shutdown_event(struct notifier_block *notifier,
126                           unsigned long event,
127                           void *data)
128 {
129         setup_shutdown_watcher();
130         return NOTIFY_DONE;
131 }
132
133 static int __init setup_shutdown_event(void)
134 {
135         static struct notifier_block xenstore_notifier = {
136                 .notifier_call = shutdown_event
137         };
138         register_xenstore_notifier(&xenstore_notifier);
139
140         return 0;
141 }
142
143 subsys_initcall(setup_shutdown_event);