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 WvSubProc::WvSubProc()
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
00051
if (memlimit > 0)
00052 {
00053
struct rlimit rlim;
00054 rlim.rlim_cur = memlimit * 1024 * 1024;
00055 rlim.rlim_max = memlimit * 1024 * 1024;
00056 setrlimit(RLIMIT_AS, &rlim);
00057 }
00058
00059
00060 execvp(cmd, (
char *
const *)argv);
00061
00062
00063
00064
00065 _exit(242);
00066 }
00067
else if (
pid > 0)
00068
running =
true;
00069
else if (
pid < 0)
00070
return pid;
00071
00072
return 0;
00073 }
00074
00075
00076 void WvSubProc::prepare(
const char cmd[], ...)
00077 {
00078 va_list ap;
00079 va_start(ap, cmd);
00080
preparev(cmd, ap);
00081 va_end(ap);
00082 }
00083
00084
00085 void WvSubProc::preparev(
const char cmd[], va_list ap)
00086 {
00087
const char *argptr;
00088
00089
00090
last_cmd = cmd;
00091
last_args.zap();
00092
while ((argptr = va_arg(ap,
const char *)) != NULL)
00093
last_args.append(
new WvString(argptr),
true);
00094 }
00095
00096
00097 void WvSubProc::preparev(
const char cmd[],
const char *
const *argv)
00098 {
00099
const char *
const *argptr;
00100
00101
00102
last_cmd = cmd;
00103
last_args.zap();
00104
for (argptr = argv; argptr && *argptr; argptr++)
00105
last_args.append(
new WvString(*argptr),
true);
00106 }
00107
00108 void WvSubProc::preparev(
const char cmd[],
WvStringList &args)
00109 {
00110
last_cmd = cmd;
00111
last_args.zap();
00112
00113 WvStringList::Iter i(args);
00114
for (i.rewind(); i.next(); )
00115
last_args.append(
new WvString(*i),
true);
00116 }
00117
00118 int WvSubProc::start(
const char cmd[], ...)
00119 {
00120 va_list ap;
00121 va_start(ap, cmd);
00122
preparev(cmd, ap);
00123 va_end(ap);
00124
00125
return start_again();
00126 }
00127
00128
00129 int WvSubProc::startv(
const char cmd[],
const char *
const *argv)
00130 {
00131
preparev(cmd, argv);
00132
return start_again();
00133 }
00134
00135
00136 int WvSubProc::start_again()
00137 {
00138
int retval;
00139
const char **argptr;
00140
00141 assert(!!
last_cmd);
00142
00143
00144
const char **argv =
new const char*[
last_args.count() + 1];
00145 WvStringList::Iter i(
last_args);
00146
for (argptr = argv, i.rewind(); i.next(); argptr++)
00147 *argptr = *i;
00148 *argptr = NULL;
00149
00150
00151 retval = _startv(
last_cmd, argv);
00152
00153
00154
delete[] argv;
00155
00156
return retval;
00157 }
00158
00159
00160 int WvSubProc::fork(
int *waitfd)
00161 {
00162
running =
false;
00163
estatus = 0;
00164
00165
pid =
wvfork_start(waitfd);
00166
00167
if (!
pid)
00168 {
00169
00170
00171
00172
00173
00174 setpgid(0,0);
00175
00176
00177 WvStringList::Iter i(
env);
00178
for (i.rewind(); i.next(); )
00179 putenv(i().edit());
00180 }
00181
else if (
pid > 0)
00182 {
00183
00184
running =
true;
00185 }
00186
else if (
pid < 0)
00187
return -errno;
00188
00189
return pid;
00190 }
00191
00192
00193 pid_t
WvSubProc::pidfile_pid()
00194 {
00195
if (!!
pidfile)
00196 {
00197
00198
char buf[1024];
00199 pid_t p = -1;
00200 FILE *file = fopen(
pidfile,
"r");
00201
00202 memset(buf, 0,
sizeof(buf));
00203
if (file && fread(buf, 1,
sizeof(buf), file) > 0)
00204 p = atoi(buf);
00205
if (file)
00206 fclose(file);
00207
if (p <= 0)
00208 p = -1;
00209
return p;
00210 }
00211
00212
return -1;
00213 }
00214
00215
00216 void WvSubProc::kill(
int sig)
00217 {
00218 assert(!
running ||
pid > 0 || !
old_pids.isempty());
00219
00220
if (pid > 0)
00221 {
00222
00223
00224 assert(pid != 1);
00225
if (::kill(-pid, sig) < 0 && errno == ESRCH)
00226
kill_primary(sig);
00227 }
00228
00229
00230 pid_tList::Iter i(
old_pids);
00231
for (i.rewind(); i.next(); )
00232 {
00233 pid_t subpid = *i;
00234 assert(subpid != 1 && subpid != -1);
00235
if (::kill(-subpid, sig) < 0 && errno == ESRCH)
00236 ::kill(subpid, sig);
00237 }
00238 }
00239
00240
00241 void WvSubProc::kill_primary(
int sig)
00242 {
00243 assert(!
running ||
pid > 0 || !
old_pids.isempty());
00244
00245
if (
running && pid > 0)
00246 ::kill(pid, sig);
00247 }
00248
00249
00250 void WvSubProc::stop(time_t msec_delay,
bool kill_children)
00251 {
00252
wait(0);
00253
00254
if (
running)
00255 {
00256
if (kill_children)
00257
kill(SIGTERM);
00258
else
00259
kill_primary(SIGTERM);
00260
00261
wait(msec_delay, kill_children);
00262 }
00263
00264
if (
running)
00265 {
00266
if (kill_children)
00267
kill(SIGKILL);
00268
else
00269
kill_primary(SIGKILL);
00270
00271
wait(-1, kill_children);
00272 }
00273 }
00274
00275
00276 void WvSubProc::wait(time_t msec_delay,
bool wait_children)
00277 {
00278
bool xrunning;
00279
int status;
00280 pid_t dead_pid;
00281
struct timeval tv1, tv2;
00282
struct timezone tz;
00283
00284 assert(!
running ||
pid > 0 || !
old_pids.isempty());
00285
00286
00287
00288
00289 xrunning = (
running || (wait_children && !
old_pids.isempty()));
00290
00291
if (!xrunning)
return;
00292
00293 gettimeofday(&tv1, &tz);
00294 tv2 = tv1;
00295
00296
do
00297 {
00298
if (pid > 0)
00299 {
00300
00301
00302
00303
00304 dead_pid = waitpid(pid, &status, (msec_delay >= 0) ? WNOHANG : 0);
00305
00306
00307
00308
00309
if (dead_pid == pid
00310 || (dead_pid < 0 && (errno == ECHILD || errno == ESRCH)))
00311 {
00312
00313
estatus = status;
00314
old_pids.append(
new pid_t(pid),
true);
00315
00316 pid_t p2 =
pidfile_pid();
00317
if (pid != p2)
00318 pid = p2;
00319
else
00320 pid = -1;
00321 }
00322
else if (dead_pid < 0)
00323 perror(
"WvSubProc::waitpid");
00324 }
00325
00326
00327
if (pid < 0)
00328 {
00329 pid_tList::Iter i(
old_pids);
00330
for (i.rewind(); i.next(); )
00331 {
00332 pid_t subpid = *i;
00333
00334
00335
00336
00337 waitpid(subpid, NULL, WNOHANG);
00338
00339
if (::kill(-subpid, 0) && errno == ESRCH)
00340 i.xunlink();
00341 }
00342
00343
00344
00345
00346
if (!wait_children ||
old_pids.isempty())
00347 xrunning =
false;
00348 }
00349
00350
00351
if (xrunning && msec_delay != 0)
00352 usleep(50*1000);
00353
00354 gettimeofday(&tv2, &tz);
00355
00356 }
while (xrunning && msec_delay
00357 && (msec_delay < 0 ||
msecdiff(tv2, tv1) < msec_delay));
00358
00359
if (!xrunning)
00360
running =
false;
00361 }