/*
+ * 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 "timeutils.h"
#include "widechar.h"
#include "xalloc.h"
+#include "all-io.h"
/*
ACT_EVENT,
ACT_BLOCK,
ACT_UNBLOCK,
+ ACT_TOGGLE,
ACT_LIST_OLD
};
[ACT_HELP] = "help",
[ACT_EVENT] = "event",
[ACT_BLOCK] = "block",
- [ACT_UNBLOCK] = "unblock"
+ [ACT_UNBLOCK] = "unblock",
+ [ACT_TOGGLE] = "toggle"
};
/* column IDs */
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;
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;
}
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;
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++) {
}
}
- fd = rfkill_ro_open(1);
+ fd = rfkill_open(1, 1);
+ if (fd < 0)
+ return fd;
while (1) {
rc = rfkill_read_event(fd, &event);
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);
}
}
- fd = rfkill_ro_open(1);
+ fd = rfkill_open(1, 1);
+ if (fd < 0)
+ return fd;
while (1) {
rc = rfkill_read_event(fd, &event);
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");
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);
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;
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++)
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);
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);
case 'r':
ctrl.raw = 1;
break;
+
case 'V':
- printf(UTIL_LINUX_VERSION);
- return EXIT_SUCCESS;
+ print_version(EXIT_SUCCESS);
case 'h':
usage();
default:
/*
* 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;
argc--;
}
break;
+
+ case ACT_TOGGLE:
+ while (argc) {
+ ret |= rfkill_toggle(*argv);
+ argv++;
+ argc--;
+ }
+ break;
}
return ret ? EXIT_FAILURE : EXIT_SUCCESS;