]> git.ipfire.org Git - thirdparty/util-linux.git/blame - sys-utils/rfkill.c
lsns: rename notruns to no_trunc
[thirdparty/util-linux.git] / sys-utils / rfkill.c
CommitLineData
d5fad6eb 1/*
e69263c0
SK
2 * /dev/rfkill userspace tool
3 *
4 * Copyright 2009 Johannes Berg <johannes@sipsolutions.net>
5 * Copyright 2009 Marcel Holtmann <marcel@holtmann.org>
6 * Copyright 2009 Tim Gardner <tim.gardner@canonical.com>
f4949fcc 7 * Copyright 2017 Sami Kerola <kerolasa@iki.fi>
7d2a9960 8 * Copyright (C) 2017 Karel Zak <kzak@redhat.com>
e69263c0
SK
9 *
10 * Permission to use, copy, modify, and/or distribute this software for any
11 * purpose with or without fee is hereby granted, provided that the above
12 * copyright notice and this permission notice appear in all copies.
13 *
14 * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
15 * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
16 * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
17 * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
18 * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
19 * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
20 * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
d5fad6eb
JB
21 */
22
b1849b89 23#include <ctype.h>
367f4080 24#include <getopt.h>
b3849c66 25#include <libsmartcols.h>
367f4080 26#include <linux/rfkill.h>
07d517c0 27#include <sys/poll.h>
fd3d4ec7 28#include <sys/syslog.h>
6217bea3 29#include <sys/time.h>
d5fad6eb 30
c0d78c90
SK
31#include "c.h"
32#include "closestream.h"
33#include "nls.h"
b3849c66 34#include "optutils.h"
367f4080
SK
35#include "pathnames.h"
36#include "strutils.h"
7d0b3acb 37#include "timeutils.h"
367f4080 38#include "widechar.h"
b3849c66 39#include "xalloc.h"
7d2a9960 40#include "path.h"
367f4080 41
ea05c23a
KZ
42
43/*
44 * NFC supported by kernel since v3.10 (year 2013); FM and another types are from
45 * year 2009 (2.6.33) or older.
46 */
47#ifndef RFKILL_TYPE_NFC
48# define RFKILL_TYPE_NFC RFKILL_TYPE_FM + 1
49#endif
50
367f4080 51struct rfkill_type_str {
7d2a9960
KZ
52 enum rfkill_type type; /* ID */
53 const char *name; /* generic name */
54 const char *desc; /* human readable name */
367f4080
SK
55};
56
57static const struct rfkill_type_str rfkill_type_strings[] = {
58 { .type = RFKILL_TYPE_ALL, .name = "all" },
7d2a9960
KZ
59 { .type = RFKILL_TYPE_WLAN, .name = "wlan", .desc = "Wireless LAN" },
60 { .type = RFKILL_TYPE_WLAN, .name = "wifi" }, /* alias */
61 { .type = RFKILL_TYPE_BLUETOOTH, .name = "bluetooth", .desc = "Bluetooth" },
62 { .type = RFKILL_TYPE_UWB, .name = "uwb", .desc = "Ultra-Wideband" },
367f4080 63 { .type = RFKILL_TYPE_UWB, .name = "ultrawideband" }, /* alias */
7d2a9960
KZ
64 { .type = RFKILL_TYPE_WIMAX, .name = "wimax", .desc = "WiMAX" },
65 { .type = RFKILL_TYPE_WWAN, .name = "wwan", .desc = "Wireless WAN" },
9e33cddd 66 { .type = RFKILL_TYPE_GPS, .name = "gps", .desc = "GPS" },
7d2a9960
KZ
67 { .type = RFKILL_TYPE_FM, .name = "fm", .desc = "FM" },
68 { .type = RFKILL_TYPE_NFC, .name = "nfc", .desc = "NFC" },
367f4080
SK
69 { .type = NUM_RFKILL_TYPES, .name = NULL }
70};
71
72struct rfkill_id {
73 union {
74 enum rfkill_type type;
75 uint32_t index;
76 };
77 enum {
78 RFKILL_IS_INVALID,
79 RFKILL_IS_TYPE,
80 RFKILL_IS_INDEX,
b03378e7 81 RFKILL_IS_ALL
367f4080
SK
82 } result;
83};
d5fad6eb 84
18d3a03f
KZ
85/* supported actions */
86enum {
87 ACT_LIST,
88 ACT_HELP,
89 ACT_EVENT,
90 ACT_BLOCK,
7d2a9960
KZ
91 ACT_UNBLOCK,
92
93 ACT_LIST_OLD
18d3a03f
KZ
94};
95
96static char *rfkill_actions[] = {
97 [ACT_LIST] = "list",
98 [ACT_HELP] = "help",
99 [ACT_EVENT] = "event",
100 [ACT_BLOCK] = "block",
101 [ACT_UNBLOCK] = "unblock"
102};
103
b3849c66
SK
104/* column IDs */
105enum {
106 COL_DEVICE,
107 COL_ID,
108 COL_TYPE,
7d2a9960 109 COL_DESC,
b3849c66
SK
110 COL_SOFT,
111 COL_HARD
112};
113
114/* column names */
115struct colinfo {
116 const char *name; /* header */
117 double whint; /* width hint (N < 1 is in percent of termwidth) */
118 int flags; /* SCOLS_FL_* */
119 const char *help;
120};
121
122/* columns descriptions */
123static const struct colinfo infos[] = {
124 [COL_DEVICE] = {"DEVICE", 0, 0, N_("kernel device name")},
7d8e3bcd 125 [COL_ID] = {"ID", 2, SCOLS_FL_RIGHT, N_("device identifier value")},
b3849c66 126 [COL_TYPE] = {"TYPE", 0, 0, N_("device type name that can be used as identifier")},
7d2a9960 127 [COL_DESC] = {"TYPE-DESC", 0, 0, N_("device type description")},
7d8e3bcd
KZ
128 [COL_SOFT] = {"SOFT", 0, SCOLS_FL_RIGHT, N_("status of software block")},
129 [COL_HARD] = {"HARD", 0, SCOLS_FL_RIGHT, N_("status of hardware block")}
b3849c66
SK
130};
131
132static int columns[ARRAY_SIZE(infos) * 2];
133static size_t ncolumns;
134
135struct control {
4f892d77 136 struct libscols_table *tb;
b3849c66
SK
137 unsigned int
138 json:1,
139 no_headings:1,
140 raw:1;
141};
142
143static int column_name_to_id(const char *name, size_t namesz)
144{
145 size_t i;
146
147 assert(name);
148
149 for (i = 0; i < ARRAY_SIZE(infos); i++) {
150 const char *cn = infos[i].name;
151
152 if (!strncasecmp(name, cn, namesz) && !*(cn + namesz))
153 return i;
154 }
155 warnx(_("unknown column: %s"), name);
156 return -1;
157}
158
159static int get_column_id(size_t num)
160{
161 assert(num < ncolumns);
162 assert(columns[num] < (int)ARRAY_SIZE(infos));
163 return columns[num];
164}
165
166static const struct colinfo *get_column_info(int num)
167{
168 return &infos[get_column_id(num)];
169}
170
18d3a03f
KZ
171static int string_to_action(const char *str)
172{
173 size_t i;
174
175 for (i = 0; i < ARRAY_SIZE(rfkill_actions); i++)
176 if (strcmp(str, rfkill_actions[i]) == 0)
177 return i;
178
179 return -EINVAL;
180}
181
49f4f7b6
KZ
182static int rfkill_ro_open(int nonblock)
183{
184 int fd;
185
186 fd = open(_PATH_DEV_RFKILL, O_RDONLY);
187 if (fd < 0) {
188 warn(_("cannot open %s"), _PATH_DEV_RFKILL);
189 return -errno;
190 }
191
192 if (nonblock && fcntl(fd, F_SETFL, O_NONBLOCK) < 0) {
193 warn(_("cannot set non-blocking %s"), _PATH_DEV_RFKILL);
194 close(fd);
195 return -errno;
196 }
197
198 return fd;
199}
200
201/* returns: 0 success, 1 read again, < 0 error */
202static int rfkill_read_event(int fd, struct rfkill_event *event)
203{
dec4fae2 204 ssize_t len = read(fd, event, sizeof(*event));
49f4f7b6
KZ
205
206 if (len < 0) {
207 if (errno == EAGAIN)
208 return 1;
209 warn(_("cannot read %s"), _PATH_DEV_RFKILL);
210 return -errno;
211 }
212
213 if (len < RFKILL_EVENT_SIZE_V1) {
214 warnx(_("wrong size of rfkill event: %zu < %d"), len, RFKILL_EVENT_SIZE_V1);
215 return 1;
216 }
217
218 return 0;
219}
220
221
367f4080 222static int rfkill_event(void)
07d517c0 223{
51da1093 224 struct rfkill_event event;
6217bea3 225 struct timeval tv;
4111bb3a 226 char date_buf[ISO_BUFSIZ];
07d517c0 227 struct pollfd p;
3c5022c6 228 int fd, n;
07d517c0 229
49f4f7b6
KZ
230 fd = rfkill_ro_open(0);
231 if (fd < 0)
3c5022c6 232 return -errno;
07d517c0
MH
233
234 memset(&p, 0, sizeof(p));
235 p.fd = fd;
236 p.events = POLLIN | POLLHUP;
237
3c5022c6 238 /* interrupted by signal only */
07d517c0 239 while (1) {
49f4f7b6
KZ
240 int rc = 1; /* recover-able error */
241
07d517c0
MH
242 n = poll(&p, 1, -1);
243 if (n < 0) {
367f4080 244 warn(_("failed to poll %s"), _PATH_DEV_RFKILL);
3c5022c6 245 goto failed;
07d517c0
MH
246 }
247
49f4f7b6
KZ
248 if (n)
249 rc = rfkill_read_event(fd, &event);
250 if (rc < 0)
3c5022c6 251 goto failed;
49f4f7b6 252 if (rc)
07d517c0 253 continue;
49f4f7b6 254
6217bea3 255 gettimeofday(&tv, NULL);
4111bb3a
WP
256 strtimeval_iso(&tv, ISO_TIMESTAMP_COMMA, date_buf,
257 sizeof(date_buf));
7d0b3acb
SK
258 printf("%s: idx %u type %u op %u soft %u hard %u\n",
259 date_buf,
260 event.idx, event.type, event.op, event.soft, event.hard);
1634aef2 261 fflush(stdout);
07d517c0
MH
262 }
263
3c5022c6 264failed:
07d517c0 265 close(fd);
3c5022c6 266 return -1;
07d517c0
MH
267}
268
7d2a9960 269static const char *get_sys_attr(uint32_t idx, const char *attr)
07d517c0 270{
7d2a9960
KZ
271 static char name[128];
272 FILE *f = path_fopen("r", 0, _PATH_SYS_RFKILL "/rfkill%u/%s", idx, attr);
273 char *p;
274
275 if (!f)
276 goto done;
277 if (!fgets(name, sizeof(name), f))
278 goto done;
279 p = strchr(name, '\n');
280 if (p)
281 *p = '\0';
282done:
283 if (f)
284 fclose(f);
07d517c0
MH
285 return name;
286}
287
fafd9121
DS
288static struct rfkill_id rfkill_id_to_type(const char *s)
289{
290 const struct rfkill_type_str *p;
291 struct rfkill_id ret;
292
293 if (islower(*s)) {
294 for (p = rfkill_type_strings; p->name != NULL; p++) {
367f4080 295 if (!strcmp(s, p->name)) {
fafd9121 296 ret.type = p->type;
b03378e7
SK
297 if (!strcmp(s, "all"))
298 ret.result = RFKILL_IS_ALL;
299 else
300 ret.result = RFKILL_IS_TYPE;
fafd9121
DS
301 return ret;
302 }
303 }
304 } else if (isdigit(*s)) {
305 /* assume a numeric character implies an index. */
f806a238
SK
306 char filename[64];
307
367f4080 308 ret.index = strtou32_or_err(s, _("invalid identifier"));
f806a238
SK
309 snprintf(filename, sizeof(filename) - 1,
310 _PATH_SYS_RFKILL "/rfkill%" PRIu32 "/name", ret.index);
311 if (access(filename, F_OK) == 0)
312 ret.result = RFKILL_IS_INDEX;
313 else
314 ret.result = RFKILL_IS_INVALID;
fafd9121
DS
315 return ret;
316 }
317
318 ret.result = RFKILL_IS_INVALID;
319 return ret;
320}
321
7d2a9960
KZ
322static const char *rfkill_type_to_desc(enum rfkill_type type)
323{
324 size_t i;
325
326 for (i = 0; i < ARRAY_SIZE(rfkill_type_strings); i++) {
327 if (type == rfkill_type_strings[i].type)
328 return rfkill_type_strings[i].desc;
329 }
330
331 return NULL;
332}
333
334
49f4f7b6
KZ
335static int event_match(struct rfkill_event *event, struct rfkill_id *id)
336{
337 if (event->op != RFKILL_OP_ADD)
338 return 0;
339
340 /* filter out unwanted results */
341 switch (id->result) {
342 case RFKILL_IS_TYPE:
343 if (event->type != id->type)
344 return 0;
345 break;
346 case RFKILL_IS_INDEX:
347 if (event->idx != id->index)
348 return 0;
349 break;
350 case RFKILL_IS_ALL:
351 break;
352 default:
353 abort();
354 }
355
356 return 1;
357}
358
b3849c66
SK
359static void fill_table_row(struct libscols_table *tb, struct rfkill_event *event)
360{
361 static struct libscols_line *ln;
362 size_t i;
363
364 assert(tb);
365
366 ln = scols_table_new_line(tb, NULL);
367 if (!ln) {
368 errno = ENOMEM;
369 errx(EXIT_FAILURE, _("failed to allocate output line"));
370 }
371
372 for (i = 0; i < (size_t)ncolumns; i++) {
373 char *str = NULL;
374 switch (get_column_id(i)) {
375 case COL_DEVICE:
7d2a9960 376 str = xstrdup(get_sys_attr(event->idx, "name"));
b3849c66
SK
377 break;
378 case COL_ID:
379 xasprintf(&str, "%" PRIu32, event->idx);
380 break;
381 case COL_TYPE:
7d2a9960
KZ
382 str = xstrdup(get_sys_attr(event->idx, "type"));
383 break;
384 case COL_DESC:
385 str = xstrdup(rfkill_type_to_desc(event->type));
b3849c66
SK
386 break;
387 case COL_SOFT:
388 str = xstrdup(event->soft ? _("blocked") : _("unblocked"));
389 break;
390 case COL_HARD:
391 str = xstrdup(event->hard ? _("blocked") : _("unblocked"));
392 break;
393 default:
394 abort();
395 }
396 if (str && scols_line_refer_data(ln, i, str))
397 errx(EXIT_FAILURE, _("failed to add output data"));
398 }
399}
400
7d2a9960
KZ
401static int rfkill_list_old(const char *param)
402{
403 struct rfkill_id id = { .result = RFKILL_IS_ALL };
404 struct rfkill_event event;
405 int fd, rc = 0;
406
407 if (param) {
408 id = rfkill_id_to_type(param);
409 if (id.result == RFKILL_IS_INVALID) {
410 warnx(_("invalid identifier: %s"), param);
411 return -EINVAL;
412 }
413 }
414
415 fd = rfkill_ro_open(1);
416
417 while (1) {
418 rc = rfkill_read_event(fd, &event);
419 if (rc < 0)
420 break;
421 if (rc == 1 && errno == EAGAIN) {
422 rc = 0; /* done */
423 break;
424 }
425 if (rc == 0 && event_match(&event, &id)) {
426 char *name = xstrdup(get_sys_attr(event.idx, "name")),
427 *type = xstrdup(rfkill_type_to_desc(event.type));
428
429 if (!type)
430 type = xstrdup(get_sys_attr(event.idx, "type"));
431
432 printf("%u: %s: %s\n", event.idx, name, type);
433 printf("\tSoft blocked: %s\n", event.soft ? "yes" : "no");
434 printf("\tHard blocked: %s\n", event.hard ? "yes" : "no");
435
436 free(name);
437 free(type);
438 }
439 }
440 close(fd);
441 return rc;
442}
443
4f892d77 444static void rfkill_list_init(struct control *ctrl)
07d517c0 445{
e8f6060f
KZ
446 size_t i;
447
b3849c66 448 scols_init_debug(0);
e8f6060f 449
4f892d77
SK
450 ctrl->tb = scols_new_table();
451 if (!ctrl->tb)
b3849c66
SK
452 err(EXIT_FAILURE, _("failed to allocate output table"));
453
4f892d77
SK
454 scols_table_enable_json(ctrl->tb, ctrl->json);
455 scols_table_enable_noheadings(ctrl->tb, ctrl->no_headings);
456 scols_table_enable_raw(ctrl->tb, ctrl->raw);
b3849c66 457
e8f6060f
KZ
458 for (i = 0; i < (size_t) ncolumns; i++) {
459 const struct colinfo *col = get_column_info(i);
b3849c66 460
e8f6060f
KZ
461 if (!scols_table_new_column(ctrl->tb, col->name, col->whint, col->flags))
462 err(EXIT_FAILURE, _("failed to allocate output column"));
b3849c66 463 }
4f892d77
SK
464}
465
4f892d77
SK
466static int rfkill_list_fill(struct control const *ctrl, const char *param)
467{
468 struct rfkill_id id = { .result = RFKILL_IS_ALL };
469 struct rfkill_event event;
49f4f7b6 470 int fd, rc = 0;
07d517c0 471
a9405c24
DS
472 if (param) {
473 id = rfkill_id_to_type(param);
474 if (id.result == RFKILL_IS_INVALID) {
367f4080 475 warnx(_("invalid identifier: %s"), param);
3c5022c6 476 return -EINVAL;
a9405c24 477 }
a9405c24
DS
478 }
479
49f4f7b6 480 fd = rfkill_ro_open(1);
07d517c0
MH
481
482 while (1) {
49f4f7b6
KZ
483 rc = rfkill_read_event(fd, &event);
484 if (rc < 0)
a9405c24 485 break;
49f4f7b6
KZ
486 if (rc == 1 && errno == EAGAIN) {
487 rc = 0; /* done */
a9405c24 488 break;
a9405c24 489 }
49f4f7b6
KZ
490 if (rc == 0 && event_match(&event, &id))
491 fill_table_row(ctrl->tb, &event);
07d517c0 492 }
07d517c0 493 close(fd);
49f4f7b6 494 return rc;
07d517c0
MH
495}
496
4f892d77
SK
497static void rfkill_list_output(struct control const *ctrl)
498{
499 scols_print_table(ctrl->tb);
500 scols_unref_table(ctrl->tb);
501}
502
367f4080 503static int rfkill_block(uint8_t block, const char *param)
07d517c0 504{
fafd9121 505 struct rfkill_id id;
b03378e7
SK
506 struct rfkill_event event = {
507 .op = RFKILL_OP_CHANGE_ALL,
508 .soft = block,
509 0
510 };
07d517c0
MH
511 ssize_t len;
512 int fd;
fd3d4ec7 513 char *message = NULL;
07d517c0 514
fafd9121 515 id = rfkill_id_to_type(param);
07d517c0 516
fafd9121 517 switch (id.result) {
b03378e7
SK
518 case RFKILL_IS_INVALID:
519 warnx(_("invalid identifier: %s"), param);
3c5022c6 520 return -1;
fafd9121 521 case RFKILL_IS_TYPE:
fafd9121 522 event.type = id.type;
fd3d4ec7 523 xasprintf(&message, "type %s", param);
fafd9121
DS
524 break;
525 case RFKILL_IS_INDEX:
526 event.op = RFKILL_OP_CHANGE;
527 event.idx = id.index;
fd3d4ec7 528 xasprintf(&message, "id %d", id.index);
fafd9121 529 break;
b03378e7 530 case RFKILL_IS_ALL:
fd3d4ec7 531 message = xstrdup("all");
367f4080
SK
532 break;
533 default:
534 abort();
94297403 535 }
b03378e7
SK
536
537 fd = open(_PATH_DEV_RFKILL, O_RDWR);
538 if (fd < 0) {
539 warn(_("cannot open %s"), _PATH_DEV_RFKILL);
fd3d4ec7 540 free(message);
3c5022c6 541 return -errno;
b03378e7 542 }
07d517c0
MH
543
544 len = write(fd, &event, sizeof(event));
545 if (len < 0)
367f4080 546 warn(_("write failed: %s"), _PATH_DEV_RFKILL);
3c5022c6
KZ
547 else {
548 openlog("rfkill", 0, LOG_USER);
549 syslog(LOG_NOTICE, "%s set for %s", block ? "block" : "unblock", message);
550 closelog();
551 }
fd3d4ec7 552 free(message);
b1209668 553 return close(fd);
07d517c0
MH
554}
555
367f4080 556static void __attribute__((__noreturn__)) usage(void)
07d517c0 557{
b3849c66 558 size_t i;
47eaa870 559
367f4080 560 fputs(USAGE_HEADER, stdout);
4f892d77 561 fprintf(stdout, _(" %s [options] command [identifier ...]\n"), program_invocation_short_name);
367f4080
SK
562
563 fputs(USAGE_SEPARATOR, stdout);
564 fputs(_("Tool for enabling and disabling wireless devices.\n"), stdout);
565
b3849c66
SK
566 fputs(USAGE_OPTIONS, stdout);
567 fputs(_(" -J, --json use JSON output format\n"), stdout);
568 fputs(_(" -n, --noheadings don't print headings\n"), stdout);
569 fputs(_(" -o, --output <list> define which output columns to use\n"), stdout);
570 fputs(_(" -r, --raw use the raw output format\n"), stdout);
571
572 fputs(USAGE_SEPARATOR, stdout);
fcc3efb4 573 printf(USAGE_HELP_OPTIONS(24));
b3849c66 574
fcc3efb4 575 fputs(USAGE_COLUMNS, stdout);
b3849c66 576 for (i = 0; i < ARRAY_SIZE(infos); i++)
7d2a9960 577 fprintf(stdout, " %-10s %s\n", infos[i].name, _(infos[i].help));
b3849c66 578
fcc3efb4
KZ
579 fputs(USAGE_COMMANDS, stdout);
580
367f4080
SK
581 /*
582 * TRANSLATORS: command names should not be translated, explaining
583 * them as additional field after identifer is fine, for example
584 *
585 * list [identifier] (lista [tarkenne])
586 */
587 fputs(_(" help\n"), stdout);
588 fputs(_(" event\n"), stdout);
589 fputs(_(" list [identifier]\n"), stdout);
590 fputs(_(" block identifier\n"), stdout);
591 fputs(_(" unblock identifier\n"), stdout);
592
367f4080
SK
593 fprintf(stdout, USAGE_MAN_TAIL("rfkill(8)"));
594 exit(EXIT_SUCCESS);
d5fad6eb
JB
595}
596
597int main(int argc, char **argv)
598{
b3849c66 599 struct control ctrl = { 0 };
18d3a03f 600 int c, act = ACT_LIST;
b3849c66 601 char *outarg = NULL;
367f4080 602 static const struct option longopts[] = {
b3849c66
SK
603 { "json", no_argument, NULL, 'J' },
604 { "noheadings", no_argument, NULL, 'n' },
605 { "output", required_argument, NULL, 'o' },
606 { "raw", no_argument, NULL, 'r' },
607 { "version", no_argument, NULL, 'V' },
608 { "help", no_argument, NULL, 'h' },
367f4080
SK
609 { NULL, 0, NULL, 0 }
610 };
b3849c66
SK
611 static const ul_excl_t excl[] = {
612 {'J', 'r'},
613 {0}
614 };
615 int excl_st[ARRAY_SIZE(excl)] = UL_EXCL_STATUS_INIT;
4f892d77 616 int ret = 0;
367f4080
SK
617
618 setlocale(LC_ALL, "");
619 bindtextdomain(PACKAGE, LOCALEDIR);
620 textdomain(PACKAGE);
621 atexit(close_stdout);
622
b3849c66
SK
623 while ((c = getopt_long(argc, argv, "Jno:rVh", longopts, NULL)) != -1) {
624 err_exclusive_options(c, longopts, excl, excl_st);
367f4080 625 switch (c) {
b3849c66
SK
626 case 'J':
627 ctrl.json = 1;
628 break;
629 case 'n':
630 ctrl.no_headings = 1;
631 break;
632 case 'o':
633 outarg = optarg;
634 break;
635 case 'r':
636 ctrl.raw = 1;
637 break;
367f4080
SK
638 case 'V':
639 printf(UTIL_LINUX_VERSION);
640 return EXIT_SUCCESS;
641 case 'h':
642 usage();
643 default:
644 errtryhelp(EXIT_FAILURE);
645 }
b3849c66
SK
646 }
647 argc -= optind;
648 argv += optind;
649
18d3a03f
KZ
650 if (argc > 0) {
651 act = string_to_action(*argv);
652 if (act < 0)
653 errtryhelp(EXIT_FAILURE);
654 argv++;
655 argc--;
7d2a9960
KZ
656
657 /*
658 * For backward compatibility we use old output format if
659 * "list" explicitly specified and--output not defined.
660 */
661 if (!outarg && act == ACT_LIST)
662 act = ACT_LIST_OLD;
18d3a03f
KZ
663 }
664
665 switch (act) {
7d2a9960
KZ
666 case ACT_LIST_OLD:
667 /* Deprecated in favour of ACT_LIST */
668 if (!argc)
669 ret |= rfkill_list_old(NULL); /* ALL */
670 else while (argc) {
671 ret |= rfkill_list_old(*argv);
672 argc--;
673 argv++;
674 }
675 break;
676
18d3a03f 677 case ACT_LIST:
b3849c66
SK
678 columns[ncolumns++] = COL_ID;
679 columns[ncolumns++] = COL_TYPE;
7d8e3bcd 680 columns[ncolumns++] = COL_DEVICE;
b3849c66
SK
681 columns[ncolumns++] = COL_SOFT;
682 columns[ncolumns++] = COL_HARD;
683
684 if (outarg
685 && string_add_to_idarray(outarg, columns,
686 ARRAY_SIZE(columns), &ncolumns,
687 column_name_to_id) < 0)
688 return EXIT_FAILURE;
18d3a03f 689
4f892d77 690 rfkill_list_init(&ctrl);
18d3a03f
KZ
691 if (!argc)
692 ret |= rfkill_list_fill(&ctrl, NULL); /* ALL */
693 else while (argc) {
4f892d77 694 ret |= rfkill_list_fill(&ctrl, *argv);
18d3a03f
KZ
695 argc--;
696 argv++;
b3849c66 697 }
4f892d77 698 rfkill_list_output(&ctrl);
18d3a03f
KZ
699 break;
700
701 case ACT_EVENT:
367f4080 702 ret = rfkill_event();
18d3a03f
KZ
703 break;
704
705 case ACT_HELP:
b3849c66 706 usage();
18d3a03f
KZ
707 break;
708
709 case ACT_BLOCK:
710 while (argc) {
4f892d77 711 ret |= rfkill_block(1, *argv);
18d3a03f 712 argc--;
4f892d77 713 argv++;
18d3a03f
KZ
714 }
715 break;
716
717 case ACT_UNBLOCK:
718 while (argc) {
4f892d77 719 ret |= rfkill_block(0, *argv);
18d3a03f
KZ
720 argv++;
721 argc--;
4f892d77 722 }
18d3a03f
KZ
723 break;
724 }
07d517c0 725
3c5022c6 726 return ret ? EXIT_FAILURE : EXIT_SUCCESS;
d5fad6eb 727}