4 * Copyright (c) Tuomo Valkonen 1999-2007.
6 * Ion is free software; you can redistribute it and/or modify it under
7 * the terms of the GNU Lesser General Public License as published by
8 * the Free Software Foundation; either version 2.1 of the License, or
9 * (at your option) any later version.
13 #include <sys/types.h>
14 #include <sys/signal.h>
24 #include <libtu/output.h>
25 #include <libtu/misc.h>
26 #include <libtu/locale.h>
27 #include <libtu/types.h>
33 /*{{{ Exec/spawn/fork */
35 #define SHELL_PATH "/bin/sh"
36 #define SHELL_NAME "sh"
37 #define SHELL_ARG "-c"
40 void mainloop_do_exec(const char *cmd)
46 argv[2]=(char*)cmd; /* stupid execve... */
48 execvp(SHELL_PATH, argv);
52 static int mypipe(int *fds)
56 cloexec_braindamage_fix(fds[0]);
57 cloexec_braindamage_fix(fds[1]);
59 warn_err_obj("pipe()");
65 static bool unblock(int fd)
67 int fl=fcntl(fd, F_GETFL);
69 fl=fcntl(fd, F_SETFL, fl|O_NONBLOCK);
74 static void duppipe(int fd, int idx, int *fds)
83 pid_t mainloop_fork(void (*fn)(void *p), void *fnp,
84 int *infd, int *outfd, int *errfd)
102 if(mypipe(errfds)!=0)
114 if(!unblock(outfds[0]))
121 if(!unblock(errfds[0]))
136 duppipe(0, 0, infds);
138 duppipe(1, 1, outfds);
140 duppipe(2, 1, errfds);
168 void (*initenv)(void *p);
173 static void do_spawn(void *spawnp)
175 SpawnP *p=(SpawnP*)spawnp;
178 p->initenv(p->initenvp);
179 mainloop_do_exec(p->cmd);
183 pid_t mainloop_do_spawn(const char *cmd,
184 void (*initenv)(void *p), void *p,
185 int *infd, int *outfd, int *errfd)
190 spawnp.initenv=initenv;
193 return mainloop_fork(do_spawn, (void*)&spawnp, infd, outfd, errfd);
197 pid_t mainloop_spawn(const char *cmd)
199 return mainloop_do_spawn(cmd, NULL, NULL, NULL, NULL, NULL);
206 /*{{{ popen_bgread */
211 bool mainloop_process_pipe_extlfn(int fd, ExtlFn fn)
216 n=read(fd, buf, BL-1);
218 if(errno==EAGAIN || errno==EINTR)
221 warn_err_obj(TR("reading a pipe"));
225 extl_call(fn, "s", NULL, &buf);
228 /* Call with no argument/NULL string to signify EOF */
229 extl_call(fn, NULL, NULL);
235 static void process_pipe(int fd, void *p)
237 if(!mainloop_process_pipe_extlfn(fd, *(ExtlFn*)p)){
238 /* We get here on EOL or if the handler failed */
239 mainloop_unregister_input_fd(fd);
241 extl_unref_fn(*(ExtlFn*)p);
247 bool mainloop_register_input_fd_extlfn(int fd, ExtlFn fn)
249 ExtlFn *p=ALLOC(ExtlFn);
251 *(ExtlFn*)p=extl_ref_fn(fn);
252 if(mainloop_register_input_fd(fd, p, process_pipe))
254 extl_unref_fn(*(ExtlFn*)p);
261 pid_t mainloop_popen_bgread(const char *cmd,
262 void (*initenv)(void *p), void *p,
263 ExtlFn handler, ExtlFn errhandler)
267 ExtlFn none=extl_fn_none();
269 pid=mainloop_do_spawn(cmd, initenv, p, NULL,
270 (handler!=none ? &fd : NULL),
271 (errhandler!=none ? &errfd : NULL));
275 if(!mainloop_register_input_fd_extlfn(fd, handler))
278 if(errhandler!=extl_fn_none()){
279 if(!mainloop_register_input_fd_extlfn(errfd, errhandler))
301 void cloexec_braindamage_fix(int fd)
303 fcntl(fd, F_SETFD, FD_CLOEXEC);