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 for (argc = 0; src[argc]; argc++)
101 if (!argv_append(dst, src[argc]))
102 return FALSE;
103 return TRUE;
104 }
107 /*
108 * Executing external commands.
109 */
111 static void
112 io_init(struct io *io)
113 {
114 memset(io, 0, sizeof(*io));
115 io->pipe = -1;
116 }
118 bool
119 io_open(struct io *io, const char *fmt, ...)
120 {
121 char name[SIZEOF_STR] = "";
122 bool fits;
123 va_list args;
125 io_init(io);
127 va_start(args, fmt);
128 fits = vsnprintf(name, sizeof(name), fmt, args) < sizeof(name);
129 va_end(args);
131 if (!fits) {
132 io->error = ENAMETOOLONG;
133 return FALSE;
134 }
135 io->pipe = *name ? open(name, O_RDONLY) : STDIN_FILENO;
136 if (io->pipe == -1)
137 io->error = errno;
138 return io->pipe != -1;
139 }
141 bool
142 io_kill(struct io *io)
143 {
144 return io->pid == 0 || kill(io->pid, SIGKILL) != -1;
145 }
147 bool
148 io_done(struct io *io)
149 {
150 pid_t pid = io->pid;
152 if (io->pipe != -1)
153 close(io->pipe);
154 free(io->buf);
155 io_init(io);
157 while (pid > 0) {
158 int status;
159 pid_t waiting = waitpid(pid, &status, 0);
161 if (waiting < 0) {
162 if (errno == EINTR)
163 continue;
164 io->error = errno;
165 return FALSE;
166 }
168 return waiting == pid &&
169 !WIFSIGNALED(status) &&
170 WIFEXITED(status) &&
171 !WEXITSTATUS(status);
172 }
174 return TRUE;
175 }
177 bool
178 io_run(struct io *io, enum io_type type, const char *dir, const char *argv[], ...)
179 {
180 int pipefds[2] = { -1, -1 };
181 va_list args;
183 io_init(io);
185 if ((type == IO_RD || type == IO_WR) && pipe(pipefds) < 0) {
186 io->error = errno;
187 return FALSE;
188 } else if (type == IO_AP) {
189 va_start(args, argv);
190 pipefds[1] = va_arg(args, int);
191 va_end(args);
192 }
194 if ((io->pid = fork())) {
195 if (io->pid == -1)
196 io->error = errno;
197 if (pipefds[!(type == IO_WR)] != -1)
198 close(pipefds[!(type == IO_WR)]);
199 if (io->pid != -1) {
200 io->pipe = pipefds[!!(type == IO_WR)];
201 return TRUE;
202 }
204 } else {
205 if (type != IO_FG) {
206 int devnull = open("/dev/null", O_RDWR);
207 int readfd = type == IO_WR ? pipefds[0] : devnull;
208 int writefd = (type == IO_RD || type == IO_AP)
209 ? pipefds[1] : devnull;
211 dup2(readfd, STDIN_FILENO);
212 dup2(writefd, STDOUT_FILENO);
213 dup2(devnull, STDERR_FILENO);
215 close(devnull);
216 if (pipefds[0] != -1)
217 close(pipefds[0]);
218 if (pipefds[1] != -1)
219 close(pipefds[1]);
220 }
222 if (dir && *dir && chdir(dir) == -1)
223 exit(errno);
225 execvp(argv[0], (char *const*) argv);
226 exit(errno);
227 }
229 if (pipefds[!!(type == IO_WR)] != -1)
230 close(pipefds[!!(type == IO_WR)]);
231 return FALSE;
232 }
234 bool
235 io_complete(enum io_type type, const char **argv, const char *dir, int fd)
236 {
237 struct io io;
239 return io_run(&io, type, dir, argv, fd) && io_done(&io);
240 }
242 bool
243 io_run_bg(const char **argv)
244 {
245 return io_complete(IO_BG, argv, NULL, -1);
246 }
248 bool
249 io_run_fg(const char **argv, const char *dir)
250 {
251 return io_complete(IO_FG, argv, dir, -1);
252 }
254 bool
255 io_run_append(const char **argv, int fd)
256 {
257 return io_complete(IO_AP, argv, NULL, fd);
258 }
260 bool
261 io_eof(struct io *io)
262 {
263 return io->eof;
264 }
266 int
267 io_error(struct io *io)
268 {
269 return io->error;
270 }
272 char *
273 io_strerror(struct io *io)
274 {
275 return strerror(io->error);
276 }
278 bool
279 io_can_read(struct io *io, bool can_block)
280 {
281 struct timeval tv = { 0, 500 };
282 fd_set fds;
284 FD_ZERO(&fds);
285 FD_SET(io->pipe, &fds);
287 return select(io->pipe + 1, &fds, NULL, NULL, can_block ? NULL : &tv) > 0;
288 }
290 ssize_t
291 io_read(struct io *io, void *buf, size_t bufsize)
292 {
293 do {
294 ssize_t readsize = read(io->pipe, buf, bufsize);
296 if (readsize < 0 && (errno == EAGAIN || errno == EINTR))
297 continue;
298 else if (readsize == -1)
299 io->error = errno;
300 else if (readsize == 0)
301 io->eof = 1;
302 return readsize;
303 } while (1);
304 }
306 DEFINE_ALLOCATOR(io_realloc_buf, char, BUFSIZ)
308 char *
309 io_get(struct io *io, int c, bool can_read)
310 {
311 char *eol;
312 ssize_t readsize;
314 while (TRUE) {
315 if (io->bufsize > 0) {
316 eol = memchr(io->bufpos, c, io->bufsize);
317 if (eol) {
318 char *line = io->bufpos;
320 *eol = 0;
321 io->bufpos = eol + 1;
322 io->bufsize -= io->bufpos - line;
323 return line;
324 }
325 }
327 if (io_eof(io)) {
328 if (io->bufsize) {
329 io->bufpos[io->bufsize] = 0;
330 io->bufsize = 0;
331 return io->bufpos;
332 }
333 return NULL;
334 }
336 if (!can_read)
337 return NULL;
339 if (io->bufsize > 0 && io->bufpos > io->buf)
340 memmove(io->buf, io->bufpos, io->bufsize);
342 if (io->bufalloc == io->bufsize) {
343 if (!io_realloc_buf(&io->buf, io->bufalloc, BUFSIZ))
344 return NULL;
345 io->bufalloc += BUFSIZ;
346 }
348 io->bufpos = io->buf;
349 readsize = io_read(io, io->buf + io->bufsize, io->bufalloc - io->bufsize);
350 if (io_error(io))
351 return NULL;
352 io->bufsize += readsize;
353 }
354 }
356 bool
357 io_write(struct io *io, const void *buf, size_t bufsize)
358 {
359 size_t written = 0;
361 while (!io_error(io) && written < bufsize) {
362 ssize_t size;
364 size = write(io->pipe, buf + written, bufsize - written);
365 if (size < 0 && (errno == EAGAIN || errno == EINTR))
366 continue;
367 else if (size == -1)
368 io->error = errno;
369 else
370 written += size;
371 }
373 return written == bufsize;
374 }
376 bool
377 io_read_buf(struct io *io, char buf[], size_t bufsize)
378 {
379 char *result = io_get(io, '\n', TRUE);
381 if (result) {
382 result = chomp_string(result);
383 string_ncopy_do(buf, bufsize, result, strlen(result));
384 }
386 return io_done(io) && result;
387 }
389 bool
390 io_run_buf(const char **argv, char buf[], size_t bufsize)
391 {
392 struct io io;
394 return io_run(&io, IO_RD, NULL, argv) && io_read_buf(&io, buf, bufsize);
395 }
397 int
398 io_load(struct io *io, const char *separators,
399 io_read_fn read_property, void *data)
400 {
401 char *name;
402 int state = OK;
404 while (state == OK && (name = io_get(io, '\n', TRUE))) {
405 char *value;
406 size_t namelen;
407 size_t valuelen;
409 name = chomp_string(name);
410 namelen = strcspn(name, separators);
412 if (name[namelen]) {
413 name[namelen] = 0;
414 value = chomp_string(name + namelen + 1);
415 valuelen = strlen(value);
417 } else {
418 value = "";
419 valuelen = 0;
420 }
422 state = read_property(name, namelen, value, valuelen, data);
423 }
425 if (state != ERR && io_error(io))
426 state = ERR;
427 io_done(io);
429 return state;
430 }
432 int
433 io_run_load(const char **argv, const char *separators,
434 io_read_fn read_property, void *data)
435 {
436 struct io io;
438 if (!io_run(&io, IO_RD, NULL, argv))
439 return ERR;
440 return io_load(&io, separators, read_property, data);
441 }