Logo Search packages:      
Sourcecode: linux version File versions  Download package

manage.c

/*
 * Handle extern requests for shutdown, reboot and sysrq
 */
#include <linux/kernel.h>
#include <linux/err.h>
#include <linux/reboot.h>
#include <linux/sysrq.h>

#include <xen/xenbus.h>

#define SHUTDOWN_INVALID  -1
#define SHUTDOWN_POWEROFF  0
#define SHUTDOWN_SUSPEND   2
/* Code 3 is SHUTDOWN_CRASH, which we don't use because the domain can only
 * report a crash, not be instructed to crash!
 * HALT is the same as POWEROFF, as far as we're concerned.  The tools use
 * the distinction when we return the reason code to them.
 */
#define SHUTDOWN_HALT      4

/* Ignore multiple shutdown requests. */
static int shutting_down = SHUTDOWN_INVALID;

static void shutdown_handler(struct xenbus_watch *watch,
                       const char **vec, unsigned int len)
{
      char *str;
      struct xenbus_transaction xbt;
      int err;

      if (shutting_down != SHUTDOWN_INVALID)
            return;

 again:
      err = xenbus_transaction_start(&xbt);
      if (err)
            return;

      str = (char *)xenbus_read(xbt, "control", "shutdown", NULL);
      /* Ignore read errors and empty reads. */
      if (XENBUS_IS_ERR_READ(str)) {
            xenbus_transaction_end(xbt, 1);
            return;
      }

      xenbus_write(xbt, "control", "shutdown", "");

      err = xenbus_transaction_end(xbt, 0);
      if (err == -EAGAIN) {
            kfree(str);
            goto again;
      }

      if (strcmp(str, "poweroff") == 0 ||
          strcmp(str, "halt") == 0)
            orderly_poweroff(false);
      else if (strcmp(str, "reboot") == 0)
            ctrl_alt_del();
      else {
            printk(KERN_INFO "Ignoring shutdown request: %s\n", str);
            shutting_down = SHUTDOWN_INVALID;
      }

      kfree(str);
}

static void sysrq_handler(struct xenbus_watch *watch, const char **vec,
                    unsigned int len)
{
      char sysrq_key = '\0';
      struct xenbus_transaction xbt;
      int err;

 again:
      err = xenbus_transaction_start(&xbt);
      if (err)
            return;
      if (!xenbus_scanf(xbt, "control", "sysrq", "%c", &sysrq_key)) {
            printk(KERN_ERR "Unable to read sysrq code in "
                   "control/sysrq\n");
            xenbus_transaction_end(xbt, 1);
            return;
      }

      if (sysrq_key != '\0')
            xenbus_printf(xbt, "control", "sysrq", "%c", '\0');

      err = xenbus_transaction_end(xbt, 0);
      if (err == -EAGAIN)
            goto again;

      if (sysrq_key != '\0')
            handle_sysrq(sysrq_key, NULL);
}

static struct xenbus_watch shutdown_watch = {
      .node = "control/shutdown",
      .callback = shutdown_handler
};

static struct xenbus_watch sysrq_watch = {
      .node = "control/sysrq",
      .callback = sysrq_handler
};

static int setup_shutdown_watcher(void)
{
      int err;

      err = register_xenbus_watch(&shutdown_watch);
      if (err) {
            printk(KERN_ERR "Failed to set shutdown watcher\n");
            return err;
      }

      err = register_xenbus_watch(&sysrq_watch);
      if (err) {
            printk(KERN_ERR "Failed to set sysrq watcher\n");
            return err;
      }

      return 0;
}

static int shutdown_event(struct notifier_block *notifier,
                    unsigned long event,
                    void *data)
{
      setup_shutdown_watcher();
      return NOTIFY_DONE;
}

static int __init setup_shutdown_event(void)
{
      static struct notifier_block xenstore_notifier = {
            .notifier_call = shutdown_event
      };
      register_xenstore_notifier(&xenstore_notifier);

      return 0;
}

subsys_initcall(setup_shutdown_event);

Generated by  Doxygen 1.6.0   Back to index