Home | History | Annotate | Line # | Download | only in xen
      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
     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
    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