X-Git-Url: https://git.decadent.org.uk/gitweb/?a=blobdiff_plain;f=mod_statusbar%2Fstatusd-launch.c;fp=mod_statusbar%2Fstatusd-launch.c;h=c07fa2f37914e6783aec72ff824f2b57987113a1;hb=a6561c9679cd701b0d50c3cfd44e4664f7df2b2f;hp=0000000000000000000000000000000000000000;hpb=cd09055902de482a1be019bf4b4efdae64c98d35;p=ion3.git diff --git a/mod_statusbar/statusd-launch.c b/mod_statusbar/statusd-launch.c new file mode 100644 index 0000000..c07fa2f --- /dev/null +++ b/mod_statusbar/statusd-launch.c @@ -0,0 +1,179 @@ +/* + * ion/mod_statusbar/statusd-launch.c + * + * Copyright (c) Tuomo Valkonen 1999-2007. + * + * See the included file LICENSE for details. + */ + +#include +#include +#include +#include +#include + +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include "statusbar.h" + + +#define CF_STATUSD_TIMEOUT_SEC 3 + +#define BL 1024 + +#define USEC 1000000 + + +static bool process_pipe(int fd, ExtlFn fn, + bool *doneseen, bool *eagain) +{ + char buf[BL]; + int n; + bool fnret; + + *eagain=FALSE; + + n=read(fd, buf, BL-1); + + if(n<0){ + if(errno==EAGAIN || errno==EINTR){ + *eagain=(errno==EAGAIN); + return TRUE; + } + warn_err_obj(TR("reading a pipe")); + return FALSE; + }else if(n>0){ + buf[n]='\0'; + *doneseen=FALSE; + return extl_call(fn, "s", "b", &buf, doneseen); + } + + return FALSE; +} + + +static bool wait_statusd_init(int outfd, int errfd, ExtlFn dh, ExtlFn eh) +{ + fd_set rfds; + struct timeval tv, endtime, now; + int nfds=maxof(outfd, errfd); + int retval; + bool dummy, doneseen, eagain=FALSE; + + if(mainloop_gettime(&endtime)!=0){ + warn_err(); + return FALSE; + } + + now=endtime; + endtime.tv_sec+=CF_STATUSD_TIMEOUT_SEC; + + while(1){ + FD_ZERO(&rfds); + + /* Calculate remaining time */ + if(now.tv_sec>endtime.tv_sec){ + goto timeout; + }else if(now.tv_sec==endtime.tv_sec){ + if(now.tv_usec>=endtime.tv_usec) + goto timeout; + tv.tv_sec=0; + tv.tv_usec=endtime.tv_usec-now.tv_usec; + }else{ + tv.tv_usec=USEC+endtime.tv_usec-now.tv_usec; + tv.tv_sec=-1+endtime.tv_sec-now.tv_sec; + /* Kernel lameness tuner: */ + tv.tv_sec+=tv.tv_usec/USEC; + tv.tv_usec%=USEC; + } + + FD_SET(outfd, &rfds); + FD_SET(errfd, &rfds); + + retval=select(nfds+1, &rfds, NULL, NULL, &tv); + if(retval>0){ + if(FD_ISSET(errfd, &rfds)){ + if(!process_pipe(errfd, eh, &dummy, &eagain)) + return FALSE; + } + if(FD_ISSET(outfd, &rfds)){ + if(!process_pipe(outfd, dh, &doneseen, &eagain)) + return FALSE; + if(doneseen){ + /* Read rest of errors. */ + bool ok; + do{ + ok=process_pipe(errfd, eh, &dummy, &eagain); + }while(ok && !eagain); + return TRUE; + } + } + }else if(retval==0){ + goto timeout; + } + + if(mainloop_gettime(&now)!=0){ + warn_err(); + return FALSE; + } + } + + return TRUE; + +timeout: + /* Just complain to stderr, not startup error log, and do not fail. + * The system might just be a bit slow. We can continue, but without + * initial values for the meters, geometry adjustments may be necessary + * when we finally get that information. + */ + ioncore_warn_nolog(TR("ion-statusd timed out.")); + return TRUE; +} + + +EXTL_EXPORT +int mod_statusbar__launch_statusd(const char *cmd, + ExtlFn initdatahandler, + ExtlFn initerrhandler, + ExtlFn datahandler, + ExtlFn errhandler) +{ + pid_t pid; + int outfd=-1, errfd=-1; + + if(cmd==NULL) + return -1; + + pid=mainloop_do_spawn(cmd, NULL, NULL, + NULL, &outfd, &errfd); + + if(pid<0) + return -1; + + if(!wait_statusd_init(outfd, errfd, initdatahandler, initerrhandler)) + goto err; + + if(!mainloop_register_input_fd_extlfn(outfd, datahandler)) + goto err; + + if(!mainloop_register_input_fd_extlfn(errfd, errhandler)) + goto err2; + + return pid; + +err2: + mainloop_unregister_input_fd(outfd); +err: + close(outfd); + close(errfd); + return -1; +} +