diff options
Diffstat (limited to 'status.c')
| -rw-r--r-- | status.c | 115 |
1 files changed, 111 insertions, 4 deletions
@@ -1,5 +1,6 @@ #include <arpa/inet.h> #include <assert.h> +#include <err.h> #include <errno.h> #include <ifaddrs.h> #include <linux/if.h> @@ -72,6 +73,7 @@ void get_all_bat_status(char* buf); void get_net_link_status(char* buf); int element_wifi(char* buf, char* link_name); static void update_statusbuffer(char* buf); +int element_command(char* buf, char* command); /* Data */ static char* battery_level_icon[] = { @@ -94,9 +96,9 @@ static struct element statusbar[] = { /*{update_func_t, {minutes, seconds}, {0}, {0}},*/ [ELEMENT_INVALID] = {NULL, NULL, {0}, {0}, {0}}, -#define ELEMENT(name, arg, minutes, seconds) \ - [ELEMENT_##name] = { \ - element_##name, \ +#define ELEMENT(identifier, function, arg, minutes, seconds) \ + [ELEMENT_##identifier] = { \ + element_##function, \ arg, \ {(minutes * 60) + ((int)seconds), (long)(seconds * 1000000) % 1000000}, \ {0}, \ @@ -366,6 +368,111 @@ element_wifi(char* buf, char* link_name) { /* external commands */ /* I just couldn't be bothered to learn pipewire */ +int +element_command(char* buf, char* command) { + int output[2]; + if (pipe(output) == -1) { + err(EXIT_FAILURE, "Failed to create pipe"); + } + + pid_t pid = fork(); + if (pid == -1) { + err(EXIT_FAILURE, "Failed to fork new process"); + } + + if (!pid) { + close(output[0]); + + // Redirect stdout to output[1] + if (dup2(output[1], STDOUT_FILENO) == -1) { + err(EXIT_FAILURE, "Failed to redirect stdout"); + } + + // Redirect stderr to stdout + if (dup2(STDOUT_FILENO, STDERR_FILENO) == -1) { + err(EXIT_FAILURE, "Failed to redirect stderr"); + } + + size_t cmd_orig_len = strlen(command); + + if (cmd_orig_len >= 115) { + err(EXIT_FAILURE, "Command too long"); + } + + char cmd[128] = "/usr/bin/env "; // 13 characters + strncat(cmd, command, 128 - 13 - 1); // copies at most 115 bytes + size_t cmd_len = strlen(cmd); + + char* args[64]; + size_t argc = 0; + + char escaped = '\0'; // Bloody hope there's no more nested args than 4 + + // Create args from cmd + // First arg is always the first "word" + args[argc++] = &cmd[0]; + + // Delimeter with zero-bytes at every space, except between single or double + // quotes. + size_t i; + for (i = 0; i < cmd_len; i++) { + // Reset the escaped character + if (cmd[i] == escaped) { + escaped = '\0'; + cmd[i] = '\0'; + continue; + } + + // Set escaped character + if (!escaped && (cmd[i] == '\'' || cmd[i] == '"')) { + escaped = cmd[i]; + // Remove the escaped character from the argument + (args[argc - 1])++; + continue; + } + + // Don't insert zero-chars until we're un-escaped again + if (escaped) { + continue; + } + + if (cmd[i] == ' ') { + cmd[i] = '\0'; + args[argc++] = &cmd[i + 1]; + } + } + + if (i == 0) { + err(EXIT_FAILURE, "Empty command"); + } + + // NULL terminated array + args[argc] = NULL; + + if (execvp(args[0], args) == -1) { + err(EXIT_FAILURE, "Failed to exec"); + } + exit(EXIT_FAILURE); + } + + close(output[1]); + size_t n = 0; + size_t m = 0; + + while (m < ELEMENT_STRBUF_SZ && + (n = read(output[0], &buf[m], ELEMENT_STRBUF_SZ - 1 - m)) > 0) { + m += n; + } + + buf[m] = '\0'; + + for (size_t i = 0; buf[i] != '\0'; i++) { + if (buf[i] == '\n') + buf[i] = ' '; + } + + return 0; +} static struct timespec time_add(struct timespec a, struct timespec b) { @@ -448,7 +555,7 @@ update_element_thread(union sigval sv) { // Empty queue while (mq_receive(mq_data.mqfd, (char*)&msg, sizeof(struct message_t), NULL) != -1) { - fprintf(stderr, "%d on %d\n", msg.action, msg.element); + //fprintf(stderr, "%d on %d\n", msg.action, msg.element); if (msg.action != update || msg.element <= ELEMENT_INVALID || msg.element > ELEMENT_MAX) { fprintf(stderr, "Invalid action/element\n"); |
