]> git.ipfire.org Git - thirdparty/util-linux.git/blame - sys-utils/wdctl.c
fstrim shouldn't run inside a container
[thirdparty/util-linux.git] / sys-utils / wdctl.c
CommitLineData
8fb6a2de
LP
1/*
2 * wdctl(8) - show hardware watchdog status
3 *
4 * Copyright (C) 2012 Lennart Poettering
09f9a393 5 * Copyright (C) 2012 Karel Zak <kzak@redhat.com>
8fb6a2de
LP
6 *
7 * This program is free software; you can redistribute it and/or modify it
8 * under the terms of the GNU General Public License as published by the
9 * Free Software Foundation; either version 2, or (at your option) any
10 * later version.
11 *
12 * This program is distributed in the hope that it will be useful, but
13 * WITHOUT ANY WARRANTY; without even the implied warranty of
14 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
15 * General Public License for more details.
16 *
17 * You should have received a copy of the GNU General Public License along
18 * with this program; if not, write to the Free Software Foundation, Inc.,
19 * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
20 */
8fb6a2de
LP
21#include <sys/ioctl.h>
22#include <getopt.h>
23#include <stdio.h>
24#include <unistd.h>
09f9a393
KZ
25#include <signal.h>
26#include <assert.h>
7560aebe 27#include <linux/watchdog.h>
b3dd29d1
KZ
28#include <sys/types.h>
29#include <sys/stat.h>
30#include <unistd.h>
8fb6a2de 31
fe7af530
OO
32#include <libsmartcols.h>
33
8fb6a2de
LP
34#include "nls.h"
35#include "c.h"
2ffddb6a 36#include "xalloc.h"
33a0de92 37#include "closestream.h"
e6dbcc4a 38#include "optutils.h"
33a0de92 39#include "pathnames.h"
09f9a393 40#include "strutils.h"
fe7af530 41#include "carefulputc.h"
b3dd29d1 42#include "path.h"
8fb6a2de 43
2eb5ba0b
KZ
44/*
45 * since 2.6.18
46 */
47#ifndef WDIOC_SETPRETIMEOUT
48# define WDIOC_SETPRETIMEOUT _IOWR(WATCHDOG_IOCTL_BASE, 8, int)
49# define WDIOC_GETPRETIMEOUT _IOR(WATCHDOG_IOCTL_BASE, 9, int)
50# define WDIOC_GETTIMELEFT _IOR(WATCHDOG_IOCTL_BASE, 10, int)
51# define WDIOF_POWEROVER 0x0040 /* Power over voltage */
52# define WDIOF_SETTIMEOUT 0x0080 /* Set timeout (in seconds) */
53# define WDIOF_MAGICCLOSE 0x0100 /* Supports magic close char */
54# define WDIOF_PRETIMEOUT 0x0200 /* Pretimeout (in seconds), get/set */
55# define WDIOF_KEEPALIVEPING 0x8000 /* Keep alive ping reply */
56#endif
57
58/*
59 * since 3.5
60 */
61#ifndef WDIOF_ALARMONLY
62# define WDIOF_ALARMONLY 0x0400 /* Watchdog triggers a management or
63 other external alarm not a reboot */
64#endif
65
09f9a393
KZ
66struct wdflag {
67 uint32_t flag;
68 const char *name;
69 const char *description;
8fb6a2de
LP
70};
71
09f9a393
KZ
72static const struct wdflag wdflags[] = {
73 { WDIOF_CARDRESET, "CARDRESET", N_("Card previously reset the CPU") },
74 { WDIOF_EXTERN1, "EXTERN1", N_("External relay 1") },
75 { WDIOF_EXTERN2, "EXTERN2", N_("External relay 2") },
76 { WDIOF_FANFAULT, "FANFAULT", N_("Fan failed") },
77 { WDIOF_KEEPALIVEPING, "KEEPALIVEPING", N_("Keep alive ping reply") },
78 { WDIOF_MAGICCLOSE, "MAGICCLOSE", N_("Supports magic close char") },
79 { WDIOF_OVERHEAT, "OVERHEAT", N_("Reset due to CPU overheat") },
80 { WDIOF_POWEROVER, "POWEROVER", N_("Power over voltage") },
81 { WDIOF_POWERUNDER, "POWERUNDER", N_("Power bad/power fault") },
82 { WDIOF_PRETIMEOUT, "PRETIMEOUT", N_("Pretimeout (in seconds)") },
2eb5ba0b
KZ
83 { WDIOF_SETTIMEOUT, "SETTIMEOUT", N_("Set timeout (in seconds)") },
84 { WDIOF_ALARMONLY, "ALARMONLY", N_("Not trigger reboot") }
09f9a393
KZ
85};
86
87
88/* column names */
89struct colinfo {
90 const char *name; /* header */
91 double whint; /* width hint (N < 1 is in percent of termwidth) */
fe7af530 92 int flags; /* SCOLS_FL_* */
09f9a393
KZ
93 const char *help;
94};
95
96747e75 96enum { COL_FLAG, COL_DESC, COL_STATUS, COL_BSTATUS, COL_DEVICE };
09f9a393
KZ
97
98/* columns descriptions */
99static struct colinfo infos[] = {
100 [COL_FLAG] = { "FLAG", 14, 0, N_("flag name") },
fe7af530
OO
101 [COL_DESC] = { "DESCRIPTION", 0.1, SCOLS_FL_TRUNC, N_("flag description") },
102 [COL_STATUS] = { "STATUS", 1, SCOLS_FL_RIGHT, N_("flag status") },
103 [COL_BSTATUS] = { "BOOT-STATUS", 1, SCOLS_FL_RIGHT, N_("flag boot status") },
96747e75
KZ
104 [COL_DEVICE] = { "DEVICE", 0.1, 0, N_("watchdog device name") }
105
09f9a393
KZ
106};
107
059a91f8
KZ
108static int columns[ARRAY_SIZE(infos) * 2];
109static int ncolumns;
09f9a393 110
e4d511d4 111struct wd_device {
8c8df421 112 const char *devpath;
09f9a393
KZ
113
114 int timeout;
115 int timeleft;
116 int pretimeout;
117
118 uint32_t status;
119 uint32_t bstatus;
b3dd29d1 120 int nowayout;
09f9a393
KZ
121
122 struct watchdog_info ident;
123
124 unsigned int has_timeout : 1,
125 has_timeleft : 1,
b3dd29d1
KZ
126 has_pretimeout : 1,
127 has_nowayout : 1;
09f9a393
KZ
128};
129
a599d137
KZ
130struct wd_control {
131 unsigned int show_oneline : 1,
132 show_raw : 1,
133 hide_headings : 1,
134 hide_flags : 1,
135 hide_ident : 1,
136 hide_timeouts : 1;
137};
138
09f9a393
KZ
139/* converts flag name to flag bit */
140static long name2bit(const char *name, size_t namesz)
141{
142 size_t i;
143
144 for (i = 0; i < ARRAY_SIZE(wdflags); i++) {
145 const char *cn = wdflags[i].name;
146 if (!strncasecmp(name, cn, namesz) && !*(cn + namesz))
147 return wdflags[i].flag;
148 }
149 warnx(_("unknown flag: %s"), name);
150 return -1;
151}
152
153static int column2id(const char *name, size_t namesz)
154{
155 size_t i;
156
059a91f8 157 for (i = 0; i < ARRAY_SIZE(infos); i++) {
09f9a393
KZ
158 const char *cn = infos[i].name;
159 if (!strncasecmp(name, cn, namesz) && !*(cn + namesz))
160 return i;
161 }
162 warnx(_("unknown column: %s"), name);
163 return -1;
164}
165
166static int get_column_id(int num)
167{
09f9a393 168 assert(num < ncolumns);
059a91f8 169 assert(columns[num] < (int) ARRAY_SIZE(infos));
09f9a393
KZ
170
171 return columns[num];
172}
173
174static struct colinfo *get_column_info(unsigned num)
175{
176 return &infos[ get_column_id(num) ];
177}
178
8c8df421
KZ
179/* We preffer cdev /dev/watchdog0 as this device has node in
180 * /sys/class/watchdog/. The old miscdev /dev/watchdog is fallback for old
181 * systemds only.
182 */
183static const char *get_default_device(void)
184{
185 const char **p;
186 static const char *devs[] = {
187 "/dev/watchdog0",
188 "/dev/watchdog",
189 NULL
190 };
191
192 for (p = devs; *p; p++) {
193 if (access(*p, F_OK) == 0)
194 return *p;
195 }
196
197 return NULL;
198}
199
86be6a32 200static void __attribute__((__noreturn__)) usage(void)
8fb6a2de 201{
86be6a32 202 FILE *out = stdout;
09f9a393 203 size_t i;
8c8df421 204 const char *dflt = get_default_device();
8fb6a2de
LP
205
206 fputs(USAGE_HEADER, out);
207 fprintf(out,
f56338b4 208 _(" %s [options] [<device> ...]\n"), program_invocation_short_name);
8fb6a2de 209
451dbcfa
BS
210 fputs(USAGE_SEPARATOR, out);
211 fputs(_("Show the status of the hardware watchdog.\n"), out);
8fb6a2de 212
451dbcfa 213 fputs(USAGE_OPTIONS, out);
fb8b62df
HH
214 fputs(_(" -f, --flags <list> print selected flags only\n"
215 " -F, --noflags don't print information about flags\n"
216 " -I, --noident don't print watchdog identity information\n"
217 " -n, --noheadings don't print headings for flags table\n"
218 " -O, --oneline print all information on one line\n"
219 " -o, --output <list> output columns of the flags\n"
220 " -r, --raw use raw output format for flags table\n"
221 " -T, --notimeouts don't print watchdog timeouts\n"
222 " -s, --settimeout <sec> set watchdog timeout\n"
223 " -x, --flags-only print only flags table (same as -I -T)\n"), out);
09f9a393 224
8fb6a2de 225 fputs(USAGE_SEPARATOR, out);
f45f3ec3 226 printf(USAGE_HELP_OPTIONS(24));
09f9a393
KZ
227 fputs(USAGE_SEPARATOR, out);
228
8c8df421
KZ
229 if (dflt)
230 fprintf(out, _("The default device is %s.\n"), dflt);
231 else
232 fprintf(out, _("No default device is available.\n"));
f56338b4 233
6e2d5a44 234 fputs(USAGE_COLUMNS, out);
09f9a393
KZ
235 for (i = 0; i < ARRAY_SIZE(infos); i++)
236 fprintf(out, " %13s %s\n", infos[i].name, _(infos[i].help));
237
f45f3ec3 238 printf(USAGE_MAN_TAIL("wdctl(8)"));
8fb6a2de 239
86be6a32 240 exit(EXIT_SUCCESS);
8fb6a2de
LP
241}
242
e4d511d4 243static void add_flag_line(struct libscols_table *table, struct wd_device *wd, const struct wdflag *fl)
8fb6a2de 244{
09f9a393 245 int i;
fe7af530 246 struct libscols_line *line;
8fb6a2de 247
fe7af530 248 line = scols_table_new_line(table, NULL);
09f9a393 249 if (!line) {
780ce22c 250 warn(_("failed to allocate output line"));
8fb6a2de
LP
251 return;
252 }
253
09f9a393
KZ
254 for (i = 0; i < ncolumns; i++) {
255 const char *str = NULL;
256
257 switch (get_column_id(i)) {
258 case COL_FLAG:
259 str = fl->name;
260 break;
261 case COL_DESC:
262 str = fl->description;
263 break;
264 case COL_STATUS:
265 str = wd->status & fl->flag ? "1" : "0";
266 break;
267 case COL_BSTATUS:
268 str = wd->bstatus & fl->flag ? "1" : "0";
269 break;
96747e75 270 case COL_DEVICE:
e4d511d4 271 str = wd->devpath;
96747e75 272 break;
09f9a393
KZ
273 default:
274 break;
275 }
8fb6a2de 276
780ce22c
KZ
277 if (str && scols_line_set_data(line, i, str)) {
278 warn(_("failed to add output data"));
279 break;
280 }
09f9a393 281 }
8fb6a2de
LP
282}
283
a599d137 284static int show_flags(struct wd_control *ctl, struct wd_device *wd, uint32_t wanted)
8fb6a2de 285{
09f9a393
KZ
286 size_t i;
287 int rc = -1;
fe7af530 288 struct libscols_table *table;
09f9a393
KZ
289 uint32_t flags;
290
b3dd29d1
KZ
291 /* information about supported bits is probably missing in /sys */
292 if (!wd->ident.options)
293 return 0;
294
710ed55d
KZ
295 scols_init_debug(0);
296
09f9a393 297 /* create output table */
0925a9dd 298 table = scols_new_table();
fe7af530 299 if (!table) {
780ce22c 300 warn(_("failed to allocate output table"));
09f9a393
KZ
301 return -1;
302 }
a599d137
KZ
303 scols_table_enable_raw(table, ctl->show_raw);
304 scols_table_enable_noheadings(table, ctl->hide_headings);
8fb6a2de 305
09f9a393
KZ
306 /* define columns */
307 for (i = 0; i < (size_t) ncolumns; i++) {
308 struct colinfo *col = get_column_info(i);
8fb6a2de 309
fe7af530 310 if (!scols_table_new_column(table, col->name, col->whint, col->flags)) {
780ce22c 311 warnx(_("failed to allocate output column"));
09f9a393 312 goto done;
8fb6a2de
LP
313 }
314 }
315
09f9a393
KZ
316 /* fill-in table with data
317 * -- one line for each supported flag (option) */
318 flags = wd->ident.options;
8fb6a2de 319
09f9a393
KZ
320 for (i = 0; i < ARRAY_SIZE(wdflags); i++) {
321 if (wanted && !(wanted & wdflags[i].flag))
322 ; /* ignore */
323 else if (flags & wdflags[i].flag)
fe7af530 324 add_flag_line(table, wd, &wdflags[i]);
8fb6a2de 325
09f9a393 326 flags &= ~wdflags[i].flag;
8fb6a2de
LP
327 }
328
09f9a393 329 if (flags)
e4d511d4 330 warnx(_("%s: unknown flags 0x%x\n"), wd->devpath, flags);
8fb6a2de 331
fe7af530 332 scols_print_table(table);
09f9a393
KZ
333 rc = 0;
334done:
fe7af530 335 scols_unref_table(table);
09f9a393
KZ
336 return rc;
337}
fb8b62df
HH
338/*
339 * Warning: successfully opened watchdog has to be properly closed with magic
340 * close character otherwise the machine will be rebooted!
341 *
342 * Don't use err() or exit() here!
343 */
e4d511d4 344static int set_watchdog(struct wd_device *wd, int timeout)
fb8b62df
HH
345{
346 int fd;
347 sigset_t sigs, oldsigs;
348 int rc = 0;
349
e4d511d4 350 assert(wd->devpath);
fb8b62df
HH
351
352 sigemptyset(&oldsigs);
353 sigfillset(&sigs);
354 sigprocmask(SIG_BLOCK, &sigs, &oldsigs);
355
e4d511d4 356 fd = open(wd->devpath, O_WRONLY|O_CLOEXEC);
fb8b62df
HH
357
358 if (fd < 0) {
359 if (errno == EBUSY)
360 warnx(_("%s: watchdog already in use, terminating."),
e4d511d4
KZ
361 wd->devpath);
362 warn(_("cannot open %s"), wd->devpath);
fb8b62df
HH
363 return -1;
364 }
365
366 for (;;) {
367 /* We just opened this to query the state, not to arm
368 * it hence use the magic close character */
369 static const char v = 'V';
370
371 if (write(fd, &v, 1) >= 0)
372 break;
373 if (errno != EINTR) {
e4d511d4 374 warn(_("%s: failed to disarm watchdog"), wd->devpath);
fb8b62df
HH
375 break;
376 }
377 /* Let's try hard, since if we don't get this right
378 * the machine might end up rebooting. */
379 }
380
381 if (ioctl(fd, WDIOC_SETTIMEOUT, &timeout) != 0) {
382 rc = errno;
e4d511d4 383 warn(_("cannot set timeout for %s"), wd->devpath);
fb8b62df
HH
384 }
385
4aaabaa9 386 if (close(fd))
3757e57f 387 warn(_("write failed"));
fb8b62df 388 sigprocmask(SIG_SETMASK, &oldsigs, NULL);
5b831eb1
BS
389 printf(P_("Timeout has been set to %d second.\n",
390 "Timeout has been set to %d seconds.\n", timeout), timeout);
fb8b62df
HH
391
392 return rc;
393}
8fb6a2de 394
09f9a393
KZ
395/*
396 * Warning: successfully opened watchdog has to be properly closed with magic
397 * close character otherwise the machine will be rebooted!
398 *
399 * Don't use err() or exit() here!
400 */
b3dd29d1 401static int read_watchdog_from_device(struct wd_device *wd)
09f9a393
KZ
402{
403 int fd;
404 sigset_t sigs, oldsigs;
405
e4d511d4 406 assert(wd->devpath);
09f9a393
KZ
407
408 sigemptyset(&oldsigs);
409 sigfillset(&sigs);
410 sigprocmask(SIG_BLOCK, &sigs, &oldsigs);
8fb6a2de 411
e4d511d4 412 fd = open(wd->devpath, O_WRONLY|O_CLOEXEC);
8fb6a2de 413
b3dd29d1
KZ
414 if (fd < 0)
415 return -errno;
8fb6a2de 416
09f9a393 417 if (ioctl(fd, WDIOC_GETSUPPORT, &wd->ident) < 0)
e4d511d4 418 warn(_("%s: failed to get information about watchdog"), wd->devpath);
09f9a393
KZ
419 else {
420 ioctl(fd, WDIOC_GETSTATUS, &wd->status);
421 ioctl(fd, WDIOC_GETBOOTSTATUS, &wd->bstatus);
422
423 if (ioctl(fd, WDIOC_GETTIMEOUT, &wd->timeout) >= 0)
424 wd->has_timeout = 1;
425 if (ioctl(fd, WDIOC_GETPRETIMEOUT, &wd->pretimeout) >= 0)
426 wd->has_pretimeout = 1;
427 if (ioctl(fd, WDIOC_GETTIMELEFT, &wd->timeleft) >= 0)
428 wd->has_timeleft = 1;
429 }
8fb6a2de
LP
430
431 for (;;) {
432 /* We just opened this to query the state, not to arm
433 * it hence use the magic close character */
8fb6a2de
LP
434 static const char v = 'V';
435
436 if (write(fd, &v, 1) >= 0)
437 break;
8fb6a2de 438 if (errno != EINTR) {
e4d511d4 439 warn(_("%s: failed to disarm watchdog"), wd->devpath);
8fb6a2de
LP
440 break;
441 }
8fb6a2de
LP
442 /* Let's try hard, since if we don't get this right
443 * the machine might end up rebooting. */
444 }
445
4aaabaa9 446 if (close(fd))
3757e57f 447 warn(_("write failed"));
09f9a393
KZ
448 sigprocmask(SIG_SETMASK, &oldsigs, NULL);
449
450 return 0;
451}
452
b3dd29d1
KZ
453/* Returns: <0 error, 0 success, 1 unssuported */
454static int read_watchdog_from_sysfs(struct wd_device *wd)
455{
456 struct path_cxt *sys;
457 struct stat st;
458 int rc;
459
460 rc = stat(wd->devpath, &st);
461 if (rc != 0)
462 return rc;
463
464 sys = ul_new_path(_PATH_SYS_DEVCHAR "/%u:%u",
465 major(st.st_rdev), minor(st.st_rdev));
466 if (!sys)
467 return -ENOMEM;
468
469 if (ul_path_get_dirfd(sys) < 0)
470 goto nosysfs; /* device not in /sys */
471
472 if (ul_path_access(sys, F_OK, "identity") != 0)
473 goto nosysfs; /* no info in /sys (old miscdev?) */
474
475 ul_path_read_buffer(sys, (char *) wd->ident.identity, sizeof(wd->ident.identity), "identity");
476
477 ul_path_scanf(sys, "status", "%x", &wd->status);
478 ul_path_read_u32(sys, &wd->bstatus, "bootstatus");
479
480 if (ul_path_read_s32(sys, &wd->nowayout, "nowayout") == 0)
481 wd->has_nowayout = 1;
482 if (ul_path_read_s32(sys, &wd->timeout, "timeout") == 0)
483 wd->has_timeout = 1;
484 if (ul_path_read_s32(sys, &wd->pretimeout, "pretimeout") == 0)
485 wd->has_pretimeout = 1;
486 if (ul_path_read_s32(sys, &wd->timeleft, "timeleft") == 0)
487 wd->has_timeleft = 1;
488
489 ul_unref_path(sys);
490 return 0;
491nosysfs:
492 ul_unref_path(sys);
493 return 1;
494}
495
496static int read_watchdog(struct wd_device *wd)
497{
498 int rc = read_watchdog_from_device(wd);
499
500 if (rc == -EBUSY || rc == -EACCES || rc == -EPERM)
501 rc = read_watchdog_from_sysfs(wd);
502
503 if (rc) {
504 warn(_("cannot read information about %s"), wd->devpath);
505 return -1;
506 }
507
508 return 0;
509}
510
5d628f37
KZ
511static void show_timeouts(struct wd_device *wd)
512{
513 if (wd->has_timeout)
514 printf(P_("%-14s %2i second\n", "%-14s %2i seconds\n", wd->timeout),
515 _("Timeout:"), wd->timeout);
516 if (wd->has_pretimeout)
517 printf(P_("%-14s %2i second\n", "%-14s %2i seconds\n", wd->pretimeout),
518 _("Pre-timeout:"), wd->pretimeout);
519 if (wd->has_timeleft)
520 printf(P_("%-14s %2i second\n", "%-14s %2i seconds\n", wd->timeleft),
521 _("Timeleft:"), wd->timeleft);
522}
523
a599d137 524static void print_oneline(struct wd_control *ctl, struct wd_device *wd, uint32_t wanted)
9561d1af 525{
e4d511d4 526 printf("%s:", wd->devpath);
9561d1af 527
a599d137 528 if (!ctl->hide_ident) {
9561d1af
KZ
529 printf(" VERSION=\"%x\"", wd->ident.firmware_version);
530
531 printf(" IDENTITY=");
fe7af530 532 fputs_quoted((char *) wd->ident.identity, stdout);
9561d1af 533 }
a599d137 534 if (!ctl->hide_timeouts) {
9561d1af
KZ
535 if (wd->has_timeout)
536 printf(" TIMEOUT=\"%i\"", wd->timeout);
537 if (wd->has_pretimeout)
538 printf(" PRETIMEOUT=\"%i\"", wd->pretimeout);
539 if (wd->has_timeleft)
540 printf(" TIMELEFT=\"%i\"", wd->timeleft);
541 }
542
a599d137 543 if (!ctl->hide_flags) {
9561d1af
KZ
544 size_t i;
545 uint32_t flags = wd->ident.options;
546
547 for (i = 0; i < ARRAY_SIZE(wdflags); i++) {
548 const struct wdflag *fl;
549
550 if ((wanted && !(wanted & wdflags[i].flag)) ||
551 !(flags & wdflags[i].flag))
552 continue;
553
554 fl= &wdflags[i];
555
556 printf(" %s=\"%s\"", fl->name,
557 wd->status & fl->flag ? "1" : "0");
558 printf(" %s_BOOT=\"%s\"", fl->name,
559 wd->bstatus & fl->flag ? "1" : "0");
560
561 }
562 }
563
564 fputc('\n', stdout);
565}
566
5d628f37 567static void print_device(struct wd_control *ctl, struct wd_device *wd, uint32_t wanted)
09f9a393 568{
5d628f37
KZ
569 /* NAME=value one line output */
570 if (ctl->show_oneline) {
571 print_oneline(ctl, wd, wanted);
572 return;
573 }
574
575 /* pretty output */
576 if (!ctl->hide_ident) {
577 printf("%-15s%s\n", _("Device:"), wd->devpath);
578 printf("%-15s%s [%s %x]\n",
579 _("Identity:"),
580 wd->ident.identity,
581 _("version"),
582 wd->ident.firmware_version);
583 }
584 if (!ctl->hide_timeouts)
585 show_timeouts(wd);
586
587 if (!ctl->hide_flags)
588 show_flags(ctl, wd, wanted);
09f9a393 589}
8fb6a2de 590
09f9a393
KZ
591int main(int argc, char *argv[])
592{
e4d511d4 593 struct wd_device wd;
a599d137 594 struct wd_control ctl = { .hide_headings = 0 };
fe7af530 595 int c, res = EXIT_SUCCESS, count = 0;
09f9a393 596 uint32_t wanted = 0;
fb8b62df 597 int timeout = 0;
8c8df421 598 const char *dflt_device = NULL;
09f9a393
KZ
599
600 static const struct option long_opts[] = {
09f9a393 601 { "flags", required_argument, NULL, 'f' },
96747e75 602 { "flags-only", no_argument, NULL, 'x' },
09f9a393
KZ
603 { "help", no_argument, NULL, 'h' },
604 { "noflags", no_argument, NULL, 'F' },
605 { "noheadings", no_argument, NULL, 'n' },
606 { "noident", no_argument, NULL, 'I' },
607 { "notimeouts", no_argument, NULL, 'T' },
fb8b62df 608 { "settimeout", required_argument, NULL, 's' },
09f9a393 609 { "output", required_argument, NULL, 'o' },
9561d1af 610 { "oneline", no_argument, NULL, 'O' },
09f9a393
KZ
611 { "raw", no_argument, NULL, 'r' },
612 { "version", no_argument, NULL, 'V' },
613 { NULL, 0, NULL, 0 }
614 };
615
a7349ee3 616 static const ul_excl_t excl[] = { /* rows and cols in ASCII order */
1c608be1
KZ
617 { 'F','f' }, /* noflags,flags*/
618 { 0 }
619 };
620 int excl_st[ARRAY_SIZE(excl)] = UL_EXCL_STATUS_INIT;
621
09f9a393
KZ
622 setlocale(LC_ALL, "");
623 bindtextdomain(PACKAGE, LOCALEDIR);
624 textdomain(PACKAGE);
2c308875 625 close_stdout_atexit();
09f9a393
KZ
626
627 while ((c = getopt_long(argc, argv,
fb8b62df 628 "d:f:hFnITo:s:OrVx", long_opts, NULL)) != -1) {
1c608be1
KZ
629
630 err_exclusive_options(c, long_opts, excl, excl_st);
631
09f9a393 632 switch(c) {
09f9a393
KZ
633 case 'o':
634 ncolumns = string_to_idarray(optarg,
635 columns, ARRAY_SIZE(columns),
636 column2id);
637 if (ncolumns < 0)
638 return EXIT_FAILURE;
639 break;
fb8b62df
HH
640 case 's':
641 timeout = strtos32_or_err(optarg, _("invalid timeout argument"));
642 break;
09f9a393
KZ
643 case 'f':
644 if (string_to_bitmask(optarg, (unsigned long *) &wanted, name2bit) != 0)
645 return EXIT_FAILURE;
646 break;
09f9a393 647 case 'F':
a599d137 648 ctl.hide_flags = 1;
09f9a393
KZ
649 break;
650 case 'I':
a599d137 651 ctl.hide_ident = 1;
09f9a393
KZ
652 break;
653 case 'T':
a599d137 654 ctl.hide_timeouts = 1;
09f9a393
KZ
655 break;
656 case 'n':
a599d137 657 ctl.hide_headings = 1;
09f9a393
KZ
658 break;
659 case 'r':
a599d137 660 ctl.show_raw = 1;
09f9a393 661 break;
9561d1af 662 case 'O':
a599d137 663 ctl.show_oneline = 1;
09f9a393 664 break;
96747e75 665 case 'x':
a599d137
KZ
666 ctl.hide_ident = 1;
667 ctl.hide_timeouts = 1;
96747e75 668 break;
2c308875
KZ
669
670 case 'h':
671 usage();
672 case 'V':
673 print_version(EXIT_SUCCESS);
09f9a393 674 default:
677ec86c 675 errtryhelp(EXIT_FAILURE);
09f9a393
KZ
676 }
677 }
678
09f9a393
KZ
679 if (!ncolumns) {
680 /* default columns */
681 columns[ncolumns++] = COL_FLAG;
682 columns[ncolumns++] = COL_DESC;
683 columns[ncolumns++] = COL_STATUS;
684 columns[ncolumns++] = COL_BSTATUS;
685 }
686
8c8df421
KZ
687 /* Device no specified, use default. */
688 if (optind == argc) {
689 dflt_device = get_default_device();
690 if (!dflt_device)
691 err(EXIT_FAILURE, _("No default device is available."));
692 }
693
f56338b4
KZ
694 do {
695 int rc;
09f9a393 696
f56338b4 697 memset(&wd, 0, sizeof(wd));
8c8df421 698 wd.devpath = dflt_device ? dflt_device : argv[optind++];
f56338b4
KZ
699
700 if (count)
701 fputc('\n', stdout);
702 count++;
703
fb8b62df
HH
704 if (timeout) {
705 rc = set_watchdog(&wd, timeout);
706 if (rc) {
707 res = EXIT_FAILURE;
708 }
709 }
710
f56338b4
KZ
711 rc = read_watchdog(&wd);
712 if (rc) {
713 res = EXIT_FAILURE;
714 continue;
715 }
716
5d628f37 717 print_device(&ctl, &wd, wanted);
9561d1af 718
f56338b4
KZ
719 } while (optind < argc);
720
721 return res;
8fb6a2de 722}