1 /* Copyright (c) 2006-2010 Jonas Fonseca <fonseca@diku.dk>
2 *
3 * This program is free software; you can redistribute it and/or
4 * modify it under the terms of the GNU General Public License as
5 * published by the Free Software Foundation; either version 2 of
6 * the License, or (at your option) any later version.
7 *
8 * This program is distributed in the hope that it will be useful,
9 * but WITHOUT ANY WARRANTY; without even the implied warranty of
10 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
11 * GNU General Public License for more details.
12 */
14 #include "tig.h"
15 #include "io.h"
17 bool
18 argv_from_string(const char *argv[SIZEOF_ARG], int *argc, char *cmd)
19 {
20 int valuelen;
22 while (*cmd && *argc < SIZEOF_ARG && (valuelen = strcspn(cmd, " \t"))) {
23 bool advance = cmd[valuelen] != 0;
25 cmd[valuelen] = 0;
26 argv[(*argc)++] = chomp_string(cmd);
27 cmd = chomp_string(cmd + valuelen + advance);
28 }
30 if (*argc < SIZEOF_ARG)
31 argv[*argc] = NULL;
32 return *argc < SIZEOF_ARG;
33 }
35 bool
36 argv_from_env(const char **argv, const char *name)
37 {
38 char *env = argv ? getenv(name) : NULL;
39 int argc = 0;
41 if (env && *env)
42 env = strdup(env);
43 return !env || argv_from_string(argv, &argc, env);
44 }
46 void
47 argv_free(const char *argv[])
48 {
49 int argc;
51 if (!argv)
52 return;
53 for (argc = 0; argv[argc]; argc++)
54 free((void *) argv[argc]);
55 argv[0] = NULL;
56 }
58 size_t
59 argv_size(const char **argv)
60 {
61 int argc = 0;
63 while (argv && argv[argc])
64 argc++;
66 return argc;
67 }
69 DEFINE_ALLOCATOR(argv_realloc, const char *, SIZEOF_ARG)
71 bool
72 argv_append(const char ***argv, const char *arg)
73 {
74 size_t argc = argv_size(*argv);
76 if (!argv_realloc(argv, argc, 2))
77 return FALSE;
79 (*argv)[argc++] = strdup(arg);
80 (*argv)[argc] = NULL;
81 return TRUE;
82 }
84 bool
85 argv_append_array(const char ***dst_argv, const char *src_argv[])
86 {
87 int i;
89 for (i = 0; src_argv && src_argv[i]; i++)
90 if (!argv_append(dst_argv, src_argv[i]))
91 return FALSE;
92 return TRUE;
93 }
95 bool
96 argv_copy(const char ***dst, const char *src[])
97 {
98 int argc;
100 argv_free(*dst);
101 for (argc = 0; src[argc]; argc++)
102 if (!argv_append(dst, src[argc]))
103 return FALSE;
104 return TRUE;
105 }
108 /*
109 * Executing external commands.
110 */
112 static void
113 io_init(struct io *io)
114 {
115 memset(io, 0, sizeof(*io));
116 io->pipe = -1;
117 }
119 bool
120 io_open(struct io *io, const char *fmt, ...)
121 {
122 char name[SIZEOF_STR] = "";
123 bool fits;
124 va_list args;
126 io_init(io);
128 va_start(args, fmt);
129 fits = vsnprintf(name, sizeof(name), fmt, args) < sizeof(name);
130 va_end(args);
132 if (!fits) {
133 io->error = ENAMETOOLONG;
134 return FALSE;
135 }
136 io->pipe = *name ? open(name, O_RDONLY) : STDIN_FILENO;
137 if (io->pipe == -1)
138 io->error = errno;
139 return io->pipe != -1;
140 }
142 bool
143 io_kill(struct io *io)
144 {
145 return io->pid == 0 || kill(io->pid, SIGKILL) != -1;
146 }
148 bool
149 io_done(struct io *io)
150 {
151 pid_t pid = io->pid;
153 if (io->pipe != -1)
154 close(io->pipe);
155 free(io->buf);
156 io_init(io);
158 while (pid > 0) {
159 int status;
160 pid_t waiting = waitpid(pid, &status, 0);
162 if (waiting < 0) {
163 if (errno == EINTR)
164 continue;
165 io->error = errno;
166 return FALSE;
167 }
169 return waiting == pid &&
170 !WIFSIGNALED(status) &&
171 WIFEXITED(status) &&
172 !WEXITSTATUS(status);
173 }
175 return TRUE;
176 }
178 bool
179 io_run(struct io *io, enum io_type type, const char *dir, const char *argv[], ...)
180 {
181 int pipefds[2] = { -1, -1 };
182 va_list args;
184 io_init(io);
186 if ((type == IO_RD || type == IO_WR) && pipe(pipefds) < 0) {
187 io->error = errno;
188 return FALSE;
189 } else if (type == IO_AP) {
190 va_start(args, argv);
191 pipefds[1] = va_arg(args, int);
192 va_end(args);
193 }
195 if ((io->pid = fork())) {
196 if (io->pid == -1)
197 io->error = errno;
198 if (pipefds[!(type == IO_WR)] != -1)
199 close(pipefds[!(type == IO_WR)]);
200 if (io->pid != -1) {
201 io->pipe = pipefds[!!(type == IO_WR)];
202 return TRUE;
203 }
205 } else {
206 if (type != IO_FG) {
207 int devnull = open("/dev/null", O_RDWR);
208 int readfd = type == IO_WR ? pipefds[0] : devnull;
209 int writefd = (type == IO_RD || type == IO_AP)
210 ? pipefds[1] : devnull;
212 dup2(readfd, STDIN_FILENO);
213 dup2(writefd, STDOUT_FILENO);
214 dup2(devnull, STDERR_FILENO);
216 close(devnull);
217 if (pipefds[0] != -1)
218 close(pipefds[0]);
219 if (pipefds[1] != -1)
220 close(pipefds[1]);
221 }
223 if (dir && *dir && chdir(dir) == -1)
224 exit(errno);
226 execvp(argv[0], (char *const*) argv);
227 exit(errno);
228 }
230 if (pipefds[!!(type == IO_WR)] != -1)
231 close(pipefds[!!(type == IO_WR)]);
232 return FALSE;
233 }
235 bool
236 io_complete(enum io_type type, const char **argv, const char *dir, int fd)
237 {
238 struct io io;
240 return io_run(&io, type, dir, argv, fd) && io_done(&io);
241 }
243 bool
244 io_run_bg(const char **argv)
245 {
246 return io_complete(IO_BG, argv, NULL, -1);
247 }
249 bool
250 io_run_fg(const char **argv, const char *dir)
251 {
252 return io_complete(IO_FG, argv, dir, -1);
253 }
255 bool
256 io_run_append(const char **argv, int fd)
257 {
258 return io_complete(IO_AP, argv, NULL, fd);
259 }
261 bool
262 io_eof(struct io *io)
263 {
264 return io->eof;
265 }
267 int
268 io_error(struct io *io)
269 {
270 return io->error;
271 }
273 char *
274 io_strerror(struct io *io)
275 {
276 return strerror(io->error);
277 }
279 bool
280 io_can_read(struct io *io, bool can_block)
281 {
282 struct timeval tv = { 0, 500 };
283 fd_set fds;
285 FD_ZERO(&fds);
286 FD_SET(io->pipe, &fds);
288 return select(io->pipe + 1, &fds, NULL, NULL, can_block ? NULL : &tv) > 0;
289 }
291 ssize_t
292 io_read(struct io *io, void *buf, size_t bufsize)
293 {
294 do {
295 ssize_t readsize = read(io->pipe, buf, bufsize);
297 if (readsize < 0 && (errno == EAGAIN || errno == EINTR))
298 continue;
299 else if (readsize == -1)
300 io->error = errno;
301 else if (readsize == 0)
302 io->eof = 1;
303 return readsize;
304 } while (1);
305 }
307 DEFINE_ALLOCATOR(io_realloc_buf, char, BUFSIZ)
309 char *
310 io_get(struct io *io, int c, bool can_read)
311 {
312 char *eol;
313 ssize_t readsize;
315 while (TRUE) {
316 if (io->bufsize > 0) {
317 eol = memchr(io->bufpos, c, io->bufsize);
318 if (eol) {
319 char *line = io->bufpos;
321 *eol = 0;
322 io->bufpos = eol + 1;
323 io->bufsize -= io->bufpos - line;
324 return line;
325 }
326 }
328 if (io_eof(io)) {
329 if (io->bufsize) {
330 io->bufpos[io->bufsize] = 0;
331 io->bufsize = 0;
332 return io->bufpos;
333 }
334 return NULL;
335 }
337 if (!can_read)
338 return NULL;
340 if (io->bufsize > 0 && io->bufpos > io->buf)
341 memmove(io->buf, io->bufpos, io->bufsize);
343 if (io->bufalloc == io->bufsize) {
344 if (!io_realloc_buf(&io->buf, io->bufalloc, BUFSIZ))
345 return NULL;
346 io->bufalloc += BUFSIZ;
347 }
349 io->bufpos = io->buf;
350 readsize = io_read(io, io->buf + io->bufsize, io->bufalloc - io->bufsize);
351 if (io_error(io))
352 return NULL;
353 io->bufsize += readsize;
354 }
355 }
357 bool
358 io_write(struct io *io, const void *buf, size_t bufsize)
359 {
360 size_t written = 0;
362 while (!io_error(io) && written < bufsize) {
363 ssize_t size;
365 size = write(io->pipe, buf + written, bufsize - written);
366 if (size < 0 && (errno == EAGAIN || errno == EINTR))
367 continue;
368 else if (size == -1)
369 io->error = errno;
370 else
371 written += size;
372 }
374 return written == bufsize;
375 }
377 bool
378 io_read_buf(struct io *io, char buf[], size_t bufsize)
379 {
380 char *result = io_get(io, '\n', TRUE);
382 if (result) {
383 result = chomp_string(result);
384 string_ncopy_do(buf, bufsize, result, strlen(result));
385 }
387 return io_done(io) && result;
388 }
390 bool
391 io_run_buf(const char **argv, char buf[], size_t bufsize)
392 {
393 struct io io;
395 return io_run(&io, IO_RD, NULL, argv) && io_read_buf(&io, buf, bufsize);
396 }
398 int
399 io_load(struct io *io, const char *separators,
400 io_read_fn read_property, void *data)
401 {
402 char *name;
403 int state = OK;
405 while (state == OK && (name = io_get(io, '\n', TRUE))) {
406 char *value;
407 size_t namelen;
408 size_t valuelen;
410 name = chomp_string(name);
411 namelen = strcspn(name, separators);
413 if (name[namelen]) {
414 name[namelen] = 0;
415 value = chomp_string(name + namelen + 1);
416 valuelen = strlen(value);
418 } else {
419 value = "";
420 valuelen = 0;
421 }
423 state = read_property(name, namelen, value, valuelen, data);
424 }
426 if (state != ERR && io_error(io))
427 state = ERR;
428 io_done(io);
430 return state;
431 }
433 int
434 io_run_load(const char **argv, const char *separators,
435 io_read_fn read_property, void *data)
436 {
437 struct io io;
439 if (!io_run(&io, IO_RD, NULL, argv))
440 return ERR;
441 return io_load(&io, separators, read_property, data);
442 }