rfkill: support old "list" output

.. just because we want to be replacement for the original version.

Signed-off-by: Karel Zak <kzak@redhat.com>
This commit is contained in:
Karel Zak 2017-10-03 15:35:17 +02:00
parent 49f4f7b6c5
commit 7d2a9960ad
2 changed files with 128 additions and 49 deletions

View file

@ -4,17 +4,24 @@
rfkill \- tool for enabling and disabling wireless devices
.SH SYNOPSIS
.B rfkill
.RI [ options ] " command" " [" id | type \ ...]
.RI [ options ]
.RI [ command ]
.RI [ id|type \ ...]
.SH DESCRIPTION
.B rfkill
lists, enabling and disabling wireless devices.
The command "list" output format is deprecated and maintained for backward
compatibility only. The new output format is the default when no command is
specified or when the option \fB\-\-output\fR is used.
The default output is subject to change. So whenever possible, you should
avoid using default outputs in your scripts. Always explicitly define expected
columns by using the \fB\-\-output\fR option together with a columns list in
environments where a stable output is required.
.SH OPTIONS
.TP
\fB\-J\fR, \fB\-\-json\fR
@ -44,9 +51,8 @@ Display help text and exit.
Listen for rfkill events and display them on stdout.
.TP
\fBlist \fR[\fIid\fR|\fItype\fR ...]
List the current state of all available devices. The full list has TYPE and
ID columns that one can use to limit the scope. It is a good idea to check
with
List the current state of all available devices. The command output format is deprecated, see the section DESCRIPTION.
It is a good idea to check with
.B list
command
.IR id " or " type
@ -66,7 +72,7 @@ Enable the corresponding device. If the device is hard\-blocked, for example
via a hardware switch, it will remain unavailable though it is now
soft\-unblocked.
.SH EXAMPLES
rfkill list
rfkill --output ID,TYPE
.br
rfkill block all
.br
@ -87,6 +93,10 @@ The code has been later modifified by
.MT kerolasa@\:iki.\:fi
Sami Kerola
.ME
and
.MT kzak@\:redhat.\:com
Karel Zak
.ME
for util-linux project.
.PP
This manual page was written by

View file

@ -5,6 +5,7 @@
* Copyright 2009 Marcel Holtmann <marcel@holtmann.org>
* Copyright 2009 Tim Gardner <tim.gardner@canonical.com>
* Copyright 2017 Sami Kerola <kerolasa@iki.fi>
* Copyright (C) 2017 Karel Zak <kzak@redhat.com>
*
* Permission to use, copy, modify, and/or distribute this software for any
* purpose with or without fee is hereby granted, provided that the above
@ -36,6 +37,7 @@
#include "timeutils.h"
#include "widechar.h"
#include "xalloc.h"
#include "path.h"
/*
@ -47,22 +49,23 @@
#endif
struct rfkill_type_str {
enum rfkill_type type;
const char *name;
enum rfkill_type type; /* ID */
const char *name; /* generic name */
const char *desc; /* human readable name */
};
static const struct rfkill_type_str rfkill_type_strings[] = {
{ .type = RFKILL_TYPE_ALL, .name = "all" },
{ .type = RFKILL_TYPE_WLAN, .name = "wifi" },
{ .type = RFKILL_TYPE_WLAN, .name = "wlan" }, /* alias */
{ .type = RFKILL_TYPE_BLUETOOTH, .name = "bluetooth" },
{ .type = RFKILL_TYPE_UWB, .name = "uwb" },
{ .type = RFKILL_TYPE_WLAN, .name = "wlan", .desc = "Wireless LAN" },
{ .type = RFKILL_TYPE_WLAN, .name = "wifi" }, /* alias */
{ .type = RFKILL_TYPE_BLUETOOTH, .name = "bluetooth", .desc = "Bluetooth" },
{ .type = RFKILL_TYPE_UWB, .name = "uwb", .desc = "Ultra-Wideband" },
{ .type = RFKILL_TYPE_UWB, .name = "ultrawideband" }, /* alias */
{ .type = RFKILL_TYPE_WIMAX, .name = "wimax" },
{ .type = RFKILL_TYPE_WWAN, .name = "wwan" },
{ .type = RFKILL_TYPE_GPS, .name = "gps" },
{ .type = RFKILL_TYPE_FM, .name = "fm" },
{ .type = RFKILL_TYPE_NFC, .name = "nfc" },
{ .type = RFKILL_TYPE_WIMAX, .name = "wimax", .desc = "WiMAX" },
{ .type = RFKILL_TYPE_WWAN, .name = "wwan", .desc = "Wireless WAN" },
{ .type = RFKILL_TYPE_GPS, .name = "gps", .desc = "GPT" },
{ .type = RFKILL_TYPE_FM, .name = "fm", .desc = "FM" },
{ .type = RFKILL_TYPE_NFC, .name = "nfc", .desc = "NFC" },
{ .type = NUM_RFKILL_TYPES, .name = NULL }
};
@ -85,7 +88,9 @@ enum {
ACT_HELP,
ACT_EVENT,
ACT_BLOCK,
ACT_UNBLOCK
ACT_UNBLOCK,
ACT_LIST_OLD
};
static char *rfkill_actions[] = {
@ -101,6 +106,7 @@ enum {
COL_DEVICE,
COL_ID,
COL_TYPE,
COL_DESC,
COL_SOFT,
COL_HARD
};
@ -118,6 +124,7 @@ static const struct colinfo infos[] = {
[COL_DEVICE] = {"DEVICE", 0, 0, N_("kernel device name")},
[COL_ID] = {"ID", 2, SCOLS_FL_RIGHT, N_("device identifier value")},
[COL_TYPE] = {"TYPE", 0, 0, N_("device type name that can be used as identifier")},
[COL_DESC] = {"TYPE-DESC", 0, 0, N_("device type description")},
[COL_SOFT] = {"SOFT", 0, SCOLS_FL_RIGHT, N_("status of software block")},
[COL_HARD] = {"HARD", 0, SCOLS_FL_RIGHT, N_("status of hardware block")}
};
@ -263,37 +270,22 @@ failed:
return -1;
}
static const char *get_name_or_type(uint32_t idx, int type)
static const char *get_sys_attr(uint32_t idx, const char *attr)
{
static char name[128] = { 0 };
char *pos, filename[64];
int fd;
if (type)
pos = "type";
else
pos = "name";
snprintf(filename, sizeof(filename) - 1,
_PATH_SYS_RFKILL "/rfkill%u/%s", idx, pos);
fd = open(filename, O_RDONLY);
if (fd < 0) {
warn(_("cannot open %s"), filename);
return NULL;
}
if (read(fd, name, sizeof(name) - 1) < 0) {
warn(_("cannot read %s"), filename);
close(fd);
return NULL;
}
pos = strchr(name, '\n');
if (pos)
*pos = '\0';
close(fd);
static char name[128];
FILE *f = path_fopen("r", 0, _PATH_SYS_RFKILL "/rfkill%u/%s", idx, attr);
char *p;
if (!f)
goto done;
if (!fgets(name, sizeof(name), f))
goto done;
p = strchr(name, '\n');
if (p)
*p = '\0';
done:
if (f)
fclose(f);
return name;
}
@ -331,6 +323,19 @@ static struct rfkill_id rfkill_id_to_type(const char *s)
return ret;
}
static const char *rfkill_type_to_desc(enum rfkill_type type)
{
size_t i;
for (i = 0; i < ARRAY_SIZE(rfkill_type_strings); i++) {
if (type == rfkill_type_strings[i].type)
return rfkill_type_strings[i].desc;
}
return NULL;
}
static int event_match(struct rfkill_event *event, struct rfkill_id *id)
{
if (event->op != RFKILL_OP_ADD)
@ -372,13 +377,16 @@ static void fill_table_row(struct libscols_table *tb, struct rfkill_event *event
char *str = NULL;
switch (get_column_id(i)) {
case COL_DEVICE:
str = xstrdup(get_name_or_type(event->idx, 0));
str = xstrdup(get_sys_attr(event->idx, "name"));
break;
case COL_ID:
xasprintf(&str, "%" PRIu32, event->idx);
break;
case COL_TYPE:
str = xstrdup(get_name_or_type(event->idx, 1));
str = xstrdup(get_sys_attr(event->idx, "type"));
break;
case COL_DESC:
str = xstrdup(rfkill_type_to_desc(event->type));
break;
case COL_SOFT:
str = xstrdup(event->soft ? _("blocked") : _("unblocked"));
@ -394,6 +402,49 @@ static void fill_table_row(struct libscols_table *tb, struct rfkill_event *event
}
}
static int rfkill_list_old(const char *param)
{
struct rfkill_id id = { .result = RFKILL_IS_ALL };
struct rfkill_event event;
int fd, rc = 0;
if (param) {
id = rfkill_id_to_type(param);
if (id.result == RFKILL_IS_INVALID) {
warnx(_("invalid identifier: %s"), param);
return -EINVAL;
}
}
fd = rfkill_ro_open(1);
while (1) {
rc = rfkill_read_event(fd, &event);
if (rc < 0)
break;
if (rc == 1 && errno == EAGAIN) {
rc = 0; /* done */
break;
}
if (rc == 0 && event_match(&event, &id)) {
char *name = xstrdup(get_sys_attr(event.idx, "name")),
*type = xstrdup(rfkill_type_to_desc(event.type));
if (!type)
type = xstrdup(get_sys_attr(event.idx, "type"));
printf("%u: %s: %s\n", event.idx, name, type);
printf("\tSoft blocked: %s\n", event.soft ? "yes" : "no");
printf("\tHard blocked: %s\n", event.hard ? "yes" : "no");
free(name);
free(type);
}
}
close(fd);
return rc;
}
static void rfkill_list_init(struct control *ctrl)
{
size_t i;
@ -527,7 +578,7 @@ static void __attribute__((__noreturn__)) usage(void)
fputs(USAGE_COLUMNS, stdout);
for (i = 0; i < ARRAY_SIZE(infos); i++)
fprintf(stdout, " %-6s %s\n", infos[i].name, _(infos[i].help));
fprintf(stdout, " %-10s %s\n", infos[i].name, _(infos[i].help));
fputs(USAGE_COMMANDS, stdout);
@ -606,9 +657,27 @@ int main(int argc, char **argv)
errtryhelp(EXIT_FAILURE);
argv++;
argc--;
/*
* For backward compatibility we use old output format if
* "list" explicitly specified and--output not defined.
*/
if (!outarg && act == ACT_LIST)
act = ACT_LIST_OLD;
}
switch (act) {
case ACT_LIST_OLD:
/* Deprecated in favour of ACT_LIST */
if (!argc)
ret |= rfkill_list_old(NULL); /* ALL */
else while (argc) {
ret |= rfkill_list_old(*argv);
argc--;
argv++;
}
break;
case ACT_LIST:
columns[ncolumns++] = COL_ID;
columns[ncolumns++] = COL_TYPE;