1 /* $Id: shutdown_xenbus.c,v 1.9 2020/05/13 22:13:49 jdolecek Exp $ */
2
3 /*-
4 * Copyright (c)2006 YAMAMOTO Takashi,
5 * All rights reserved.
6 *
7 * Redistribution and use in source and binary forms, with or without
8 * modification, are permitted provided that the following conditions
9 * are met:
10 * 1. Redistributions of source code must retain the above copyright
11 * notice, this list of conditions and the following disclaimer.
12 * 2. Redistributions in binary form must reproduce the above copyright
13 * notice, this list of conditions and the following disclaimer in the
14 * documentation and/or other materials provided with the distribution.
15 *
16 * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
17 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
18 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
19 * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
20 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
21 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
22 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
23 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
24 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
25 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
26 * SUCH DAMAGE.
27 */
28
29 /*
30 * Copyright (c) 2005 Manuel Bouyer.
31 *
32 * Redistribution and use in source and binary forms, with or without
33 * modification, are permitted provided that the following conditions
34 * are met:
35 * 1. Redistributions of source code must retain the above copyright
36 * notice, this list of conditions and the following disclaimer.
37 * 2. Redistributions in binary form must reproduce the above copyright
38 * notice, this list of conditions and the following disclaimer in the
39 * documentation and/or other materials provided with the distribution.
40 *
41 * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
42 * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
43 * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
44 * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
45 * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
46 * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
47 * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
48 * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
49 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
50 * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
51 *
52 */
53
54 /*
55 * watch "control/shutdown" and generate sysmon events.
56 */
57
58 #include <sys/cdefs.h>
59 __KERNEL_RCSID(0, "$NetBSD: shutdown_xenbus.c,v 1.9 2020/05/13 22:13:49 jdolecek Exp $");
60
61 #include <sys/param.h>
62
63 #include <dev/sysmon/sysmonvar.h>
64
65 #include <xen/xenbus.h>
66 #include <xen/shutdown_xenbus.h>
67
68 #define SHUTDOWN_PATH "control"
69 #define SHUTDOWN_NAME "shutdown"
70
71 static struct sysmon_pswitch xenbus_power = {
72 .smpsw_type = PSWITCH_TYPE_POWER,
73 .smpsw_name = "xenbus",
74 };
75 static struct sysmon_pswitch xenbus_reset = {
76 .smpsw_type = PSWITCH_TYPE_RESET,
77 .smpsw_name = "xenbus",
78 };
79 static struct sysmon_pswitch xenbus_sleep = {
80 .smpsw_type = PSWITCH_TYPE_SLEEP,
81 .smpsw_name = "xenbus",
82 };
83
84 static void
xenbus_shutdown_handler(struct xenbus_watch * watch,const char ** vec,unsigned int len)85 xenbus_shutdown_handler(struct xenbus_watch *watch, const char **vec,
86 unsigned int len)
87 {
88
89 struct xenbus_transaction *xbt;
90 int error;
91 char reqstr[32];
92
93 again:
94 xbt = xenbus_transaction_start();
95 if (xbt == NULL) {
96 return;
97 }
98 error = xenbus_read(xbt, SHUTDOWN_PATH, SHUTDOWN_NAME,
99 reqstr, sizeof(reqstr));
100 /* Ignore if read error or empty value */
101 if (error || reqstr[0] == '\0') {
102 if (error && error != ENOENT) {
103 printf("%s: xenbus_read %d\n", __func__, error);
104 }
105 error = xenbus_transaction_end(xbt, 1);
106 if (error != 0) {
107 printf("%s: xenbus_transaction_end 1 %d\n",
108 __func__, error);
109 }
110 return;
111 }
112
113 /* Acknowledge the command */
114 error = xenbus_write(xbt, SHUTDOWN_PATH, SHUTDOWN_NAME, "");
115 if (error) {
116 printf("%s: xenbus_rm %d\n", __func__, error);
117 }
118 error = xenbus_transaction_end(xbt, 0);
119 if (error == EAGAIN) {
120 goto again;
121 }
122 if (error != 0) {
123 printf("%s: xenbus_transaction_end 2 %d\n", __func__, error);
124 }
125 if (strcmp(reqstr, "poweroff") == 0) {
126 sysmon_pswitch_event(&xenbus_power, PSWITCH_EVENT_PRESSED);
127 } else if (strcmp(reqstr, "halt") == 0) { /* XXX eventually halt without -p */
128 sysmon_pswitch_event(&xenbus_power, PSWITCH_EVENT_PRESSED);
129 } else if (strcmp(reqstr, "reboot") == 0) {
130 sysmon_pswitch_event(&xenbus_reset, PSWITCH_EVENT_PRESSED);
131 } else if (strcmp(reqstr, "suspend") == 0) {
132 xen_suspend_allow = true;
133 sysmon_pswitch_event(&xenbus_sleep, PSWITCH_EVENT_PRESSED);
134 } else {
135 printf("ignore shutdown request: %s\n", reqstr);
136 }
137 }
138
139 static struct xenbus_watch xenbus_shutdown_watch = {
140 .node = __UNCONST(SHUTDOWN_PATH "/" SHUTDOWN_NAME), /* XXX */
141 .xbw_callback = xenbus_shutdown_handler,
142 };
143
144 void
shutdown_xenbus_setup(void)145 shutdown_xenbus_setup(void)
146 {
147 xen_suspend_allow = false;
148
149 if (sysmon_pswitch_register(&xenbus_power) != 0 ||
150 sysmon_pswitch_register(&xenbus_reset) != 0 ||
151 sysmon_pswitch_register(&xenbus_sleep) != 0) {
152 aprint_error("%s: unable to register with sysmon\n", __func__);
153 return;
154 }
155 if (register_xenbus_watch(&xenbus_shutdown_watch)) {
156 aprint_error("%s: unable to watch control/shutdown\n", __func__);
157 }
158 }
159