new mod_xrandr
[notion/jeffpc.git] / libmainloop / exec.c
blobf4847a8a141a77aadbe97e3967c49bd4e7b91bc1
1 /*
2 * ion/mainloop/exec.c
4 * Copyright (c) Tuomo Valkonen 1999-2009.
6 * See the included file LICENSE for details.
7 */
9 #include <limits.h>
10 #include <sys/types.h>
11 #include <sys/signal.h>
12 #include <unistd.h>
13 #include <fcntl.h>
14 #include <signal.h>
15 #include <time.h>
16 #include <string.h>
17 #include <stdlib.h>
18 #include <stdio.h>
19 #include <errno.h>
21 #include <libtu/output.h>
22 #include <libtu/misc.h>
23 #include <libtu/locale.h>
24 #include <libtu/types.h>
26 #include "select.h"
27 #include "exec.h"
30 /*{{{ Exec/spawn/fork */
32 #define SHELL_PATH "/bin/sh"
33 #define SHELL_NAME "sh"
34 #define SHELL_ARG "-c"
37 void mainloop_do_exec(const char *cmd)
39 char *argv[4];
41 argv[0]=SHELL_NAME;
42 argv[1]=SHELL_ARG;
43 argv[2]=(char*)cmd; /* stupid execve... */
44 argv[3]=NULL;
45 execvp(SHELL_PATH, argv);
49 static int mypipe(int *fds)
51 int r=pipe(fds);
52 if(r==0){
53 cloexec_braindamage_fix(fds[0]);
54 cloexec_braindamage_fix(fds[1]);
55 }else{
56 warn_err_obj("pipe()");
58 return r;
62 static bool unblock(int fd)
64 int fl=fcntl(fd, F_GETFL);
65 if(fl!=-1)
66 fl=fcntl(fd, F_SETFL, fl|O_NONBLOCK);
67 return (fd!=-1);
71 static void duppipe(int fd, int idx, int *fds)
73 close(fd);
74 dup(fds[idx]);
75 close(fds[0]);
76 close(fds[1]);
80 pid_t mainloop_fork(void (*fn)(void *p), void *fnp,
81 int *infd, int *outfd, int *errfd)
83 int pid;
84 int infds[2];
85 int outfds[2];
86 int errfds[2];
88 if(infd!=NULL){
89 if(mypipe(infds)!=0)
90 return -1;
93 if(outfd!=NULL){
94 if(mypipe(outfds)!=0)
95 goto err1;
98 if(errfd!=NULL){
99 if(mypipe(errfds)!=0)
100 goto err2;
104 pid=fork();
106 if(pid<0)
107 goto err3;
109 if(pid!=0){
110 if(outfd!=NULL){
111 if(!unblock(outfds[0]))
112 goto err3;
113 *outfd=outfds[0];
114 close(outfds[1]);
117 if(errfd!=NULL){
118 if(!unblock(errfds[0]))
119 goto err3;
120 *errfd=errfds[0];
121 close(errfds[1]);
124 if(infd!=NULL){
125 *infd=infds[1];
126 close(infds[0]);
129 return pid;
132 if(infd!=NULL)
133 duppipe(0, 0, infds);
134 if(outfd!=NULL)
135 duppipe(1, 1, outfds);
136 if(errfd!=NULL)
137 duppipe(2, 1, errfds);
139 fn(fnp);
141 abort();
143 err3:
144 warn_err();
145 if(errfd!=NULL){
146 close(errfds[0]);
147 close(errfds[1]);
149 err2:
150 if(outfd!=NULL){
151 close(outfds[0]);
152 close(outfds[1]);
154 err1:
155 if(infd!=NULL){
156 close(infds[0]);
157 close(infds[1]);
159 return -1;
163 typedef struct{
164 const char *cmd;
165 void (*initenv)(void *p);
166 void *initenvp;
167 } SpawnP;
170 static void do_spawn(void *spawnp)
172 SpawnP *p=(SpawnP*)spawnp;
174 if(p->initenv)
175 p->initenv(p->initenvp);
176 mainloop_do_exec(p->cmd);
180 pid_t mainloop_do_spawn(const char *cmd,
181 void (*initenv)(void *p), void *p,
182 int *infd, int *outfd, int *errfd)
184 SpawnP spawnp;
186 spawnp.cmd=cmd;
187 spawnp.initenv=initenv;
188 spawnp.initenvp=p;
190 return mainloop_fork(do_spawn, (void*)&spawnp, infd, outfd, errfd);
194 pid_t mainloop_spawn(const char *cmd)
196 return mainloop_do_spawn(cmd, NULL, NULL, NULL, NULL, NULL);
200 /*}}}*/
203 /*{{{ popen_bgread */
206 #define BL 1024
208 bool mainloop_process_pipe_extlfn(int fd, ExtlFn fn)
210 char buf[BL];
211 int n;
213 n=read(fd, buf, BL-1);
214 if(n<0){
215 if(errno==EAGAIN || errno==EINTR)
216 return TRUE;
217 n=0;
218 warn_err_obj(TR("reading a pipe"));
219 return FALSE;
220 }else if(n>0){
221 buf[n]='\0';
222 extl_call(fn, "s", NULL, &buf);
223 return TRUE;
224 }else/* if(n==0)*/{
225 /* Call with no argument/NULL string to signify EOF */
226 extl_call(fn, NULL, NULL);
227 return FALSE;
232 static void process_pipe(int fd, void *p)
234 if(!mainloop_process_pipe_extlfn(fd, *(ExtlFn*)p)){
235 /* We get here on EOL or if the handler failed */
236 mainloop_unregister_input_fd(fd);
237 close(fd);
238 extl_unref_fn(*(ExtlFn*)p);
239 free(p);
244 bool mainloop_register_input_fd_extlfn(int fd, ExtlFn fn)
246 ExtlFn *p=ALLOC(ExtlFn);
247 if(p!=NULL){
248 *(ExtlFn*)p=extl_ref_fn(fn);
249 if(mainloop_register_input_fd(fd, p, process_pipe))
250 return TRUE;
251 extl_unref_fn(*(ExtlFn*)p);
252 free(p);
254 return FALSE;
258 pid_t mainloop_popen_bgread(const char *cmd,
259 void (*initenv)(void *p), void *p,
260 ExtlFn handler, ExtlFn errhandler)
262 pid_t pid=-1;
263 int fd=-1, errfd=-1;
264 ExtlFn none=extl_fn_none();
266 pid=mainloop_do_spawn(cmd, initenv, p, NULL,
267 (handler!=none ? &fd : NULL),
268 (errhandler!=none ? &errfd : NULL));
270 if(pid>0){
271 if(handler!=none){
272 if(!mainloop_register_input_fd_extlfn(fd, handler))
273 goto err;
275 if(errhandler!=extl_fn_none()){
276 if(!mainloop_register_input_fd_extlfn(errfd, errhandler))
277 goto err;
281 return pid;
283 err:
284 if(fd>=0)
285 close(fd);
286 if(errfd>=0)
287 close(errfd);
288 return -1;
292 /*}}}*/
295 /*{{{ Misc. */
298 void cloexec_braindamage_fix(int fd)
300 fcntl(fd, F_SETFD, FD_CLOEXEC);
304 /*}}}*/