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 }