1 /* Copyright (c) 2006-2010 Jonas Fonseca <fonseca@diku.dk>
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.
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.
18 get_arg_valuelen(const char *arg
, bool *quoted
)
20 if (*arg
== '"' || *arg
== '\'') {
21 const char *end
= *arg
== '"' ? "\"" : "'";
22 int valuelen
= strcspn(arg
+ 1, end
);
26 return valuelen
> 0 ? valuelen
+ 2 : strlen(arg
);
28 return strcspn(arg
, " \t");
33 split_argv_string(const char *argv
[SIZEOF_ARG
], int *argc
, char *cmd
, bool remove_quotes
)
35 while (*cmd
&& *argc
< SIZEOF_ARG
) {
37 int valuelen
= get_arg_valuelen(cmd
, "ed
);
38 bool advance
= cmd
[valuelen
] != 0;
39 int quote_offset
= !!(quoted
&& remove_quotes
);
41 cmd
[valuelen
- quote_offset
] = 0;
42 argv
[(*argc
)++] = chomp_string(cmd
+ quote_offset
);
43 cmd
= chomp_string(cmd
+ valuelen
+ advance
);
46 if (*argc
< SIZEOF_ARG
)
48 return *argc
< SIZEOF_ARG
;
52 argv_from_string_no_quotes(const char *argv
[SIZEOF_ARG
], int *argc
, char *cmd
)
54 return split_argv_string(argv
, argc
, cmd
, TRUE
);
58 argv_from_string(const char *argv
[SIZEOF_ARG
], int *argc
, char *cmd
)
60 return split_argv_string(argv
, argc
, cmd
, FALSE
);
64 argv_from_env(const char **argv
, const char *name
)
66 char *env
= argv
? getenv(name
) : NULL
;
71 return !env
|| argv_from_string(argv
, &argc
, env
);
75 argv_free(const char *argv
[])
81 for (argc
= 0; argv
[argc
]; argc
++)
82 free((void *) argv
[argc
]);
87 argv_size(const char **argv
)
91 while (argv
&& argv
[argc
])
97 DEFINE_ALLOCATOR(argv_realloc
, const char *, SIZEOF_ARG
)
100 argv_append(const char ***argv
, const char *arg
)
102 size_t argc
= argv_size(*argv
);
104 if (!*arg
&& argc
> 0)
107 if (!argv_realloc(argv
, argc
, 2))
110 (*argv
)[argc
++] = strdup(arg
);
111 (*argv
)[argc
] = NULL
;
116 argv_append_array(const char ***dst_argv
, const char *src_argv
[])
120 for (i
= 0; src_argv
&& src_argv
[i
]; i
++)
121 if (!argv_append(dst_argv
, src_argv
[i
]))
127 argv_copy(const char ***dst
, const char *src
[])
132 for (argc
= 0; src
[argc
]; argc
++)
133 if (!argv_append(dst
, src
[argc
]))
140 * Executing external commands.
144 io_init(struct io
*io
)
146 memset(io
, 0, sizeof(*io
));
151 io_open(struct io
*io
, const char *fmt
, ...)
153 char name
[SIZEOF_STR
] = "";
158 FORMAT_BUFFER(name
, sizeof(name
), fmt
, retval
);
160 io
->error
= ENAMETOOLONG
;
164 io
->pipe
= *name
? open(name
, O_RDONLY
) : dup(STDIN_FILENO
);
167 return io
->pipe
!= -1;
171 io_kill(struct io
*io
)
173 return io
->pid
== 0 || kill(io
->pid
, SIGKILL
) != -1;
177 io_done(struct io
*io
)
188 pid_t waiting
= waitpid(pid
, &status
, 0);
197 return waiting
== pid
&&
198 !WIFSIGNALED(status
) &&
200 !WEXITSTATUS(status
);
207 io_run(struct io
*io
, enum io_type type
, const char *dir
, const char *argv
[], ...)
209 int pipefds
[2] = { -1, -1 };
214 if (dir
&& !strcmp(dir
, argv
[0]))
215 return io_open(io
, "%s%s", dir
, argv
[1]);
217 if ((type
== IO_RD
|| type
== IO_WR
) && pipe(pipefds
) < 0) {
220 } else if (type
== IO_AP
) {
221 va_start(args
, argv
);
222 pipefds
[1] = va_arg(args
, int);
226 if ((io
->pid
= fork())) {
229 if (pipefds
[!(type
== IO_WR
)] != -1)
230 close(pipefds
[!(type
== IO_WR
)]);
232 io
->pipe
= pipefds
[!!(type
== IO_WR
)];
238 int devnull
= open("/dev/null", O_RDWR
);
239 int readfd
= type
== IO_WR
? pipefds
[0] : devnull
;
240 int writefd
= (type
== IO_RD
|| type
== IO_AP
)
241 ? pipefds
[1] : devnull
;
243 dup2(readfd
, STDIN_FILENO
);
244 dup2(writefd
, STDOUT_FILENO
);
245 dup2(devnull
, STDERR_FILENO
);
248 if (pipefds
[0] != -1)
250 if (pipefds
[1] != -1)
254 if (dir
&& *dir
&& chdir(dir
) == -1)
257 execvp(argv
[0], (char *const*) argv
);
261 if (pipefds
[!!(type
== IO_WR
)] != -1)
262 close(pipefds
[!!(type
== IO_WR
)]);
267 io_complete(enum io_type type
, const char **argv
, const char *dir
, int fd
)
271 return io_run(&io
, type
, dir
, argv
, fd
) && io_done(&io
);
275 io_run_bg(const char **argv
)
277 return io_complete(IO_BG
, argv
, NULL
, -1);
281 io_run_fg(const char **argv
, const char *dir
)
283 return io_complete(IO_FG
, argv
, dir
, -1);
287 io_run_append(const char **argv
, int fd
)
289 return io_complete(IO_AP
, argv
, NULL
, fd
);
293 io_eof(struct io
*io
)
299 io_error(struct io
*io
)
305 io_strerror(struct io
*io
)
307 return strerror(io
->error
);
311 io_can_read(struct io
*io
, bool can_block
)
313 struct timeval tv
= { 0, 500 };
317 FD_SET(io
->pipe
, &fds
);
319 return select(io
->pipe
+ 1, &fds
, NULL
, NULL
, can_block
? NULL
: &tv
) > 0;
323 io_read(struct io
*io
, void *buf
, size_t bufsize
)
326 ssize_t readsize
= read(io
->pipe
, buf
, bufsize
);
328 if (readsize
< 0 && (errno
== EAGAIN
|| errno
== EINTR
))
330 else if (readsize
== -1)
332 else if (readsize
== 0)
338 DEFINE_ALLOCATOR(io_realloc_buf
, char, BUFSIZ
)
341 io_get(struct io
*io
, int c
, bool can_read
)
347 if (io
->bufsize
> 0) {
348 eol
= memchr(io
->bufpos
, c
, io
->bufsize
);
350 char *line
= io
->bufpos
;
353 io
->bufpos
= eol
+ 1;
354 io
->bufsize
-= io
->bufpos
- line
;
361 io
->bufpos
[io
->bufsize
] = 0;
371 if (io
->bufsize
> 0 && io
->bufpos
> io
->buf
)
372 memmove(io
->buf
, io
->bufpos
, io
->bufsize
);
374 if (io
->bufalloc
== io
->bufsize
) {
375 if (!io_realloc_buf(&io
->buf
, io
->bufalloc
, BUFSIZ
))
377 io
->bufalloc
+= BUFSIZ
;
380 io
->bufpos
= io
->buf
;
381 readsize
= io_read(io
, io
->buf
+ io
->bufsize
, io
->bufalloc
- io
->bufsize
);
384 io
->bufsize
+= readsize
;
389 io_write(struct io
*io
, const void *buf
, size_t bufsize
)
393 while (!io_error(io
) && written
< bufsize
) {
396 size
= write(io
->pipe
, buf
+ written
, bufsize
- written
);
397 if (size
< 0 && (errno
== EAGAIN
|| errno
== EINTR
))
405 return written
== bufsize
;
409 io_printf(struct io
*io
, const char *fmt
, ...)
411 char buf
[SIZEOF_STR
] = "";
414 FORMAT_BUFFER(buf
, sizeof(buf
), fmt
, retval
);
416 io
->error
= ENAMETOOLONG
;
420 return io_write(io
, buf
, retval
);
424 io_read_buf(struct io
*io
, char buf
[], size_t bufsize
)
426 char *result
= io_get(io
, '\n', TRUE
);
429 result
= chomp_string(result
);
430 string_ncopy_do(buf
, bufsize
, result
, strlen(result
));
433 return io_done(io
) && result
;
437 io_run_buf(const char **argv
, char buf
[], size_t bufsize
)
441 return io_run(&io
, IO_RD
, NULL
, argv
) && io_read_buf(&io
, buf
, bufsize
);
445 io_load(struct io
*io
, const char *separators
,
446 io_read_fn read_property
, void *data
)
451 while (state
== OK
&& (name
= io_get(io
, '\n', TRUE
))) {
456 name
= chomp_string(name
);
457 namelen
= strcspn(name
, separators
);
461 value
= chomp_string(name
+ namelen
+ 1);
462 valuelen
= strlen(value
);
469 state
= read_property(name
, namelen
, value
, valuelen
, data
);
472 if (state
!= ERR
&& io_error(io
))
480 io_run_load(const char **argv
, const char *separators
,
481 io_read_fn read_property
, void *data
)
485 if (!io_run(&io
, IO_RD
, NULL
, argv
))
487 return io_load(&io
, separators
, read_property
, data
);