Commit Diff


commit - 23a90cf95d6b733db64c1c4adb136018997a8fd1
commit + c9b5e794e4a1455fe3ead85670b45c65e72fe873
blob - 29ccceaafc5b3c6e989b5075ad1ed8015cf05366
blob + d88a1e429c79a4fe86b55d0d4e52d4e20b54f6c6
--- include/statbar.h
+++ include/statbar.h
@@ -3,6 +3,7 @@
 #include <stdio.h>
 
 #include <poll.h>
+#include <unistd.h>
 
 /* Glyphs */
 #define MAIL "\ueb1c"
@@ -19,6 +20,8 @@
 #define WIFI "\uf1eb"
 #define ETHERNET "\uef09"
 
+extern void close_display(void);
+
 /* FS */
 extern bool weather_loc_valid;
 extern bool mail_path_valid;
@@ -42,12 +45,9 @@ extern void normalize_clock_interval(const struct time
 extern pid_t start_privileged_battery_process(int *pipe_fd, const struct timespec *timeout);
 
 /* Volume */
-extern char volume_string[11];
+#define VOLUME_STRING_SIZE 11
 
-extern bool init_volume(int *nfds);
-extern void fill_sndio_pfds(struct pollfd *pfd);
-extern void process_volume_events(struct pollfd *pfd, bool *hdl_open);
-extern void close_volume(void);
+extern pid_t start_volume_process(int *pipe_fd);
 
 /* CPU Temp */
 extern char cputemp_string[14];
blob - 79d1a8a4d4213e3eceb6f2590ccf1ff3f90901df
blob + 4f7843bb78a4141565fd3bba8b1d66807067d887
--- modules/volume.c
+++ modules/volume.c
@@ -1,94 +1,158 @@
+#include <signal.h>
 #include <stdio.h>
+#include <stdlib.h>
 #include <string.h>
 
 #include <poll.h>
+#include <sys/poll.h>
+#include <unistd.h>
 
 #include <sndio.h>
 
 #include "statbar.h"
 
-char volume_string[11];
-
 static struct sioctl_hdl *hdl;
+static volatile sig_atomic_t should_quit = 0;
+static unsigned int ctl_addr = -1;
 
-void
+static void
 onval(void *arg, unsigned int addr, unsigned int val)
 {
-	char vglyph[5];
+	char *vglyph;
 
-	(void)arg;
-	(void)addr;
+	if (ctl_addr != addr) return;
 
 	if (val == 0)
-		(void)strcpy(vglyph, VOLMUTE);
+		vglyph = VOLMUTE;
 	else if (val < 128)
-		(void)strcpy(vglyph, VOLLOW);
+		vglyph = VOLLOW;
 	else
-		(void)strcpy(vglyph, VOL);
+		vglyph = VOL;
 
-	(void)snprintf(volume_string, 11, "%s  %3d%%", vglyph, val * 100 / 255);
+	(void)dprintf(*(int *)arg, "%s  %3d%%", vglyph, val * 100 / 255);
 }
 
-void
+static void
 ondesc(void *arg, struct sioctl_desc *desc, int val)
 {
-	static bool did_init = false;
-	char vglyph[5];
+	char *vglyph;
 
-	(void)arg;
-
 	if (val == 0)
-		(void)strcpy(vglyph, VOLMUTE);
+		vglyph = VOLMUTE;
 	else if (val < 128)
-		(void)strcpy(vglyph, VOLLOW);
+		vglyph = VOLLOW;
 	else
-		(void)strcpy(vglyph, VOL);
+		vglyph = VOL;
 
-	if (!did_init && desc != NULL && strcmp(desc->func, "level") == 0)
+	if (ctl_addr == -1 &&
+		desc != NULL &&
+		strcmp(desc->func, "level") == 0 &&
+		strcmp(desc->node0.name, "output") == 0)
 	{
-		(void)snprintf(volume_string, 11, "%s  %3d%%", vglyph, val * 100 / 255);
-		did_init = true;
+		(void)dprintf(*(int *)arg, "%s  %3d%%", vglyph, val * 100 / 255);
+		ctl_addr = desc->addr;
 	}
 }
 
-bool
-init_volume(int *nfds)
+static int
+init_volume(int *nfds, void *fd)
 {
 	hdl = sioctl_open(SIO_DEVANY, SIOCTL_READ, 0);
 	if (hdl == NULL)
 	{
 		(void)puts("Could not open sndio");
-		(void)strcpy(volume_string, UNKNOWN);
 
-		return false;
+		return -1;
 	}
-	*nfds += sioctl_nfds(hdl);
-	(void)sioctl_ondesc(hdl, ondesc, NULL);
-	(void)sioctl_onval(hdl, onval, NULL);
+	*nfds = sioctl_nfds(hdl);
+	(void)sioctl_ondesc(hdl, ondesc, fd);
+	(void)sioctl_onval(hdl, onval, fd);
 
 	return true;
 }
 
-void
-fill_sndio_pfds(struct pollfd *pfd)
+static void
+signal_handler(int sig)
 {
-	sioctl_pollfd(hdl, pfd, POLLIN);
+	if (sig == SIGTERM || sig == SIGINT) should_quit = 1;
 }
 
-void
-process_volume_events(struct pollfd *pfd, bool *hdl_open)
+pid_t
+start_volume_process(int *pipe_fd)
 {
+	pid_t pid;
+	int vol_pipe[2];
+	int nfds;
+	struct pollfd *pfd;
+
+	if (pipe(vol_pipe) == -1)
+	{
+		perror("pipe");
+
+		return -1;
+	}
+	*pipe_fd = vol_pipe[0];
+
+	pid = fork();
+	if (pid)
+	{
+		if (pid == -1) (void)close(vol_pipe[0]);
+		(void)close(vol_pipe[1]);
+
+		return pid;
+	}
+
+	if (pledge("stdio inet unix rpath", NULL) == -1)
+	{
+		perror("pledge");
+		(void)close(vol_pipe[0]);
+		(void)close(vol_pipe[1]);
+
+		_exit(1);
+	}
+	if (init_volume(&nfds, &vol_pipe[1]) == -1) _exit(1);
+	(void)close(vol_pipe[0]);
+	(void)puts("Volume process started");
+
+	(void)signal(SIGTERM, signal_handler);
+	(void)signal(SIGINT, signal_handler);
+
+	pfd = malloc(nfds * sizeof(struct pollfd));
+	if (pfd == NULL)
+	{
+		perror("malloc");
+
+		_exit(1);
+	}
+	(void)sioctl_pollfd(hdl, pfd, POLLIN);
+
+	if (pledge("stdio", NULL) == -1)
+	{
+		perror("pledge");
+		free(pfd);
+		(void)close(vol_pipe[1]);
+
+		_exit(1);
+	}
+	while(!should_quit)
+	{
+		if (poll(pfd, nfds, INFTIM) > 0)
+		{
 			if (sioctl_revents(hdl, pfd) & POLLHUP)
 			{
 				(void)puts("Lost connection to sndio\n");
-				sioctl_close(hdl);
-				*hdl_open = false;
+
+				break;
 			}
-}
+		}
 
-void
-close_volume(void)
-{
-	sioctl_close(hdl);
+		if (getppid() == 1) break;
+	}
+	(void)puts("Closing volume process");
+	(void)sioctl_close(hdl);
+	free(pfd);
+	(void)close(vol_pipe[1]);
+
+	_exit(0);
 }
 
blob - 780d00cd6185f0ea59de3b2b64c6eb90502fe37a
blob + bb91908b4fbb21965cc9bcb2462655c446c8c6e0
--- src/main.c
+++ src/main.c
@@ -1,6 +1,5 @@
 #include <errno.h>
 #include <stdbool.h>
-#include <stdlib.h>
 #include <stdio.h>
 
 #include <fcntl.h>
@@ -18,6 +17,7 @@
 #include "statbar.h"
 
 #define MAX_STATBAR_LEN 128
+#define NFDS 5
 
 enum clocks_e
 {
@@ -77,14 +77,11 @@ main(int argc, char *argv[])
 	char statbar_text[MAX_STATBAR_LEN];
 	bool dirty = true;
 	int batt_fd;
+	int vol_fd;
 	int weather_pipe[2];
 	pid_t batt_pid;
+	pid_t vol_pid;
 	unsigned char cmd;
-	struct pollfd *cmd_pfd = NULL;
-	struct pollfd *batt_pfd = NULL;
-	struct pollfd *network_pfd = NULL;
-	struct pollfd *weather_pfd = NULL;
-	bool hdl_open = false;
 	bool network_open = false;
 	struct timespec now;
 	struct timespec clocks[CLOCKS_COUNT];
@@ -95,24 +92,21 @@ main(int argc, char *argv[])
 	struct timespec cputemp_interval = { .tv_sec = 2 };
 	struct timespec fanspeed_interval = { .tv_sec = 3 };
 	struct timespec weather_interval = { .tv_sec = 1800 };
-	struct pollfd *pfd;
+	struct pollfd pfd[NFDS];
+	struct pollfd *cmd_pfd = &pfd[0];
+	struct pollfd *batt_pfd = &pfd[1];
+	struct pollfd *vol_pfd = &pfd[2];
+	struct pollfd *network_pfd = &pfd[3];
+	struct pollfd *weather_pfd = &pfd[4];
 	char battery_string[BATTERY_STRING_SIZE];
-	int nfds = 2; /* Start with 2 to guarantee space for the network socket and cmd interface */
+	char volume_string[VOLUME_STRING_SIZE];
 	int i;
+	ssize_t n;
 
 	(void)setvbuf(stdout, NULL, _IOLBF, 0);
-
-	display = XOpenDisplay(NULL);
-	if (display == NULL)
-	{
-		(void)puts("Failed to get display");
-
-		return 1;
-	}
 	install_signal_handlers();
 
 	statbar_text[0] = '\0';
-	root = DefaultRootWindow(display);
 	(void)puts("Welcome to statbar");
 
 	/* Init components */
@@ -123,51 +117,51 @@ main(int argc, char *argv[])
 	timespecadd(&now, &cputemp_interval, &clocks[CPUTEMP_CLOCK]);
 	timespecadd(&now, &fanspeed_interval, &clocks[FANSPEED_CLOCK]);
 	timespecadd(&now, &weather_interval, &clocks[WEATHER_CLOCK]);
-	if (pipe(weather_pipe) != 0)
-	{
-		perror("pipe");
-		weather_loc_valid = false;
-	}
 
 	get_clock();
 	batt_pid = start_privileged_battery_process(&batt_fd, &battery_interval);
-	hdl_open = init_volume(&nfds);
+	vol_pid = start_volume_process(&vol_fd);
 	get_cputemp();
 	get_fanspeed();
 	get_initial_network_state();
-	if (weather_loc_valid) nfds++;
-	if (batt_pid > 0) nfds++;
 
-	pfd = malloc(nfds * sizeof(struct pollfd));
-	if (pfd == NULL)
+	if (pipe(weather_pipe) != 0)
 	{
-		perror("malloc");
-		goto cleanup;
+		perror("pipe");
+		weather_loc_valid = false;
 	}
-	cmd_pfd = &pfd[nfds - 1];
+
 	cmd_pfd->fd = open_command_interface();
 	cmd_pfd->events = POLLIN;
-	network_pfd = &pfd[nfds - 2];
-	network_open = init_network_socket(&network_pfd->fd);
-	network_pfd->events = POLLIN;
+	if (batt_pid > 0)
+	{
+		batt_pfd->fd = batt_fd;
+		batt_pfd->events = POLLIN;
+	}
+	if (vol_pid > 0)
+	{
+		vol_pfd->fd = vol_fd;
+		vol_pfd->events = POLLIN;
+	}
 	if (weather_loc_valid)
 	{
-		weather_pfd = &pfd[nfds - 3];
 		weather_pfd->fd = weather_pipe[0];
 		weather_pfd->events = POLLIN;
 		get_weather(weather_pipe[1]);
 	}
-	if (batt_pid > 0)
-	{
-		batt_pfd = &pfd[nfds - (weather_loc_valid ? 4 : 3)];
-		batt_pfd->fd = batt_fd;
-		batt_pfd->events = POLLIN;
-	}
 	if (mail_path_valid) mail_path_valid = get_mail();
 
-	fill_sndio_pfds(pfd);
-	if (pledge("stdio rpath cpath inet proc exec route audio", NULL) == -1)
+	display = XOpenDisplay(NULL);
+	if (display == NULL)
 	{
+		(void)puts("Failed to get display");
+
+		return -1;
+	}
+	root = DefaultRootWindow(display);
+
+	if (pledge("stdio rpath cpath inet proc exec route", NULL) == -1)
+	{
 		perror("pledge");
 
 		goto cleanup;
@@ -206,10 +200,8 @@ main(int argc, char *argv[])
 			timespecsub(next_event, &now, &next_interval);
 		}
 
-		if (ppoll(pfd, nfds, &next_interval, NULL) > 0)
+		if (ppoll(pfd, NFDS, &next_interval, NULL) > 0)
 		{
-			if (hdl_open)
-				process_volume_events(pfd, &hdl_open);
 			if (cmd_pfd->revents & POLLIN)
 			{
 				(void)read(cmd_pfd->fd, &cmd, 1);
@@ -235,7 +227,15 @@ main(int argc, char *argv[])
 				}
 			}
 			if (batt_pfd->revents & POLLIN)
-				(void)read(batt_pfd->fd, battery_string, BATTERY_STRING_SIZE);
+			{
+				n = read(batt_pfd->fd, battery_string, BATTERY_STRING_SIZE - 1);
+				if (n > 0) battery_string[n] = '\0';
+			}
+			if (vol_pfd->revents & POLLIN)
+			{
+				n = read(vol_pfd->fd, volume_string, VOLUME_STRING_SIZE - 1);
+				if (n > 0) volume_string[n] = '\0';
+			}
 			if (network_pfd->revents & POLLIN)
 				read_network_socket(network_pfd->fd);
 			if (weather_pfd && (weather_pfd->revents & POLLIN))
@@ -298,7 +298,7 @@ main(int argc, char *argv[])
 
 		if (dirty)
 		{
-			(void)snprintf(statbar_text, MAX_STATBAR_LEN, "%s%s| %s | %s | %s | %s | %s | %s",
+			(void)snprintf(statbar_text, MAX_STATBAR_LEN - 1, "%s%s| %s | %s | %s | %s | %s | %s",
 				mail_string,
 				network_string,
 				weather_string,
@@ -307,8 +307,8 @@ main(int argc, char *argv[])
 				volume_string,
 				battery_string,
 				clock_string);
-			XStoreName(display, root, statbar_text);
-			XFlush(display);
+			(void)XStoreName(display, root, statbar_text);
+			(void)XFlush(display);
 			dirty = false;
 		}
 	}
@@ -316,7 +316,7 @@ main(int argc, char *argv[])
 cleanup:
 	(void)puts("Closing statbar");
 	if (batt_pid > 0) (void)kill(batt_pid, SIGTERM); 
-	if (hdl_open) close_volume();
+	if (batt_pid > 0) (void)kill(vol_pid, SIGTERM);
 	if (network_open) (void)close(network_pfd->fd);
 	if (weather_loc_valid) close_weather();
 	if (mail_path_valid) close_mail(); 
@@ -328,7 +328,6 @@ cleanup:
 		(void)close(weather_pipe[1]);
 	}
 	close_command_interface();
-	free(pfd);
 
 	return 0;
 }