]> git.ipfire.org Git - thirdparty/util-linux.git/blobdiff - sys-utils/wdctl.c
misc: cosmetics, remove argument from usage(FILE*)
[thirdparty/util-linux.git] / sys-utils / wdctl.c
index c18f7fc38e076f5657fb3da54d243e850dee67bc..28a24c1f8ea5b1c70e686afdfd33948db80a35db 100644 (file)
  * with this program; if not, write to the Free Software Foundation, Inc.,
  * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
  */
-#include <linux/watchdog.h>
 #include <sys/ioctl.h>
 #include <getopt.h>
 #include <stdio.h>
 #include <unistd.h>
 #include <signal.h>
 #include <assert.h>
+#include <linux/watchdog.h>
+
+#include <libsmartcols.h>
 
 #include "nls.h"
 #include "c.h"
+#include "xalloc.h"
 #include "closestream.h"
 #include "optutils.h"
 #include "pathnames.h"
 #include "strutils.h"
-#include "tt.h"
+#include "carefulputc.h"
+
+/*
+ * since 2.6.18
+ */
+#ifndef WDIOC_SETPRETIMEOUT
+# define WDIOC_SETPRETIMEOUT    _IOWR(WATCHDOG_IOCTL_BASE, 8, int)
+# define WDIOC_GETPRETIMEOUT   _IOR(WATCHDOG_IOCTL_BASE, 9, int)
+# define WDIOC_GETTIMELEFT     _IOR(WATCHDOG_IOCTL_BASE, 10, int)
+# define WDIOF_POWEROVER       0x0040  /* Power over voltage */
+# define WDIOF_SETTIMEOUT      0x0080  /* Set timeout (in seconds) */
+# define WDIOF_MAGICCLOSE      0x0100  /* Supports magic close char */
+# define WDIOF_PRETIMEOUT      0x0200  /* Pretimeout (in seconds), get/set */
+# define WDIOF_KEEPALIVEPING   0x8000  /* Keep alive ping reply */
+#endif
+
+/*
+ * since 3.5
+ */
+#ifndef WDIOF_ALARMONLY
+# define WDIOF_ALARMONLY       0x0400  /* Watchdog triggers a management or
+                                          other external alarm not a reboot */
+#endif
+
+/* basic output flags */
+static int no_headings;
+static int raw;
 
 struct wdflag {
        uint32_t        flag;
@@ -51,7 +80,8 @@ static const struct wdflag wdflags[] = {
        { WDIOF_POWEROVER,     "POWEROVER",  N_("Power over voltage") },
        { WDIOF_POWERUNDER,    "POWERUNDER", N_("Power bad/power fault") },
        { WDIOF_PRETIMEOUT,    "PRETIMEOUT", N_("Pretimeout (in seconds)") },
-       { WDIOF_SETTIMEOUT,    "SETTIMEOUT", N_("Set timeout (in seconds)") }
+       { WDIOF_SETTIMEOUT,    "SETTIMEOUT", N_("Set timeout (in seconds)") },
+       { WDIOF_ALARMONLY,     "ALARMONLY",  N_("Not trigger reboot") }
 };
 
 
@@ -59,7 +89,7 @@ static const struct wdflag wdflags[] = {
 struct colinfo {
        const char *name; /* header */
        double     whint; /* width hint (N < 1 is in percent of termwidth) */
-       int        flags; /* TT_FL_* */
+       int        flags; /* SCOLS_FL_* */
        const char *help;
 };
 
@@ -68,15 +98,15 @@ enum { COL_FLAG, COL_DESC, COL_STATUS, COL_BSTATUS, COL_DEVICE };
 /* columns descriptions */
 static struct colinfo infos[] = {
        [COL_FLAG]    = { "FLAG",        14,  0, N_("flag name") },
-       [COL_DESC]    = { "DESCRIPTION", 0.1, TT_FL_TRUNC, N_("flag description") },
-       [COL_STATUS]  = { "STATUS",      1,   TT_FL_RIGHT, N_("flag status") },
-       [COL_BSTATUS] = { "BOOT-STATUS", 1,   TT_FL_RIGHT, N_("flag boot status") },
+       [COL_DESC]    = { "DESCRIPTION", 0.1, SCOLS_FL_TRUNC, N_("flag description") },
+       [COL_STATUS]  = { "STATUS",      1,   SCOLS_FL_RIGHT, N_("flag status") },
+       [COL_BSTATUS] = { "BOOT-STATUS", 1,   SCOLS_FL_RIGHT, N_("flag boot status") },
        [COL_DEVICE]  = { "DEVICE",      0.1, 0, N_("watchdog device name") }
 
 };
 
-#define NCOLS ARRAY_SIZE(infos)
-static int columns[NCOLS], ncolumns;
+static int columns[ARRAY_SIZE(infos) * 2];
+static int ncolumns;
 
 struct wdinfo {
        char            *device;
@@ -113,7 +143,7 @@ static int column2id(const char *name, size_t namesz)
 {
        size_t i;
 
-       for (i = 0; i < NCOLS; i++) {
+       for (i = 0; i < ARRAY_SIZE(infos); i++) {
                const char *cn = infos[i].name;
                if (!strncasecmp(name, cn, namesz) && !*(cn + namesz))
                        return i;
@@ -124,9 +154,8 @@ static int column2id(const char *name, size_t namesz)
 
 static int get_column_id(int num)
 {
-       assert(ARRAY_SIZE(columns) == NCOLS);
        assert(num < ncolumns);
-       assert(columns[num] < (int) NCOLS);
+       assert(columns[num] < (int) ARRAY_SIZE(infos));
 
        return columns[num];
 }
@@ -136,25 +165,29 @@ static struct colinfo *get_column_info(unsigned num)
        return &infos[ get_column_id(num) ];
 }
 
-static void usage(FILE *out)
+static void __attribute__((__noreturn__)) usage(void)
 {
+       FILE *out = stdout;
        size_t i;
 
        fputs(USAGE_HEADER, out);
        fprintf(out,
              _(" %s [options] [<device> ...]\n"), program_invocation_short_name);
 
-       fputs(USAGE_OPTIONS, out);
+       fputs(USAGE_SEPARATOR, out);
+       fputs(_("Show the status of the hardware watchdog.\n"), out);
 
-       fputs(_(" -f, --flags <list>    print selected flags only\n"
-               " -F, --noflags         don't print information about flags\n"
-               " -I, --noident         don't print watchdog identity information\n"
-               " -n, --noheadings      don't print headings for flags table\n"
-               " -O, --oneline         print all information on one line\n"
-               " -o, --output <list>   output columns of the flags\n"
-               " -r, --raw             use raw output format for flags table\n"
-               " -T, --notimeouts      don't print watchdog timeouts\n"
-               " -x, --flags-only      print only flags table (same as -I -T)\n"), out);
+       fputs(USAGE_OPTIONS, out);
+       fputs(_(" -f, --flags <list>     print selected flags only\n"
+               " -F, --noflags          don't print information about flags\n"
+               " -I, --noident          don't print watchdog identity information\n"
+               " -n, --noheadings       don't print headings for flags table\n"
+               " -O, --oneline          print all information on one line\n"
+               " -o, --output <list>    output columns of the flags\n"
+               " -r, --raw              use raw output format for flags table\n"
+               " -T, --notimeouts       don't print watchdog timeouts\n"
+               " -s, --settimeout <sec> set watchdog timeout\n"
+               " -x, --flags-only       print only flags table (same as -I -T)\n"), out);
 
        fputs(USAGE_SEPARATOR, out);
        fputs(USAGE_HELP, out);
@@ -162,25 +195,24 @@ static void usage(FILE *out)
        fputs(USAGE_SEPARATOR, out);
 
        fprintf(out, _("The default device is %s.\n"), _PATH_WATCHDOG_DEV);
-       fputs(USAGE_SEPARATOR, out);
 
-       fputs(_("Available columns:\n"), out);
+       fputs(USAGE_COLUMNS, out);
        for (i = 0; i < ARRAY_SIZE(infos); i++)
                fprintf(out, " %13s  %s\n", infos[i].name, _(infos[i].help));
 
-       fprintf(out, USAGE_MAN_TAIL("wdctl(1)"));
+       fprintf(out, USAGE_MAN_TAIL("wdctl(8)"));
 
-       exit(out == stderr ? EXIT_FAILURE : EXIT_SUCCESS);
+       exit(EXIT_SUCCESS);
 }
 
-static void add_flag_line(struct tt *tt, struct wdinfo *wd, const struct wdflag *fl)
+static void add_flag_line(struct libscols_table *table, struct wdinfo *wd, const struct wdflag *fl)
 {
        int i;
-       struct tt_line *line;
+       struct libscols_line *line;
 
-       line = tt_add_line(tt, NULL);
+       line = scols_table_new_line(table, NULL);
        if (!line) {
-               warn(_("failed to add line to output"));
+               warn(_("failed to allocate output line"));
                return;
        }
 
@@ -207,31 +239,37 @@ static void add_flag_line(struct tt *tt, struct wdinfo *wd, const struct wdflag
                        break;
                }
 
-               if (str)
-                       tt_line_set_data(line, i, str);
+               if (str && scols_line_set_data(line, i, str)) {
+                       warn(_("failed to add output data"));
+                       break;
+               }
        }
 }
 
-static int show_flags(struct wdinfo *wd, int tt_flags, uint32_t wanted)
+static int show_flags(struct wdinfo *wd, uint32_t wanted)
 {
        size_t i;
        int rc = -1;
-       struct tt *tt;
+       struct libscols_table *table;
        uint32_t flags;
 
+       scols_init_debug(0);
+
        /* create output table */
-       tt = tt_new_table(tt_flags);
-       if (!tt) {
-               warn(_("failed to initialize output table"));
+       table = scols_new_table();
+       if (!table) {
+               warn(_("failed to allocate output table"));
                return -1;
        }
+       scols_table_enable_raw(table, raw);
+       scols_table_enable_noheadings(table, no_headings);
 
        /* define columns */
        for (i = 0; i < (size_t) ncolumns; i++) {
                struct colinfo *col = get_column_info(i);
 
-               if (!tt_define_column(tt, col->name, col->whint, col->flags)) {
-                       warnx(_("failed to initialize output column"));
+               if (!scols_table_new_column(table, col->name, col->whint, col->flags)) {
+                       warnx(_("failed to allocate output column"));
                        goto done;
                }
        }
@@ -244,7 +282,7 @@ static int show_flags(struct wdinfo *wd, int tt_flags, uint32_t wanted)
                if (wanted && !(wanted & wdflags[i].flag))
                        ; /* ignore */
                else if (flags & wdflags[i].flag)
-                       add_flag_line(tt, wd, &wdflags[i]);
+                       add_flag_line(table, wd, &wdflags[i]);
 
                flags &= ~wdflags[i].flag;
        }
@@ -252,10 +290,66 @@ static int show_flags(struct wdinfo *wd, int tt_flags, uint32_t wanted)
        if (flags)
                warnx(_("%s: unknown flags 0x%x\n"), wd->device, flags);
 
-       tt_print_table(tt);
+       scols_print_table(table);
        rc = 0;
 done:
-       tt_free_table(tt);
+       scols_unref_table(table);
+       return rc;
+}
+/*
+ * Warning: successfully opened watchdog has to be properly closed with magic
+ * close character otherwise the machine will be rebooted!
+ *
+ * Don't use err() or exit() here!
+ */
+static int set_watchdog(struct wdinfo *wd, int timeout)
+{
+       int fd;
+       sigset_t sigs, oldsigs;
+       int rc = 0;
+
+       assert(wd->device);
+
+       sigemptyset(&oldsigs);
+       sigfillset(&sigs);
+       sigprocmask(SIG_BLOCK, &sigs, &oldsigs);
+
+       fd = open(wd->device, O_WRONLY|O_CLOEXEC);
+
+       if (fd < 0) {
+               if (errno == EBUSY)
+                       warnx(_("%s: watchdog already in use, terminating."),
+                                       wd->device);
+               warn(_("cannot open %s"), wd->device);
+               return -1;
+       }
+
+       for (;;) {
+               /* We just opened this to query the state, not to arm
+                * it hence use the magic close character */
+               static const char v = 'V';
+
+               if (write(fd, &v, 1) >= 0)
+                       break;
+               if (errno != EINTR) {
+                       warn(_("%s: failed to disarm watchdog"), wd->device);
+                       break;
+               }
+               /* Let's try hard, since if we don't get this right
+                * the machine might end up rebooting. */
+       }
+
+       if (ioctl(fd, WDIOC_SETTIMEOUT, &timeout) != 0) {
+               rc = errno;
+               warn(_("cannot set timeout for %s"), wd->device);
+       }
+
+       if (close_fd(fd))
+               warn(_("write failed"));
+       sigprocmask(SIG_SETMASK, &oldsigs, NULL);
+       printf(P_("Timeout has been set to %d second.\n",
+                 "Timeout has been set to %d seconds.\n", timeout), timeout);
+
        return rc;
 }
 
@@ -282,7 +376,7 @@ static int read_watchdog(struct wdinfo *wd)
                if (errno == EBUSY)
                        warnx(_("%s: watchdog already in use, terminating."),
                                        wd->device);
-               warn(_("%s: open failed"), wd->device);
+               warn(_("cannot open %s"), wd->device);
                return -1;
        }
 
@@ -315,7 +409,8 @@ static int read_watchdog(struct wdinfo *wd)
                 * the machine might end up rebooting. */
        }
 
-       close(fd);
+       if (close_fd(fd))
+               warn(_("write failed"));
        sigprocmask(SIG_SETMASK, &oldsigs, NULL);
 
        return 0;
@@ -330,7 +425,7 @@ static void print_oneline(struct wdinfo *wd, uint32_t wanted,
                printf(" VERSION=\"%x\"", wd->ident.firmware_version);
 
                printf(" IDENTITY=");
-               tt_fputs_quoted((char *) wd->ident.identity, stdout);
+               fputs_quoted((char *) wd->ident.identity, stdout);
        }
        if (!notimeouts) {
                if (wd->has_timeout)
@@ -368,26 +463,23 @@ static void print_oneline(struct wdinfo *wd, uint32_t wanted,
 static void show_timeouts(struct wdinfo *wd)
 {
        if (wd->has_timeout)
-               printf(_("%-15s%2i seconds\n"), _("Timeout:"), wd->timeout);
+               printf(P_("%-14s %2i second\n", "%-14s %2i seconds\n", wd->timeout),
+                         _("Timeout:"), wd->timeout);
        if (wd->has_pretimeout)
-               printf(_("%-15s%2i seconds\n"), _("Pre-timeout:"), wd->pretimeout);
+               printf(P_("%-14s %2i second\n", "%-14s %2i seconds\n", wd->pretimeout),
+                         _("Pre-timeout:"), wd->pretimeout);
        if (wd->has_timeleft)
-               printf(_("%-15s%2i seconds\n"), _("Timeleft:"), wd->timeleft);
+               printf(P_("%-14s %2i second\n", "%-14s %2i seconds\n", wd->timeleft),
+                         _("Timeleft:"), wd->timeleft);
 }
 
 int main(int argc, char *argv[])
 {
        struct wdinfo wd;
-       int c, tt_flags = 0, res = EXIT_SUCCESS, count = 0;
+       int c, res = EXIT_SUCCESS, count = 0;
        char noflags = 0, noident = 0, notimeouts = 0, oneline = 0;
        uint32_t wanted = 0;
-
-       enum {
-               EXCL_NONE,
-               EXCL_FLAGS,
-               EXCL_NOFLAGS
-       };
-       int excl_flag = EXCL_NONE;
+       int timeout = 0;
 
        static const struct option long_opts[] = {
                { "flags",      required_argument, NULL, 'f' },
@@ -397,6 +489,7 @@ int main(int argc, char *argv[])
                { "noheadings", no_argument,       NULL, 'n' },
                { "noident",    no_argument,       NULL, 'I' },
                { "notimeouts", no_argument,       NULL, 'T' },
+               { "settimeout", required_argument, NULL, 's' },
                { "output",     required_argument, NULL, 'o' },
                { "oneline",    no_argument,       NULL, 'O' },
                { "raw",        no_argument,       NULL, 'r' },
@@ -404,13 +497,22 @@ int main(int argc, char *argv[])
                { NULL, 0, NULL, 0 }
        };
 
+       static const ul_excl_t excl[] = {       /* rows and cols in ASCII order */
+               { 'F','f' },                    /* noflags,flags*/
+               { 0 }
+       };
+       int excl_st[ARRAY_SIZE(excl)] = UL_EXCL_STATUS_INIT;
+
        setlocale(LC_ALL, "");
        bindtextdomain(PACKAGE, LOCALEDIR);
        textdomain(PACKAGE);
        atexit(close_stdout);
 
        while ((c = getopt_long(argc, argv,
-                               "d:f:hFnITo:OrVx", long_opts, NULL)) != -1) {
+                               "d:f:hFnITo:s:OrVx", long_opts, NULL)) != -1) {
+
+               err_exclusive_options(c, long_opts, excl, excl_st);
+
                switch(c) {
                case 'o':
                        ncolumns = string_to_idarray(optarg,
@@ -419,8 +521,10 @@ int main(int argc, char *argv[])
                        if (ncolumns < 0)
                                return EXIT_FAILURE;
                        break;
+               case 's':
+                       timeout = strtos32_or_err(optarg, _("invalid timeout argument"));
+                       break;
                case 'f':
-                       exclusive_option(&excl_flag, EXCL_FLAGS, "--{flags,noflags}");
                        if (string_to_bitmask(optarg, (unsigned long *) &wanted, name2bit) != 0)
                                return EXIT_FAILURE;
                        break;
@@ -428,9 +532,8 @@ int main(int argc, char *argv[])
                        printf(UTIL_LINUX_VERSION);
                        return EXIT_SUCCESS;
                case 'h':
-                       usage(stdout);
+                       usage();
                case 'F':
-                       exclusive_option(&excl_flag, EXCL_NOFLAGS, "--{flags,noflags}");
                        noflags = 1;
                        break;
                case 'I':
@@ -440,10 +543,10 @@ int main(int argc, char *argv[])
                        notimeouts = 1;
                        break;
                case 'n':
-                       tt_flags |= TT_FL_NOHEADINGS;
+                       no_headings = 1;
                        break;
                case 'r':
-                       tt_flags |= TT_FL_RAW;
+                       raw = 1;
                        break;
                case 'O':
                        oneline = 1;
@@ -452,10 +555,8 @@ int main(int argc, char *argv[])
                        noident = 1;
                        notimeouts = 1;
                        break;
-
-               case '?':
                default:
-                       usage(stderr);
+                       errtryhelp(EXIT_FAILURE);
                }
        }
 
@@ -481,6 +582,13 @@ int main(int argc, char *argv[])
                        fputc('\n', stdout);
                count++;
 
+               if (timeout) {
+                       rc = set_watchdog(&wd, timeout);
+                       if (rc) {
+                               res = EXIT_FAILURE;
+                       }
+               }
+
                rc = read_watchdog(&wd);
                if (rc) {
                        res = EXIT_FAILURE;
@@ -495,15 +603,16 @@ int main(int argc, char *argv[])
                /* pretty output */
                if (!noident) {
                        printf("%-15s%s\n", _("Device:"), wd.device);
-                       printf(_("%-15s%s [version %x]\n"),
-                                       ("Identity:"),
+                       printf("%-15s%s [%s %x]\n",
+                                       _("Identity:"),
                                        wd.ident.identity,
+                                       _("version"),
                                        wd.ident.firmware_version);
                }
                if (!notimeouts)
                        show_timeouts(&wd);
                if (!noflags)
-                       show_flags(&wd, tt_flags, wanted);
+                       show_flags(&wd, wanted);
        } while (optind < argc);
 
        return res;