summaryrefslogtreecommitdiff
path: root/status.c
diff options
context:
space:
mode:
authoronelin <oscar@nelin.dk>2026-05-02 15:43:41 +0000
committeronelin <oscar@nelin.dk>2026-05-02 15:43:41 +0000
commit3cf48f65cd78135b237bc4f562e0a0ea1e0d013d (patch)
treeb614be333dc013ad3f22f947ce664fb52704db18 /status.c
parent56f5db0e3b52aa7dd9d975f46221dfaf8aca4b46 (diff)
Add external command functionalityHEADmaster
Diffstat (limited to 'status.c')
-rw-r--r--status.c115
1 files changed, 111 insertions, 4 deletions
diff --git a/status.c b/status.c
index 935b933..43ccfb7 100644
--- a/status.c
+++ b/status.c
@@ -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");