]> git.ipfire.org Git - thirdparty/util-linux.git/commitdiff
rfkill: use libsmartcols output
authorSami Kerola <kerolasa@iki.fi>
Sun, 25 Jun 2017 08:42:06 +0000 (09:42 +0100)
committerSami Kerola <kerolasa@iki.fi>
Wed, 30 Aug 2017 19:32:48 +0000 (20:32 +0100)
This also makes the rfkill to output status when executed without arguments.
That is believed ot be more useful than usage() output.

Signed-off-by: Sami Kerola <kerolasa@iki.fi>
configure.ac
sys-utils/Makemodule.am
sys-utils/rfkill.8
sys-utils/rfkill.c

index dd1e324dd6e87ba54717ffc2904d898d2327729b..1fb61bb9fdb1c2bda55b103ffca43673711b72a1 100644 (file)
@@ -1619,6 +1619,7 @@ AM_CONDITIONAL([BUILD_RENICE], [test "x$build_renice" = xyes])
 
 UL_BUILD_INIT([rfkill], [yes])
 UL_REQUIRES_LINUX([rfkill])
+UL_REQUIRES_BUILD([rfkill], [libsmartcols])
 AM_CONDITIONAL([BUILD_RFKILL], [test "x$build_rfkill" = xyes])
 
 UL_BUILD_INIT([setsid], [yes])
index 7eba78d1b47d0ca4dc27f9f754993e11596cfb25..b2d9bf59008e5deaa143aed05f6aba8dcf64e6ff 100644 (file)
@@ -63,7 +63,8 @@ if BUILD_RFKILL
 usrbin_exec_PROGRAMS += rfkill
 dist_man_MANS += sys-utils/rfkill.8
 rfkill_SOURCES = sys-utils/rfkill.c
-rfkill_LDADD = $(LDADD) libcommon.la
+rfkill_LDADD = $(LDADD) libcommon.la libsmartcols.la
+rfkill_CFLAGS = $(AM_CFLAGS) -I$(ul_libsmartcols_incdir)
 endif
 
 if BUILD_SETSID
index 63d3999b48ba33ab798d0a62531650167ff9ef2c..c79e24365f15c194043773b20b50d3123377b256 100644 (file)
@@ -4,9 +4,22 @@
 rfkill \- tool for enabling and disabling wireless devices
 .SH SYNOPSIS
 .B rfkill
-.RI [ options ] " command" " [" index | type ]
+.RI [ options ] " command" " [" id | type ]
 .SH OPTIONS
 .TP
+\fB\-J\fR, \fB\-\-json\fR
+Use JSON output format.
+.TP
+\fB\-n\fR, \fB\-\-noheadings\fR
+Do not print a header line.
+.TP
+\fB\-o\fR, \fB\-\-output\fR
+Specify which output columns to print.  Use \-\-help to get a list of
+available columns.
+.TP
+\fB\-r\fR, \fB\-\-raw\fR
+Use the raw output format.
+.TP
 .B \-\-help
 Display help text and exit.
 .TP
@@ -20,34 +33,26 @@ Display help text and exit.
 .B event
 Listen for rfkill events and display them on stdout.
 .TP
-\fBlist \fR[\fIindex\fR|\fItype\fR]
-List the current state of all available rfkill\-using devices, or just all
-of the given type.
+\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
+.B list
+command
+.BR id " or " type
+scope is appropriate before setting
+.BR block " or " unblock .
+Special
+.B all
+type string will match everything.
 .TP
-\fBblock \fBindex\fR|\fBtype\fR
+\fBblock \fBid\fR|\fBtype\fR
 Disable the corresponding device.
 .TP
-\fBunblock \fBindex\fR|\fBtype\fR
+\fBunblock \fBid\fR|\fBtype\fR
 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.
-.SS
-INDEXES AND TYPES
-.TS
-tab(:);
-left l l.
-0:all
-1:wifi
-1:wlan (alias of wifi)
-2:bluetooth
-3:uwb
-3:ultrawideband (alias of uwb)
-4:wimax
-5:wwan
-6:gps
-7:fm
-8:nfc
-.TE
 .SH EXAMPLES
 rfkill list
 .br
index 717506950f73c4fbe929d5d4282889c915a3d20f..04d4199f0d45189d92c77ceb589fc0ed65923da1 100644 (file)
@@ -20,6 +20,7 @@
 
 #include <ctype.h>
 #include <getopt.h>
+#include <libsmartcols.h>
 #include <linux/rfkill.h>
 #include <sys/poll.h>
 #include <sys/time.h>
 #include "c.h"
 #include "closestream.h"
 #include "nls.h"
+#include "optutils.h"
 #include "pathnames.h"
 #include "strutils.h"
 #include "widechar.h"
+#include "xalloc.h"
 
 struct rfkill_type_str {
        enum rfkill_type type;
@@ -64,6 +67,70 @@ struct rfkill_id {
        } result;
 };
 
+/* column IDs */
+enum {
+       COL_DEVICE,
+       COL_ID,
+       COL_TYPE,
+       COL_SOFT,
+       COL_HARD
+};
+
+/* column names */
+struct colinfo {
+       const char *name;       /* header */
+       double whint;           /* width hint (N < 1 is in percent of termwidth) */
+       int flags;              /* SCOLS_FL_* */
+       const char *help;
+};
+
+/* columns descriptions */
+static const struct colinfo infos[] = {
+       [COL_DEVICE] = {"DEVICE", 0, 0, N_("kernel device name")},
+       [COL_ID]     = {"ID",     0, 0, N_("device identifier value")},
+       [COL_TYPE]   = {"TYPE",   0, 0, N_("device type name that can be used as identifier")},
+       [COL_SOFT]   = {"SOFT",   0, 0, N_("status of software block")},
+       [COL_HARD]   = {"HARD",   0, 0, N_("status of hardware block")}
+};
+
+static int columns[ARRAY_SIZE(infos) * 2];
+static size_t ncolumns;
+
+struct control {
+       unsigned int
+               json:1,
+               no_headings:1,
+               raw:1;
+};
+
+static int column_name_to_id(const char *name, size_t namesz)
+{
+       size_t i;
+
+       assert(name);
+
+       for (i = 0; i < ARRAY_SIZE(infos); i++) {
+               const char *cn = infos[i].name;
+
+               if (!strncasecmp(name, cn, namesz) && !*(cn + namesz))
+                       return i;
+       }
+       warnx(_("unknown column: %s"), name);
+       return -1;
+}
+
+static int get_column_id(size_t num)
+{
+       assert(num < ncolumns);
+       assert(columns[num] < (int)ARRAY_SIZE(infos));
+       return columns[num];
+}
+
+static const struct colinfo *get_column_info(int num)
+{
+       return &infos[get_column_id(num)];
+}
+
 static int rfkill_event(void)
 {
        struct rfkill_event event;
@@ -117,14 +184,18 @@ static int rfkill_event(void)
        return ret;
 }
 
-static const char *get_name(uint32_t idx)
+static const char *get_name_or_type(uint32_t idx, int type)
 {
        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/name", idx);
+                               _PATH_SYS_RFKILL "/rfkill%u/%s", idx, pos);
 
        fd = open(filename, O_RDONLY);
        if (fd < 0) {
@@ -147,35 +218,6 @@ static const char *get_name(uint32_t idx)
        return name;
 }
 
-static const char *type2string(enum rfkill_type type)
-{
-       switch (type) {
-       case RFKILL_TYPE_ALL:
-               return "All";
-       case RFKILL_TYPE_WLAN:
-               return "Wireless LAN";
-       case RFKILL_TYPE_BLUETOOTH:
-               return "Bluetooth";
-       case RFKILL_TYPE_UWB:
-               return "Ultra-Wideband";
-       case RFKILL_TYPE_WIMAX:
-               return "WiMAX";
-       case RFKILL_TYPE_WWAN:
-               return "Wireless WAN";
-       case RFKILL_TYPE_GPS:
-               return "GPS";
-       case RFKILL_TYPE_FM:
-               return "FM";
-       case RFKILL_TYPE_NFC:
-               return "NFC";
-       case NUM_RFKILL_TYPES:
-               return NULL;
-       default:
-               abort();
-       }
-       return NULL;
-}
-
 static struct rfkill_id rfkill_id_to_type(const char *s)
 {
        const struct rfkill_type_str *p;
@@ -203,13 +245,71 @@ static struct rfkill_id rfkill_id_to_type(const char *s)
        return ret;
 }
 
-static int rfkill_list(const char *param)
+static void fill_table_row(struct libscols_table *tb, struct rfkill_event *event)
+{
+       static struct libscols_line *ln;
+       size_t i;
+
+       assert(tb);
+
+       ln = scols_table_new_line(tb, NULL);
+       if (!ln) {
+               errno = ENOMEM;
+               errx(EXIT_FAILURE, _("failed to allocate output line"));
+       }
+
+       for (i = 0; i < (size_t)ncolumns; i++) {
+               char *str = NULL;
+               switch (get_column_id(i)) {
+               case COL_DEVICE:
+                       str = xstrdup(get_name_or_type(event->idx, 0));
+                       break;
+               case COL_ID:
+                       xasprintf(&str, "%" PRIu32, event->idx);
+                       break;
+               case COL_TYPE:
+                       str = xstrdup(get_name_or_type(event->idx, 1));
+                       break;
+               case COL_SOFT:
+                       str = xstrdup(event->soft ? _("blocked") : _("unblocked"));
+                       break;
+               case COL_HARD:
+                       str = xstrdup(event->hard ? _("blocked") : _("unblocked"));
+                       break;
+               default:
+                       abort();
+               }
+               if (str && scols_line_refer_data(ln, i, str))
+                       errx(EXIT_FAILURE, _("failed to add output data"));
+       }
+}
+
+static int rfkill_list(struct control const *const ctrl, const char *param)
 {
        struct rfkill_id id = { .result = RFKILL_IS_ALL };
        struct rfkill_event event;
-       const char *name;
        ssize_t len;
        int fd;
+       struct libscols_table *tb;
+
+       scols_init_debug(0);
+       tb = scols_new_table();
+       if (!tb)
+               err(EXIT_FAILURE, _("failed to allocate output table"));
+
+       scols_table_enable_json(tb, ctrl->json);
+       scols_table_enable_noheadings(tb, ctrl->no_headings);
+       scols_table_enable_raw(tb, ctrl->raw);
+       {
+               size_t i;
+
+               for (i = 0; i < (size_t)ncolumns; i++) {
+                       const struct colinfo *col = get_column_info(i);
+
+                       if (!scols_table_new_column(tb, col->name, col->whint, col->flags))
+                               err(EXIT_FAILURE, _("failed to initialize output column"));
+               }
+       }
 
        if (param) {
                id = rfkill_id_to_type(param);
@@ -263,15 +363,11 @@ static int rfkill_list(const char *param)
                default:
                        abort();
                }
-               name = get_name(event.idx);
-
-               printf("%u: %s: %s\n", event.idx, name,
-                                               type2string(event.type));
-               printf("\t%s: %s\n", _("Soft blocked"), event.soft ? _("yes") : _("no"));
-               printf("\t%s: %s\n", _("Hard blocked"), event.hard ? _("yes") : _("no"));
+               fill_table_row(tb, &event);
        }
-
        close(fd);
+       scols_print_table(tb);
+       scols_unref_table(tb);
        return 0;
 }
 
@@ -319,14 +415,28 @@ static int rfkill_block(uint8_t block, const char *param)
 
 static void __attribute__((__noreturn__)) usage(void)
 {
-       const struct rfkill_type_str *p;
+       size_t i;
 
        fputs(USAGE_HEADER, stdout);
-       fprintf(stdout, _(" %s command [identifier]\n"), program_invocation_short_name);
+       fprintf(stdout, _(" %s [options] command [identifier]\n"), program_invocation_short_name);
 
        fputs(USAGE_SEPARATOR, stdout);
        fputs(_("Tool for enabling and disabling wireless devices.\n"), stdout);
 
+       fputs(USAGE_OPTIONS, stdout);
+       fputs(_(" -J, --json             use JSON output format\n"), stdout);
+       fputs(_(" -n, --noheadings       don't print headings\n"), stdout);
+       fputs(_(" -o, --output <list>    define which output columns to use\n"), stdout);
+       fputs(_(" -r, --raw              use the raw output format\n"), stdout);
+
+       fputs(USAGE_SEPARATOR, stdout);
+       print_usage_help_options(24);
+
+       fputs(USAGE_SEPARATOR, stdout);
+       fputs(_("Available columns:\n"), stdout);
+       for (i = 0; i < ARRAY_SIZE(infos); i++)
+               fprintf(stdout, " %-6s  %s\n", infos[i].name, _(infos[i].help));
+
        fputs(USAGE_SEPARATOR, stdout);
        fputs(_("Commands:\n"), stdout);
        /*
@@ -341,23 +451,29 @@ static void __attribute__((__noreturn__)) usage(void)
        fputs(_(" block   identifier\n"), stdout);
        fputs(_(" unblock identifier\n"), stdout);
 
-       fputs(USAGE_SEPARATOR, stdout);
-       fputs(_("Identifiers, that can be referred by id number or name:\n"), stdout);
-       for (p = rfkill_type_strings; p->name != NULL; p++)
-               printf(" %d %s\n", p->type, p->name);
-
        fprintf(stdout, USAGE_MAN_TAIL("rfkill(8)"));
        exit(EXIT_SUCCESS);
 }
 
 int main(int argc, char **argv)
 {
+       struct control ctrl = { 0 };
        int c;
+       char *outarg = NULL;
        static const struct option longopts[] = {
-               { "version", no_argument, NULL, 'V' },
-               { "help",    no_argument, NULL, 'h' },
+               { "json",       no_argument,       NULL, 'J' },
+               { "noheadings", no_argument,       NULL, 'n' },
+               { "output",     required_argument, NULL, 'o' },
+               { "raw",        no_argument,       NULL, 'r' },
+               { "version",    no_argument,       NULL, 'V' },
+               { "help",       no_argument,       NULL, 'h' },
                { NULL, 0, NULL, 0 }
        };
+       static const ul_excl_t excl[] = {
+               {'J', 'r'},
+               {0}
+       };
+       int excl_st[ARRAY_SIZE(excl)] = UL_EXCL_STATUS_INIT;
        int ret;
 
        setlocale(LC_ALL, "");
@@ -365,8 +481,21 @@ int main(int argc, char **argv)
        textdomain(PACKAGE);
        atexit(close_stdout);
 
-       while ((c = getopt_long(argc, argv, "Vh", longopts, NULL)) != -1)
+       while ((c = getopt_long(argc, argv, "Jno:rVh", longopts, NULL)) != -1) {
+               err_exclusive_options(c, longopts, excl, excl_st);
                switch (c) {
+               case 'J':
+                       ctrl.json = 1;
+                       break;
+               case 'n':
+                       ctrl.no_headings = 1;
+                       break;
+               case 'o':
+                       outarg = optarg;
+                       break;
+               case 'r':
+                       ctrl.raw = 1;
+                       break;
                case 'V':
                        printf(UTIL_LINUX_VERSION);
                        return EXIT_SUCCESS;
@@ -375,20 +504,31 @@ int main(int argc, char **argv)
                default:
                        errtryhelp(EXIT_FAILURE);
                }
-
-       /* Skip program name. */
-       argv++;
-       argc--;
-
-       if (argc == 0 || strcmp(*argv, _("help")) == 0)
-               usage();
-
-       if (strcmp(*argv, "event") == 0) {
+       }
+       argc -= optind;
+       argv += optind;
+
+       if (argc == 0 || strcmp(*argv, "list") == 0) {
+               columns[ncolumns++] = COL_DEVICE;
+               columns[ncolumns++] = COL_ID;
+               columns[ncolumns++] = COL_TYPE;
+               columns[ncolumns++] = COL_SOFT;
+               columns[ncolumns++] = COL_HARD;
+
+               if (outarg
+                   && string_add_to_idarray(outarg, columns,
+                                            ARRAY_SIZE(columns), &ncolumns,
+                                            column_name_to_id) < 0)
+                       return EXIT_FAILURE;
+               if (argc) {
+                       argc--;
+                       argv++;
+               }
+               ret = rfkill_list(&ctrl, *argv);
+       } else if (strcmp(*argv, "event") == 0) {
                ret = rfkill_event();
-       } else if (strcmp(*argv, "list") == 0) {
-               argc--;
-               argv++;
-               ret = rfkill_list(*argv); /* NULL is acceptable */
+       } else if (strcmp(*argv, "help") == 0) {
+               usage();
        } else if (strcmp(*argv, "block") == 0 && argc > 1) {
                argc--;
                argv++;