2 * notion/mainloop/exec.c
4 * Copyright (c) the Notion team 2013.
5 * Copyright (c) Tuomo Valkonen 1999-2009.
7 * See the included file LICENSE for details.
11 #include <sys/types.h>
12 #include <sys/signal.h>
22 #include <libtu/output.h>
23 #include <libtu/misc.h>
24 #include <libtu/locale.h>
25 #include <libtu/types.h>
31 /*{{{ Exec/spawn/fork */
33 #define SHELL_PATH "/bin/sh"
34 #define SHELL_NAME "sh"
35 #define SHELL_ARG "-c"
38 void mainloop_do_exec(const char *cmd
)
44 argv
[2]=(char*)cmd
; /* stupid execve... */
46 execvp(SHELL_PATH
, argv
);
50 static int mypipe(int *fds
)
54 cloexec_braindamage_fix(fds
[0]);
55 cloexec_braindamage_fix(fds
[1]);
57 warn_err_obj("pipe()");
63 static bool unblock(int fd
)
65 int fl
=fcntl(fd
, F_GETFL
);
67 fl
=fcntl(fd
, F_SETFL
, fl
|O_NONBLOCK
);
72 static void duppipe(int fd
, int idx
, int *fds
)
81 pid_t
mainloop_fork(void (*fn
)(void *p
), void *fnp
,
82 int *infd
, int *outfd
, int *errfd
)
100 if(mypipe(errfds
)!=0)
114 if(!unblock(outfds
[0]))
121 if(!unblock(errfds
[0]))
137 duppipe(0, 0, infds
);
139 duppipe(1, 1, outfds
);
141 duppipe(2, 1, errfds
);
170 void (*initenv
)(void *p
);
175 static void do_spawn(void *spawnp
)
177 SpawnP
*p
=(SpawnP
*)spawnp
;
180 p
->initenv(p
->initenvp
);
181 mainloop_do_exec(p
->cmd
);
185 pid_t
mainloop_do_spawn(const char *cmd
,
186 void (*initenv
)(void *p
), void *p
,
187 int *infd
, int *outfd
, int *errfd
)
192 spawnp
.initenv
=initenv
;
195 return mainloop_fork(do_spawn
, (void*)&spawnp
, infd
, outfd
, errfd
);
199 pid_t
mainloop_spawn(const char *cmd
)
201 return mainloop_do_spawn(cmd
, NULL
, NULL
, NULL
, NULL
, NULL
);
208 /*{{{ popen_bgread */
213 bool mainloop_process_pipe_extlfn(int fd
, ExtlFn fn
)
218 n
=read(fd
, buf
, BL
-1);
220 if(errno
==EAGAIN
|| errno
==EINTR
)
223 warn_err_obj(TR("reading a pipe"));
227 extl_call(fn
, "s", NULL
, &buf
);
230 /* Call with no argument/NULL string to signify EOF */
231 extl_call(fn
, NULL
, NULL
);
237 static void process_pipe(int fd
, void *p
)
239 if(!mainloop_process_pipe_extlfn(fd
, *(ExtlFn
*)p
)){
240 /* We get here on EOL or if the handler failed */
241 mainloop_unregister_input_fd(fd
);
243 extl_unref_fn(*(ExtlFn
*)p
);
249 bool mainloop_register_input_fd_extlfn(int fd
, ExtlFn fn
)
251 ExtlFn
*p
=ALLOC(ExtlFn
);
253 *(ExtlFn
*)p
=extl_ref_fn(fn
);
254 if(mainloop_register_input_fd(fd
, p
, process_pipe
))
256 extl_unref_fn(*(ExtlFn
*)p
);
263 pid_t
mainloop_popen_bgread(const char *cmd
,
264 void (*initenv
)(void *p
), void *p
,
265 ExtlFn handler
, ExtlFn errhandler
)
269 ExtlFn none
=extl_fn_none();
271 pid
=mainloop_do_spawn(cmd
, initenv
, p
, NULL
,
272 (handler
!=none
? &fd
: NULL
),
273 (errhandler
!=none
? &errfd
: NULL
));
277 if(!mainloop_register_input_fd_extlfn(fd
, handler
))
280 if(errhandler
!=extl_fn_none()){
281 if(!mainloop_register_input_fd_extlfn(errfd
, errhandler
))
303 void cloexec_braindamage_fix(int fd
)
305 fcntl(fd
, F_SETFD
, FD_CLOEXEC
);