watchdog.c 4.2 KB
Newer Older
R
Richard W.M. Jones 已提交
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16
/*
 * Virtual hardware watchdog.
 *
 * Copyright (C) 2009 Red Hat Inc.
 *
 * This program is free software; you can redistribute it and/or
 * modify it under the terms of the GNU General Public License
 * as published by the Free Software Foundation; either version 2
 * of the License, or (at your option) any later version.
 *
 * This program is distributed in the hope that it will be useful,
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 * GNU General Public License for more details.
 *
 * You should have received a copy of the GNU General Public License
17
 * along with this program; if not, see <http://www.gnu.org/licenses/>.
R
Richard W.M. Jones 已提交
18 19 20 21 22
 *
 * By Richard W.M. Jones (rjones@redhat.com).
 */

#include "qemu-common.h"
M
Markus Armbruster 已提交
23 24
#include "qemu-option.h"
#include "qemu-config.h"
B
Blue Swirl 已提交
25
#include "qemu-queue.h"
L
Luiz Capitulino 已提交
26 27
#include "qemu-objects.h"
#include "monitor.h"
R
Richard W.M. Jones 已提交
28 29 30
#include "sysemu.h"
#include "hw/watchdog.h"

31 32 33 34 35 36 37 38 39
/* Possible values for action parameter. */
#define WDT_RESET        1	/* Hard reset. */
#define WDT_SHUTDOWN     2	/* Shutdown. */
#define WDT_POWEROFF     3	/* Quit. */
#define WDT_PAUSE        4	/* Pause. */
#define WDT_DEBUG        5	/* Prints a message and continues running. */
#define WDT_NONE         6	/* Do nothing. */

static int watchdog_action = WDT_RESET;
B
Blue Swirl 已提交
40
static QLIST_HEAD(watchdog_list, WatchdogTimerModel) watchdog_list;
R
Richard W.M. Jones 已提交
41 42 43

void watchdog_add_model(WatchdogTimerModel *model)
{
B
Blue Swirl 已提交
44
    QLIST_INSERT_HEAD(&watchdog_list, model, entry);
R
Richard W.M. Jones 已提交
45 46 47 48 49 50 51 52 53 54
}

/* Returns:
 *   0 = continue
 *   1 = exit program with error
 *   2 = exit program without error
 */
int select_watchdog(const char *p)
{
    WatchdogTimerModel *model;
M
Markus Armbruster 已提交
55
    QemuOpts *opts;
R
Richard W.M. Jones 已提交
56 57 58

    /* -watchdog ? lists available devices and exits cleanly. */
    if (strcmp(p, "?") == 0) {
B
Blue Swirl 已提交
59
        QLIST_FOREACH(model, &watchdog_list, entry) {
R
Richard W.M. Jones 已提交
60 61 62 63 64 65
            fprintf(stderr, "\t%s\t%s\n",
                     model->wdt_name, model->wdt_description);
        }
        return 2;
    }

B
Blue Swirl 已提交
66
    QLIST_FOREACH(model, &watchdog_list, entry) {
R
Richard W.M. Jones 已提交
67
        if (strcasecmp(model->wdt_name, p) == 0) {
M
Markus Armbruster 已提交
68
            /* add the device */
69
            opts = qemu_opts_create(qemu_find_opts("device"), NULL, 0);
M
Markus Armbruster 已提交
70
            qemu_opt_set(opts, "driver", p);
R
Richard W.M. Jones 已提交
71 72 73 74 75
            return 0;
        }
    }

    fprintf(stderr, "Unknown -watchdog device. Supported devices are:\n");
B
Blue Swirl 已提交
76
    QLIST_FOREACH(model, &watchdog_list, entry) {
R
Richard W.M. Jones 已提交
77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102
        fprintf(stderr, "\t%s\t%s\n",
                 model->wdt_name, model->wdt_description);
    }
    return 1;
}

int select_watchdog_action(const char *p)
{
    if (strcasecmp(p, "reset") == 0)
        watchdog_action = WDT_RESET;
    else if (strcasecmp(p, "shutdown") == 0)
        watchdog_action = WDT_SHUTDOWN;
    else if (strcasecmp(p, "poweroff") == 0)
        watchdog_action = WDT_POWEROFF;
    else if (strcasecmp(p, "pause") == 0)
        watchdog_action = WDT_PAUSE;
    else if (strcasecmp(p, "debug") == 0)
        watchdog_action = WDT_DEBUG;
    else if (strcasecmp(p, "none") == 0)
        watchdog_action = WDT_NONE;
    else
        return -1;

    return 0;
}

L
Luiz Capitulino 已提交
103 104 105 106 107 108 109 110 111
static void watchdog_mon_event(const char *action)
{
    QObject *data;

    data = qobject_from_jsonf("{ 'action': %s }", action);
    monitor_protocol_event(QEVENT_WATCHDOG, data);
    qobject_decref(data);
}

R
Richard W.M. Jones 已提交
112 113 114 115 116 117 118
/* This actually performs the "action" once a watchdog has expired,
 * ie. reboot, shutdown, exit, etc.
 */
void watchdog_perform_action(void)
{
    switch(watchdog_action) {
    case WDT_RESET:             /* same as 'system_reset' in monitor */
L
Luiz Capitulino 已提交
119
        watchdog_mon_event("reset");
R
Richard W.M. Jones 已提交
120 121 122 123
        qemu_system_reset_request();
        break;

    case WDT_SHUTDOWN:          /* same as 'system_powerdown' in monitor */
L
Luiz Capitulino 已提交
124
        watchdog_mon_event("shutdown");
R
Richard W.M. Jones 已提交
125 126 127 128
        qemu_system_powerdown_request();
        break;

    case WDT_POWEROFF:          /* same as 'quit' command in monitor */
L
Luiz Capitulino 已提交
129
        watchdog_mon_event("poweroff");
R
Richard W.M. Jones 已提交
130 131 132 133
        exit(0);
        break;

    case WDT_PAUSE:             /* same as 'stop' command in monitor */
L
Luiz Capitulino 已提交
134
        watchdog_mon_event("pause");
135
        vm_stop(RSTATE_WATCHDOG);
R
Richard W.M. Jones 已提交
136 137 138
        break;

    case WDT_DEBUG:
L
Luiz Capitulino 已提交
139
        watchdog_mon_event("debug");
R
Richard W.M. Jones 已提交
140 141 142 143
        fprintf(stderr, "watchdog: timer fired\n");
        break;

    case WDT_NONE:
L
Luiz Capitulino 已提交
144
        watchdog_mon_event("none");
R
Richard W.M. Jones 已提交
145 146 147
        break;
    }
}