]> git.sur5r.net Git - i3/i3/blob - i3bar/src/child.c
Be more strict with encapsulation
[i3/i3] / i3bar / src / child.c
1 #include <stdlib.h>
2 #include <unistd.h>
3 #include <sys/types.h>
4 #include <signal.h>
5 #include <stdio.h>
6 #include <fcntl.h>
7 #include <string.h>
8 #include <errno.h>
9 #include <ev.h>
10
11 #include "common.h"
12
13 ev_io    *child_io;
14 ev_child *child_sig;
15
16 void cleanup() {
17     ev_io_stop(main_loop, child_io);
18     ev_child_stop(main_loop, child_sig);
19     FREE(child_io);
20     FREE(child_sig);
21     FREE(statusline);
22 }
23
24 void strip_dzen_formats(char *buffer) {
25     char *src = buffer;
26     char *dest = buffer;
27     while (*src != '\0') {
28         if (*src == '^') {
29             if (!strncmp(src, "^ro", strlen("^ro"))) {
30                 *(dest++) = ' ';
31                 *(dest++) = '|';
32                 *(dest++) = ' ';
33             }
34             while (*src != ')') {
35                 src++;
36             }
37             src++;
38         } else {
39             *dest = *src;
40             src++;
41             dest++;
42         }
43     }
44     *(--dest) = '\0';
45 }
46
47 void child_io_cb(struct ev_loop *loop, ev_io *watcher, int revents) {
48     int fd = watcher->fd;
49     int n = 0;
50     int rec = 0;
51     int buffer_len = STDIN_CHUNK_SIZE;
52     char *buffer = malloc(buffer_len);
53     memset(buffer, '\0', buffer_len);
54     while(1) {
55         n = read(fd, buffer + rec, buffer_len - rec);
56         if (n == -1) {
57             if (errno == EAGAIN) {
58                 break;
59             }
60             printf("ERROR: read() failed!");
61             exit(EXIT_FAILURE);
62         }
63         if (n == 0) {
64             if (rec == buffer_len) {
65                 char *tmp = buffer;
66                 buffer = malloc(buffer_len + STDIN_CHUNK_SIZE);
67                 memset(buffer, '\0', buffer_len);
68                 strncpy(buffer, tmp, buffer_len);
69                 buffer_len += STDIN_CHUNK_SIZE;
70                 FREE(tmp);
71             } else {
72                 break;
73             }
74         }
75         rec += n;
76     }
77     if (strlen(buffer) == 0) {
78         FREE(buffer);
79         return;
80     }
81     strip_dzen_formats(buffer);
82     FREE(statusline);
83     statusline = buffer;
84     printf("%s", buffer);
85     draw_bars();
86 }
87
88 void child_sig_cb(struct ev_loop *loop, ev_child *watcher, int revents) {
89     printf("Child (pid: %d) unexpectedly exited with status %d\n", child_pid, watcher->rstatus);
90     cleanup();
91 }
92
93 void start_child(char *command) {
94     int fd[2];
95     pipe(fd);
96     child_pid = fork();
97     switch (child_pid) {
98         case -1:
99             printf("ERROR: Couldn't fork()");
100             exit(EXIT_FAILURE);
101         case 0:
102             close(fd[0]);
103
104             dup2(fd[1], STDOUT_FILENO);
105
106             static const char *shell = NULL;
107
108             if ((shell = getenv("SHELL")) == NULL)
109                 shell = "/bin/sh";
110
111             execl(shell, shell, "-c", command, (char*) NULL);
112             break;
113         default:
114             close(fd[1]);
115
116             dup2(fd[0], STDIN_FILENO);
117             fcntl(STDIN_FILENO, F_SETFL, O_NONBLOCK);
118
119             child_io = malloc(sizeof(ev_io));
120             ev_io_init(child_io, &child_io_cb, STDIN_FILENO, EV_READ);
121             ev_io_start(main_loop, child_io);
122
123             /* We must cleanup, if the child unexpectedly terminates */
124             child_sig = malloc(sizeof(ev_io));
125             ev_child_init(child_sig, &child_sig_cb, child_pid, 0);
126             ev_child_start(main_loop, child_sig);
127
128             break;
129     }
130 }
131
132 void kill_child() {
133     kill(child_pid, SIGQUIT);
134     cleanup();
135 }