document where the posix module is on Debian
[notion/jeffpc.git] / mod_statusbar / statusd-launch.c
blobb298f9d38e3ae1ba8faf4158e99f032e3930cffe
1 /*
2 * ion/mod_statusbar/statusd-launch.c
4 * Copyright (c) Tuomo Valkonen 1999-2009.
6 * See the included file LICENSE for details.
7 */
9 #include <sys/time.h>
10 #include <sys/types.h>
11 #include <unistd.h>
12 #include <time.h>
13 #include <errno.h>
15 #include <libtu/minmax.h>
16 #include <libextl/readconfig.h>
17 #include <libmainloop/exec.h>
18 #include <libmainloop/select.h>
19 #include <libmainloop/signal.h>
20 #include <ioncore/saveload.h>
21 #include <ioncore/bindmaps.h>
22 #include <ioncore/global.h>
23 #include <ioncore/ioncore.h>
25 #include "statusbar.h"
28 #define CF_STATUSD_TIMEOUT_SEC 3
30 #define BL 1024
32 #define USEC 1000000
35 static bool process_pipe(int fd, ExtlFn fn,
36 bool *doneseen, bool *eagain)
38 char buf[BL];
39 int n;
40 bool fnret;
42 *eagain=FALSE;
44 n=read(fd, buf, BL-1);
46 if(n<0){
47 if(errno==EAGAIN || errno==EINTR){
48 *eagain=(errno==EAGAIN);
49 return TRUE;
51 warn_err_obj(TR("reading a pipe"));
52 return FALSE;
53 }else if(n>0){
54 buf[n]='\0';
55 *doneseen=FALSE;
56 return extl_call(fn, "s", "b", &buf, doneseen);
59 return FALSE;
63 static bool wait_statusd_init(int outfd, int errfd, ExtlFn dh, ExtlFn eh)
65 fd_set rfds;
66 struct timeval tv, endtime, now;
67 int nfds=maxof(outfd, errfd);
68 int retval;
69 bool dummy, doneseen, eagain=FALSE;
71 if(mainloop_gettime(&endtime)!=0){
72 warn_err();
73 return FALSE;
76 now=endtime;
77 endtime.tv_sec+=CF_STATUSD_TIMEOUT_SEC;
79 while(1){
80 FD_ZERO(&rfds);
82 /* Calculate remaining time */
83 if(now.tv_sec>endtime.tv_sec){
84 goto timeout;
85 }else if(now.tv_sec==endtime.tv_sec){
86 if(now.tv_usec>=endtime.tv_usec)
87 goto timeout;
88 tv.tv_sec=0;
89 tv.tv_usec=endtime.tv_usec-now.tv_usec;
90 }else{
91 tv.tv_usec=USEC+endtime.tv_usec-now.tv_usec;
92 tv.tv_sec=-1+endtime.tv_sec-now.tv_sec;
93 /* Kernel lameness tuner: */
94 tv.tv_sec+=tv.tv_usec/USEC;
95 tv.tv_usec%=USEC;
98 FD_SET(outfd, &rfds);
99 FD_SET(errfd, &rfds);
101 retval=select(nfds+1, &rfds, NULL, NULL, &tv);
102 if(retval>0){
103 if(FD_ISSET(errfd, &rfds)){
104 if(!process_pipe(errfd, eh, &dummy, &eagain))
105 return FALSE;
107 if(FD_ISSET(outfd, &rfds)){
108 if(!process_pipe(outfd, dh, &doneseen, &eagain))
109 return FALSE;
110 if(doneseen){
111 /* Read rest of errors. */
112 bool ok;
114 ok=process_pipe(errfd, eh, &dummy, &eagain);
115 }while(ok && !eagain);
116 return TRUE;
119 }else if(retval==0){
120 goto timeout;
123 if(mainloop_gettime(&now)!=0){
124 warn_err();
125 return FALSE;
129 return TRUE;
131 timeout:
132 /* Just complain to stderr, not startup error log, and do not fail.
133 * The system might just be a bit slow. We can continue, but without
134 * initial values for the meters, geometry adjustments may be necessary
135 * when we finally get that information.
137 ioncore_warn_nolog(TR("ion-statusd timed out."));
138 return TRUE;
142 EXTL_EXPORT
143 int mod_statusbar__launch_statusd(const char *cmd,
144 ExtlFn initdatahandler,
145 ExtlFn initerrhandler,
146 ExtlFn datahandler,
147 ExtlFn errhandler)
149 pid_t pid;
150 int outfd=-1, errfd=-1;
152 if(cmd==NULL)
153 return -1;
155 pid=mainloop_do_spawn(cmd, NULL, NULL,
156 NULL, &outfd, &errfd);
158 if(pid<0)
159 return -1;
161 if(!wait_statusd_init(outfd, errfd, initdatahandler, initerrhandler))
162 goto err;
164 if(!mainloop_register_input_fd_extlfn(outfd, datahandler))
165 goto err;
167 if(!mainloop_register_input_fd_extlfn(errfd, errhandler))
168 goto err2;
170 return pid;
172 err2:
173 mainloop_unregister_input_fd(outfd);
174 err:
175 close(outfd);
176 close(errfd);
177 return -1;