1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 168 169 170 171 172 173 174 175 176 177 178 179
|
/*
* ion/mod_statusbar/statusd-launch.c
*
* Copyright (c) Tuomo Valkonen 1999-2009.
*
* See the included file LICENSE for details.
*/
#include <sys/time.h>
#include <sys/types.h>
#include <unistd.h>
#include <time.h>
#include <errno.h>
#include <libtu/minmax.h>
#include <libextl/readconfig.h>
#include <libmainloop/exec.h>
#include <libmainloop/select.h>
#include <libmainloop/signal.h>
#include <ioncore/saveload.h>
#include <ioncore/bindmaps.h>
#include <ioncore/global.h>
#include <ioncore/ioncore.h>
#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;
}
|