]> git.ipfire.org Git - thirdparty/util-linux.git/blobdiff - sys-utils/rfkill.c
sys-utils: cleanup license lines, add SPDX
[thirdparty/util-linux.git] / sys-utils / rfkill.c
index 031fe436fd4fb310612498d64d447825228a0803..167d3a23a6a56b0332b8f30ab0e8467ca8c43dc7 100644 (file)
@@ -1,4 +1,6 @@
 /*
+ * SPDX-License-Identifier: ISC
+ *
  * /dev/rfkill userspace tool
  *
  * Copyright 2009 Johannes Berg <johannes@sipsolutions.net>
  * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
  * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
  */
-
 #include <ctype.h>
 #include <getopt.h>
 #include <libsmartcols.h>
 #include <linux/rfkill.h>
-#include <sys/poll.h>
+#include <poll.h>
 #include <sys/syslog.h>
 #include <sys/time.h>
 
@@ -37,7 +38,7 @@
 #include "timeutils.h"
 #include "widechar.h"
 #include "xalloc.h"
-#include "path.h"
+#include "all-io.h"
 
 
 /*
@@ -94,6 +95,7 @@ enum {
        ACT_EVENT,
        ACT_BLOCK,
        ACT_UNBLOCK,
+       ACT_TOGGLE,
 
        ACT_LIST_OLD
 };
@@ -103,7 +105,8 @@ static char *rfkill_actions[] = {
        [ACT_HELP]      = "help",
        [ACT_EVENT]     = "event",
        [ACT_BLOCK]     = "block",
-       [ACT_UNBLOCK]   = "unblock"
+       [ACT_UNBLOCK]   = "unblock",
+       [ACT_TOGGLE]    = "toggle"
 };
 
 /* column IDs */
@@ -184,11 +187,11 @@ static int string_to_action(const char *str)
        return -EINVAL;
 }
 
-static int rfkill_ro_open(int nonblock)
+static int rfkill_open(int rdonly, int nonblock)
 {
        int fd;
 
-       fd = open(_PATH_DEV_RFKILL, O_RDONLY);
+       fd = open(_PATH_DEV_RFKILL, rdonly ? O_RDONLY : O_RDWR);
        if (fd < 0) {
                warn(_("cannot open %s"), _PATH_DEV_RFKILL);
                return -errno;
@@ -215,8 +218,9 @@ static int rfkill_read_event(int fd, struct rfkill_event *event)
                return -errno;
        }
 
-       if (len < RFKILL_EVENT_SIZE_V1) {
-               warnx(_("wrong size of rfkill event: %zu < %d"), len, RFKILL_EVENT_SIZE_V1);
+       if ((size_t) len < (size_t) RFKILL_EVENT_SIZE_V1) {
+               warnx(_("wrong size of rfkill event: %zu < %zu"),
+                               (size_t) len, (size_t) RFKILL_EVENT_SIZE_V1);
                return 1;
        }
 
@@ -226,31 +230,40 @@ static int rfkill_read_event(int fd, struct rfkill_event *event)
 
 static int rfkill_event(void)
 {
+       enum {
+               POLLFD_RFKILL,
+               POLLFD_STDOUT,
+               POLLFD_COUNT
+       };
        struct rfkill_event event;
        struct timeval tv;
        char date_buf[ISO_BUFSIZ];
-       struct pollfd p;
+       struct pollfd p[POLLFD_COUNT];
        int fd, n;
 
-       fd = rfkill_ro_open(0);
+       fd = rfkill_open(1, 0);
        if (fd < 0)
-               return -errno;
+               return fd;
 
        memset(&p, 0, sizeof(p));
-       p.fd = fd;
-       p.events = POLLIN | POLLHUP;
+       p[POLLFD_RFKILL].fd = fd;
+       p[POLLFD_RFKILL].events = POLLIN | POLLHUP;
+       p[POLLFD_STDOUT].fd = STDOUT_FILENO;
+       p[POLLFD_STDOUT].events = 0;
 
        /* interrupted by signal only */
        while (1) {
                int rc = 1;     /* recover-able error */
 
-               n = poll(&p, 1, -1);
+               n = poll(p, ARRAY_SIZE(p), -1);
                if (n < 0) {
                        warn(_("failed to poll %s"), _PATH_DEV_RFKILL);
                        goto failed;
                }
 
-               if (n)
+               if (p[POLLFD_STDOUT].revents)
+                       goto failed; /* read end of stdout closed */
+               if (p[POLLFD_RFKILL].revents)
                        rc = rfkill_read_event(fd, &event);
                if (rc < 0)
                        goto failed;
@@ -274,9 +287,12 @@ failed:
 static const char *get_sys_attr(uint32_t idx, const char *attr)
 {
        static char name[128];
-       FILE *f = path_fopen("r", 0, _PATH_SYS_RFKILL "/rfkill%u/%s", idx, attr);
+       char path[PATH_MAX];
+       FILE *f;
        char *p;
 
+       snprintf(path, sizeof(path), _PATH_SYS_RFKILL "/rfkill%u/%s", idx, attr);
+       f = fopen(path, "r");
        if (!f)
                goto done;
        if (!fgets(name, sizeof(name), f))
@@ -293,7 +309,7 @@ done:
 static struct rfkill_id rfkill_id_to_type(const char *s)
 {
        const struct rfkill_type_str *p;
-       struct rfkill_id ret;
+       struct rfkill_id ret = { .result = 0 };
 
        if (islower(*s)) {
                for (p = rfkill_type_strings; p->name != NULL; p++) {
@@ -417,7 +433,9 @@ static int rfkill_list_old(const char *param)
                }
        }
 
-       fd = rfkill_ro_open(1);
+       fd = rfkill_open(1, 1);
+       if (fd < 0)
+               return fd;
 
        while (1) {
                rc = rfkill_read_event(fd, &event);
@@ -457,14 +475,22 @@ static void rfkill_list_init(struct control *ctrl)
                err(EXIT_FAILURE, _("failed to allocate output table"));
 
        scols_table_enable_json(ctrl->tb, ctrl->json);
+       scols_table_set_name(ctrl->tb, "rfkilldevices");
        scols_table_enable_noheadings(ctrl->tb, ctrl->no_headings);
        scols_table_enable_raw(ctrl->tb, ctrl->raw);
 
        for (i = 0; i < (size_t) ncolumns; i++) {
                const struct colinfo *col = get_column_info(i);
+               struct libscols_column *cl;
 
-               if (!scols_table_new_column(ctrl->tb, col->name, col->whint, col->flags))
+               cl = scols_table_new_column(ctrl->tb, col->name, col->whint, col->flags);
+               if (!cl)
                        err(EXIT_FAILURE, _("failed to allocate output column"));
+               if (ctrl->json) {
+                       int id = get_column_id(i);
+                       if (id == COL_ID)
+                               scols_column_set_json_type(cl, SCOLS_JSON_NUMBER);
+               }
        }
 }
 
@@ -482,7 +508,9 @@ static int rfkill_list_fill(struct control const *ctrl, const char *param)
                }
        }
 
-       fd = rfkill_ro_open(1);
+       fd = rfkill_open(1, 1);
+       if (fd < 0)
+               return fd;
 
        while (1) {
                rc = rfkill_read_event(fd, &event);
@@ -505,32 +533,27 @@ static void rfkill_list_output(struct control const *ctrl)
        scols_unref_table(ctrl->tb);
 }
 
-static int rfkill_block(uint8_t block, const char *param)
+static int __rfkill_block(int fd, struct rfkill_id *id, uint8_t block, const char *param)
 {
-       struct rfkill_id id;
        struct rfkill_event event = {
                .op = RFKILL_OP_CHANGE_ALL,
                .soft = block,
                0
        };
-       ssize_t len;
-       int fd;
        char *message = NULL;
 
-       id = rfkill_id_to_type(param);
-
-       switch (id.result) {
+       switch (id->result) {
        case RFKILL_IS_INVALID:
                warnx(_("invalid identifier: %s"), param);
                return -1;
        case RFKILL_IS_TYPE:
-               event.type = id.type;
+               event.type = id->type;
                xasprintf(&message, "type %s", param);
                break;
        case RFKILL_IS_INDEX:
                event.op = RFKILL_OP_CHANGE;
-               event.idx = id.index;
-               xasprintf(&message, "id %d", id.index);
+               event.idx = id->index;
+               xasprintf(&message, "id %d", id->index);
                break;
        case RFKILL_IS_ALL:
                message = xstrdup("all");
@@ -539,15 +562,7 @@ static int rfkill_block(uint8_t block, const char *param)
                abort();
        }
 
-       fd = open(_PATH_DEV_RFKILL, O_RDWR);
-       if (fd < 0) {
-               warn(_("cannot open %s"), _PATH_DEV_RFKILL);
-               free(message);
-               return -errno;
-       }
-
-       len = write(fd, &event, sizeof(event));
-       if (len < 0)
+       if (write_all(fd, &event, sizeof(event)) != 0)
                warn(_("write failed: %s"), _PATH_DEV_RFKILL);
        else {
                openlog("rfkill", 0, LOG_USER);
@@ -555,9 +570,62 @@ static int rfkill_block(uint8_t block, const char *param)
                closelog();
        }
        free(message);
+       return 0;
+}
+
+static int rfkill_block(uint8_t block, const char *param)
+{
+       struct rfkill_id id;
+       int fd;
+
+       id = rfkill_id_to_type(param);
+       if (id.result == RFKILL_IS_INVALID) {
+               warnx(_("invalid identifier: %s"), param);
+               return -EINVAL;
+       }
+
+       fd = rfkill_open(0, 0);
+       if (fd < 0)
+               return fd;
+
+       __rfkill_block(fd, &id, block, param);
+
        return close(fd);
 }
 
+static int rfkill_toggle(const char *param)
+{
+       struct rfkill_id id = { .result = RFKILL_IS_ALL };
+       struct rfkill_event event;
+       int fd, rc = 0;
+
+       id = rfkill_id_to_type(param);
+       if (id.result == RFKILL_IS_INVALID) {
+               warnx(_("invalid identifier: %s"), param);
+               return -EINVAL;
+       }
+
+       fd = rfkill_open(0, 1);
+       if (fd < 0)
+               return fd;
+
+       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))
+                       __rfkill_block(fd, &id, event.soft ? 0 : 1, param);
+       }
+
+       close(fd);
+       return rc;
+}
+
+
 static void __attribute__((__noreturn__)) usage(void)
 {
        size_t i;
@@ -572,10 +640,11 @@ static void __attribute__((__noreturn__)) usage(void)
        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(_("     --output-all       output all columns\n"), stdout);
        fputs(_(" -r, --raw              use the raw output format\n"), stdout);
 
        fputs(USAGE_SEPARATOR, stdout);
-       printf(USAGE_HELP_OPTIONS(24));
+       fprintf(stdout, USAGE_HELP_OPTIONS(24));
 
        fputs(USAGE_COLUMNS, stdout);
        for (i = 0; i < ARRAY_SIZE(infos); i++)
@@ -585,7 +654,7 @@ static void __attribute__((__noreturn__)) usage(void)
 
        /*
         * TRANSLATORS: command names should not be translated, explaining
-        * them as additional field after identifer is fine, for example
+        * them as additional field after identifier is fine, for example
         *
         * list   [identifier]   (lista [tarkenne])
         */
@@ -594,6 +663,7 @@ static void __attribute__((__noreturn__)) usage(void)
        fputs(_(" list   [identifier]\n"), stdout);
        fputs(_(" block   identifier\n"), stdout);
        fputs(_(" unblock identifier\n"), stdout);
+       fputs(_(" toggle  identifier\n"), stdout);
 
        fprintf(stdout, USAGE_MAN_TAIL("rfkill(8)"));
        exit(EXIT_SUCCESS);
@@ -602,12 +672,16 @@ static void __attribute__((__noreturn__)) usage(void)
 int main(int argc, char **argv)
 {
        struct control ctrl = { 0 };
-       int c, act = ACT_LIST;
+       int c, act = ACT_LIST, list_all = 0;
        char *outarg = NULL;
+       enum {
+               OPT_LIST_TYPES = CHAR_MAX + 1
+       };
        static const struct option longopts[] = {
                { "json",       no_argument,       NULL, 'J' },
                { "noheadings", no_argument,       NULL, 'n' },
                { "output",     required_argument, NULL, 'o' },
+               { "output-all", no_argument,       NULL, OPT_LIST_TYPES },
                { "raw",        no_argument,       NULL, 'r' },
                { "version",    no_argument,       NULL, 'V' },
                { "help",       no_argument,       NULL, 'h' },
@@ -623,7 +697,7 @@ int main(int argc, char **argv)
        setlocale(LC_ALL, "");
        bindtextdomain(PACKAGE, LOCALEDIR);
        textdomain(PACKAGE);
-       atexit(close_stdout);
+       close_stdout_atexit();
 
        while ((c = getopt_long(argc, argv, "Jno:rVh", longopts, NULL)) != -1) {
                err_exclusive_options(c, longopts, excl, excl_st);
@@ -637,12 +711,15 @@ int main(int argc, char **argv)
                case 'o':
                        outarg = optarg;
                        break;
+               case OPT_LIST_TYPES:
+                       list_all = 1;
+                       break;
                case 'r':
                        ctrl.raw = 1;
                        break;
+
                case 'V':
-                       printf(UTIL_LINUX_VERSION);
-                       return EXIT_SUCCESS;
+                       print_version(EXIT_SUCCESS);
                case 'h':
                        usage();
                default:
@@ -661,7 +738,7 @@ int main(int argc, char **argv)
 
                /*
                 * For backward compatibility we use old output format if
-                * "list" explicitly specified and--output not defined.
+                * "list" explicitly specified and --output not defined.
                 */
                if (!outarg && act == ACT_LIST)
                        act = ACT_LIST_OLD;
@@ -683,6 +760,8 @@ int main(int argc, char **argv)
                columns[ncolumns++] = COL_ID;
                columns[ncolumns++] = COL_TYPE;
                columns[ncolumns++] = COL_DEVICE;
+               if (list_all)
+                       columns[ncolumns++] = COL_DESC;
                columns[ncolumns++] = COL_SOFT;
                columns[ncolumns++] = COL_HARD;
 
@@ -726,6 +805,14 @@ int main(int argc, char **argv)
                        argc--;
                }
                break;
+
+       case ACT_TOGGLE:
+               while (argc) {
+                       ret |= rfkill_toggle(*argv);
+                       argv++;
+                       argc--;
+               }
+               break;
        }
 
        return ret ? EXIT_FAILURE : EXIT_SUCCESS;