00001
00002
00003
00004
00005
00006
00007
00008 #include "wvsubproc.h"
00009 #include "wvtimeutils.h"
00010 #include <stdio.h>
00011 #include <unistd.h>
00012 #include <sys/types.h>
00013 #include <sys/wait.h>
00014 #include <sys/time.h>
00015 #include <stdarg.h>
00016 #include <errno.h>
00017 #include <assert.h>
00018
00019 #include "wvfork.h"
00020
00021 void WvSubProc::init()
00022 {
00023 pid = -1;
00024 memlimit = -1;
00025 running = false;
00026 estatus = 0;
00027 }
00028
00029
00030 WvSubProc::~WvSubProc()
00031 {
00032
00033
00034 stop(100);
00035 }
00036
00037
00038 int WvSubProc::_startv(const char cmd[], const char * const *argv)
00039 {
00040 int waitfd = -1;
00041
00042 pid = fork(&waitfd);
00043
00044
00045 if (!pid)
00046 {
00047
00048 close(waitfd);
00049
00050 #ifdef RLIMIT_AS
00051
00052 if (memlimit > 0)
00053 {
00054 struct rlimit rlim;
00055 memset(&rlim, 0, sizeof(rlim));
00056 rlim.rlim_cur = memlimit * 1024 * 1024;
00057 rlim.rlim_max = memlimit * 1024 * 1024;
00058 setrlimit(RLIMIT_AS, &rlim);
00059 }
00060 #endif
00061
00062
00063 execvp(cmd, (char * const *)argv);
00064
00065
00066
00067
00068 _exit(242);
00069 }
00070 else if (pid > 0)
00071 running = true;
00072 else if (pid < 0)
00073 return pid;
00074
00075 return 0;
00076 }
00077
00078
00079 void WvSubProc::prepare(const char cmd[], ...)
00080 {
00081 va_list ap;
00082 va_start(ap, cmd);
00083 preparev(cmd, ap);
00084 va_end(ap);
00085 }
00086
00087
00088 void WvSubProc::preparev(const char cmd[], va_list ap)
00089 {
00090 const char *argptr;
00091
00092
00093 last_cmd = cmd;
00094 last_args.zap();
00095 while ((argptr = va_arg(ap, const char *)) != NULL)
00096 last_args.append(new WvString(argptr), true);
00097 }
00098
00099
00100 void WvSubProc::preparev(const char cmd[], const char * const *argv)
00101 {
00102 const char * const *argptr;
00103
00104
00105 last_cmd = cmd;
00106 last_args.zap();
00107 for (argptr = argv; argptr && *argptr; argptr++)
00108 last_args.append(new WvString(*argptr), true);
00109 }
00110
00111 void WvSubProc::preparev(const char cmd[], WvStringList &args)
00112 {
00113 last_cmd = cmd;
00114 last_args.zap();
00115
00116 WvStringList::Iter i(args);
00117 for (i.rewind(); i.next(); )
00118 last_args.append(new WvString(*i), true);
00119 }
00120
00121 int WvSubProc::start(const char cmd[], ...)
00122 {
00123 va_list ap;
00124 va_start(ap, cmd);
00125 preparev(cmd, ap);
00126 va_end(ap);
00127
00128 return start_again();
00129 }
00130
00131
00132 int WvSubProc::startv(const char cmd[], const char * const *argv)
00133 {
00134 preparev(cmd, argv);
00135 return start_again();
00136 }
00137
00138
00139 int WvSubProc::start_again()
00140 {
00141 int retval;
00142 const char **argptr;
00143
00144 assert(!!last_cmd);
00145
00146
00147 const char **argv = new const char*[last_args.count() + 1];
00148 WvStringList::Iter i(last_args);
00149 for (argptr = argv, i.rewind(); i.next(); argptr++)
00150 *argptr = *i;
00151 *argptr = NULL;
00152
00153
00154 retval = _startv(last_cmd, argv);
00155
00156
00157 deletev argv;
00158
00159 return retval;
00160 }
00161
00162
00163 int WvSubProc::fork(int *waitfd)
00164 {
00165 static WvString ldpreload, ldlibrary;
00166
00167 running = false;
00168 estatus = 0;
00169
00170 pid = wvfork_start(waitfd);
00171
00172 if (!pid)
00173 {
00174
00175
00176
00177
00178
00179 setpgid(0,0);
00180
00181
00182 WvStringList::Iter i(env);
00183 for (i.rewind(); i.next(); )
00184 {
00185 if (!strncmp(*i, "LD_LIBRARY_PATH=", 16)
00186 && getenv("LD_LIBRARY_PATH"))
00187 {
00188
00189 ldlibrary = WvString("%s:%s", *i,
00190 getenv("LD_LIBRARY_PATH") + 16);
00191 putenv(ldlibrary.edit());
00192 }
00193 else if (!strncmp(*i, "LD_PRELOAD=", 11)
00194 && getenv("LD_PRELOAD"))
00195 {
00196
00197 ldpreload = WvString("%s:%s", *i,
00198 getenv("LD_PRELOAD") + 11);
00199 putenv(ldpreload.edit());
00200 }
00201 else if (!strstr(*i, "="))
00202 {
00203
00204
00205 unsetenv(*i);
00206 }
00207 else
00208 putenv(i->edit());
00209 }
00210 }
00211 else if (pid > 0)
00212 {
00213
00214 running = true;
00215 }
00216 else if (pid < 0)
00217 return -errno;
00218
00219 return pid;
00220 }
00221
00222
00223 pid_t WvSubProc::pidfile_pid()
00224 {
00225 if (!!pidfile)
00226 {
00227
00228 char buf[1024];
00229 pid_t p = -1;
00230 FILE *file = fopen(pidfile, "r");
00231
00232 memset(buf, 0, sizeof(buf));
00233 if (file && fread(buf, 1, sizeof(buf), file) > 0)
00234 p = atoi(buf);
00235 if (file)
00236 fclose(file);
00237 if (p <= 0)
00238 p = -1;
00239 return p;
00240 }
00241
00242 return -1;
00243 }
00244
00245
00246 void WvSubProc::kill(int sig)
00247 {
00248 assert(!running || pid > 0 || !old_pids.isempty());
00249
00250 if (pid > 0)
00251 {
00252
00253
00254 assert(pid != 1);
00255 if (::kill(-pid, sig) < 0 && errno == ESRCH)
00256 kill_primary(sig);
00257 }
00258
00259
00260 pid_tList::Iter i(old_pids);
00261 for (i.rewind(); i.next(); )
00262 {
00263 pid_t subpid = *i;
00264 assert(subpid != 1 && subpid != -1);
00265 if (::kill(-subpid, sig) < 0 && errno == ESRCH)
00266 ::kill(subpid, sig);
00267 }
00268 }
00269
00270
00271 void WvSubProc::kill_primary(int sig)
00272 {
00273 assert(!running || pid > 0 || !old_pids.isempty());
00274
00275 if (running && pid > 0)
00276 ::kill(pid, sig);
00277 }
00278
00279
00280 void WvSubProc::stop(time_t msec_delay, bool kill_children)
00281 {
00282 wait(0);
00283
00284 if (running)
00285 {
00286 if (kill_children)
00287 kill(SIGTERM);
00288 else
00289 kill_primary(SIGTERM);
00290
00291 wait(msec_delay, kill_children);
00292 }
00293
00294 if (running)
00295 {
00296 if (kill_children)
00297 kill(SIGKILL);
00298 else
00299 kill_primary(SIGKILL);
00300
00301 wait(-1, kill_children);
00302 }
00303 }
00304
00305
00306 void WvSubProc::wait(time_t msec_delay, bool wait_children)
00307 {
00308 bool xrunning;
00309 int status;
00310 pid_t dead_pid;
00311 struct timeval tv1, tv2;
00312 struct timezone tz;
00313
00314 assert(!running || pid > 0 || !old_pids.isempty());
00315
00316
00317
00318
00319 xrunning = (running || (wait_children && !old_pids.isempty()));
00320
00321 if (!xrunning) return;
00322
00323 gettimeofday(&tv1, &tz);
00324 tv2 = tv1;
00325
00326 do
00327 {
00328 if (pid > 0)
00329 {
00330
00331
00332
00333
00334 dead_pid = waitpid(pid, &status, (msec_delay >= 0) ? WNOHANG : 0);
00335
00336
00337
00338
00339 if (dead_pid == pid
00340 || (dead_pid < 0 && (errno == ECHILD || errno == ESRCH)))
00341 {
00342
00343 estatus = status;
00344 old_pids.append(new pid_t(pid), true);
00345
00346 pid_t p2 = pidfile_pid();
00347 if (pid != p2)
00348 pid = p2;
00349 else
00350 pid = -1;
00351 }
00352 else if (dead_pid < 0)
00353 perror("WvSubProc::waitpid");
00354 }
00355
00356
00357 if (pid < 0)
00358 {
00359 pid_tList::Iter i(old_pids);
00360 for (i.rewind(); i.next(); )
00361 {
00362 pid_t subpid = *i;
00363
00364
00365
00366
00367 waitpid(subpid, NULL, WNOHANG);
00368
00369 if (::kill(-subpid, 0) && errno == ESRCH)
00370 i.xunlink();
00371 }
00372
00373
00374
00375
00376 if (!wait_children || old_pids.isempty())
00377 xrunning = false;
00378 }
00379
00380
00381 if (xrunning && msec_delay != 0)
00382 usleep(50*1000);
00383
00384 gettimeofday(&tv2, &tz);
00385
00386 } while (xrunning && msec_delay
00387 && (msec_delay < 0 || msecdiff(tv2, tv1) < msec_delay));
00388
00389 if (!xrunning)
00390 running = false;
00391 }