slstatus

My fork of https://tools.suckless.org/slstatus/
git clone https://git.inz.fi/slstatus
Log | Files | Refs | README | LICENSE

pipe_command.c (2360B)


      1 /* See LICENSE file for copyright and license details. */
      2 #include <stdio.h>
      3 #include <string.h>
      4 #include <stdlib.h>
      5 #include <unistd.h>
      6 #include <fcntl.h>
      7 #include <errno.h>
      8 
      9 #include "../util.h"
     10 
     11 static struct {
     12 	int fd;
     13 	int len;
     14 	int bused;
     15 	int neednl;
     16 	char last[256];
     17 	char buffer[256];
     18 	const char *cmd;
     19 } *pipes = NULL;
     20 int npipes = 0;
     21 
     22 char *find_last_seg(char *buffer, size_t n, char sep, int *len)
     23 {
     24 	char *i;
     25 	char *pp = NULL;
     26 	char *p = buffer - 1;
     27 
     28 	for (i = buffer; n--; i++) {
     29 		if (*i == sep) {
     30 			pp = p;
     31 			p = i;
     32 		}
     33 	}
     34 
     35 	if (pp) {
     36 		*len = p - pp - 1;
     37 		return pp + 1;
     38 	}
     39 
     40 	*len = -1;
     41 	return NULL;
     42 }
     43 
     44 const char *
     45 pipe_command(const char *cmd)
     46 {
     47 	int i;
     48 
     49 	for (i = 0; i < npipes && pipes[i].cmd != cmd; i++);
     50 	if (i == npipes) {
     51 		int pfd[2];
     52 		pipes = realloc(pipes, sizeof(*pipes) * ++npipes);
     53 		if (pipe(pfd))
     54 			die("failed to open pipe");
     55 		watch(pfd[0]);
     56 
     57 		switch (fork()) {
     58 		case -1:
     59 			die("fork failed");
     60 			break;
     61 		case 0:
     62 			close(pfd[0]);
     63 			close(STDIN_FILENO);
     64 			close(STDOUT_FILENO);
     65 			dup2(pfd[1], STDOUT_FILENO);
     66 			close(pfd[1]);
     67 			open("/dev/null", O_WRONLY);
     68 			execlp("sh", "sh", "-c", cmd, NULL);
     69 			exit(1);
     70 			break;
     71 		default:
     72 			close(pfd[1]);
     73 			fcntl(pfd[0], F_SETFL, O_NONBLOCK);
     74 			pipes[i].fd = pfd[0];
     75 			pipes[i].bused = 0;
     76 			pipes[i].len = 0;
     77 			pipes[i].cmd = cmd;
     78 			pipes[i].neednl = 0;
     79 			break;
     80 		}
     81 		npipes++;
     82 	}
     83 
     84 	int fd = pipes[i].fd;
     85 	int r;
     86 	char *nnl;
     87 	int len;
     88 
     89 	r = read(fd, pipes[i].buffer + pipes[i].bused,
     90 		 sizeof(pipes[i].buffer) - pipes[i].bused);
     91 
     92 	if (r == 0)
     93 		die("pipe source died");
     94 	if (r < 0) {
     95 		if (errno == EWOULDBLOCK || errno == EAGAIN)
     96 			r = 0;
     97 		else
     98 			die("pipe error:");
     99 	}
    100 
    101 	nnl = find_last_seg(pipes[i].buffer, r, '\n', &len);
    102 
    103 	if (nnl) {
    104 		if (!pipes[i].neednl || nnl != pipes[i].buffer) {
    105 			memcpy(pipes[i].last, nnl, len);
    106 			pipes[i].len = len;
    107 		}
    108 		pipes[i].neednl = 0;
    109 		pipes[i].bused = r - (nnl + len + 1 - pipes[i].buffer);
    110 		memmove(pipes[i].buffer, nnl + len + 1, pipes[i].bused);
    111 	} else if (!pipes[i].neednl) {
    112 		pipes[i].bused += r;
    113 
    114 		if (pipes[i].bused == sizeof(pipes[i].buffer)) {
    115 			pipes[i].len = pipes[i].bused;
    116 			memcpy(pipes[i].last, pipes[i].buffer,
    117 			       pipes[i].bused);
    118 			pipes[i].bused = 0;
    119 			pipes[i].neednl = 1;
    120 		}
    121 	}
    122 
    123 	if (pipes[i].len == 0)
    124 		return NULL;
    125 	return bprintf("%.*s", pipes[i].len, pipes[i].last);
    126 }