00001 #include "config.h"
00002
00003 #include <iostream>
00004
00005 #ifdef HAVE_STDLIB_H
00006 #include <stdlib.h>
00007 #endif
00008 #ifdef HAVE_SYS_TYPES_H
00009 #include <sys/types.h>
00010 #endif
00011 #ifdef HAVE_SYS_WAIT_H
00012 #include <sys/wait.h>
00013 #endif
00014 #ifdef HAVE_UNISTD_H
00015 #include <unistd.h>
00016 #endif
00017 #ifdef HAVE_SIGNAL_H
00018 #include <signal.h>
00019 #endif
00020 #ifdef HAVE_SYS_SELECT_H
00021 #include <sys/select.h>
00022 #endif
00023 #include <sys/time.h>
00024
00025 #include <cerrno>
00026
00027 #include "asserts.h"
00028 #include "error.h"
00029 #include "fs.h"
00030 #include "exec.h"
00031
00032
00033 execute::execute()
00034 {
00035 clear();
00036 }
00037
00038
00039 execute::~execute()
00040 {
00041 clear();
00042 }
00043
00044
00045
00046 void execute::clear(void)
00047 {
00048 if (child_running() && is_parent())
00049 signal_child(SIGKILL);
00050
00051 m_fd1[0] = 0;
00052 m_fd1[1] = 0;
00053 m_fd2[0] = 0;
00054 m_fd2[1] = 0;
00055 m_fd3[0] = 0;
00056 m_fd3[1] = 0;
00057 m_pid = 0;
00058 m_status = 0;
00059 m_in_eof = false;
00060 m_out_eof = false;
00061 m_err_eof = false;
00062 m_child_started = false;
00063 }
00064
00065
00066 static void _signal_handler(int signo)
00067 {
00068 throw(ERROR(0,"Tried to write to a read-only pipe"));
00069 }
00070
00071
00072 void execute::fork(void)
00073 {
00074 clear();
00075 if (signal(SIGPIPE, _signal_handler) == SIG_ERR)
00076 throw(ERROR(errno,"Could not catch SIGPIPIE signal"));
00077 if (pipe(m_fd1) < 0)
00078 throw(ERROR(errno,"Could not create pipe for in"));
00079 if (pipe(m_fd2) < 0)
00080 throw(ERROR(errno,"Could not create pipe for out"));
00081 if (pipe(m_fd3) < 0)
00082 throw(ERROR(errno,"Could not create pipe for err"));
00083 if ((m_pid = ::fork()) < 0)
00084 throw(ERROR(errno,"Could not fork"));
00085 if (m_pid > 0) {
00086
00087 close(m_fd1[0]);
00088 close(m_fd2[1]);
00089 close(m_fd3[1]);
00090 m_child_started = true;
00091 }
00092 else {
00093
00094 close(m_fd1[1]);
00095 close(m_fd2[0]);
00096 close(m_fd3[0]);
00097 }
00098 }
00099
00100
00101 bool execute::is_child(void)
00102 {
00103 if (m_pid == 0) {
00104 return(true);
00105 }
00106 return(false);
00107 }
00108
00109
00110 bool execute::is_parent(void)
00111 {
00112 bool value;
00113
00114 value = !is_child();
00115
00116 return(value);
00117 }
00118
00119
00120 pid_t execute::my_pid(void)
00121 {
00122 pid_t value;
00123
00124 value = pid();
00125
00126 return(value);
00127 }
00128
00129
00130 void execute::exit(int code)
00131 {
00132 if (is_child())
00133 ::exit(code);
00134 }
00135
00136
00137
00138 void execute::reroute_stdio(void)
00139 {
00140 if (!is_child())
00141 return;
00142
00143 if (m_fd1[0] != STDIN_FILENO) {
00144 if (dup2(m_fd1[0], STDIN_FILENO) != STDIN_FILENO) {
00145 error e(errno,ERROR_INSTANCE("dup2() failed for stdin"));
00146 std::cerr << e << std::endl;
00147 exit(127);
00148 }
00149 close(m_fd1[0]);
00150 }
00151 if (m_fd2[1] != STDOUT_FILENO) {
00152 if (dup2(m_fd2[1], STDOUT_FILENO) != STDOUT_FILENO) {
00153 error e(errno,ERROR_INSTANCE("dup2() failed for stdout"));
00154 std::cerr << e << std::endl;
00155 exit(127);
00156 }
00157 close(m_fd2[1]);
00158 }
00159 if (m_fd3[1] != STDERR_FILENO) {
00160 if (dup2(m_fd3[1], STDERR_FILENO) != STDERR_FILENO) {
00161 error e(errno,ERROR_INSTANCE("dup2() failed for stderr"));
00162 std::cerr << e << std::endl;
00163 exit(127);
00164 }
00165 close(m_fd3[1]);
00166 }
00167 }
00168
00169
00170 pid_t execute::child_pid(void)
00171 {
00172 return(m_pid);
00173 }
00174
00175
00176 void execute::signal_child(int signal_no)
00177 {
00178 kill(m_pid, signal_no);
00179 }
00180
00181
00182 void execute::hup_child(void)
00183 {
00184 signal_child(SIGHUP);
00185 }
00186
00187
00188 void execute::kill_child(void)
00189 {
00190 signal_child(SIGKILL);
00191 }
00192
00193
00194 void execute::wait(void)
00195 {
00196 if (is_parent())
00197 ::wait(&m_status);
00198 }
00199
00200
00201 pid_t execute::check_child_(void)
00202 {
00203 pid_t value;
00204
00205 value = waitpid(m_pid, &m_status, WNOHANG|WUNTRACED);
00206
00207 return(value);
00208 }
00209
00210
00211 bool execute::child_started(void) const
00212 {
00213 return(m_child_started);
00214 }
00215
00216
00217 bool execute::child_running(void)
00218 {
00219 bool value;
00220
00221
00222 value = (check_child_() != -1);
00223
00224 return(value);
00225 }
00226
00227
00228 bool execute::child_exited(void)
00229 {
00230 bool value;
00231
00232 value = (check_child_() == -1);
00233
00234 return(value);
00235 }
00236
00237
00238 bool execute::child_exited_normally(void)
00239 {
00240 bool value;
00241
00242
00243
00244 value = (child_exited() && (child_exit_code() == 0));
00245
00246 return(value);
00247 }
00248
00249
00250 bool execute::child_signaled(void)
00251 {
00252 bool value;
00253
00254 check_child_();
00255 value = WIFSIGNALED(m_status);
00256
00257 return(value);
00258 }
00259
00260
00261 int execute::child_exit_code(void)
00262 {
00263 int value;
00264
00265
00266 check_child_();
00267 value = WEXITSTATUS(m_status);
00268
00269 return(value);
00270 }
00271
00272
00273 int execute::child_signal_no(void)
00274 {
00275 int value;
00276
00277 check_child_();
00278 if (child_exited()) {
00279 value = WTERMSIG(m_status);
00280 return(value);
00281 }
00282 else {
00283 value = WSTOPSIG(m_status);
00284 return(value);
00285 }
00286 }
00287
00288
00289
00290
00291
00292
00293
00294
00295
00296 int execute::in_fd(void)
00297 {
00298 if (is_parent()) {
00299
00300 return(m_fd1[1]);
00301 }
00302 else {
00303
00304 return(m_fd1[0]);
00305 }
00306 }
00307
00308
00309
00310
00311
00312
00313
00314
00315
00316 int execute::out_fd(void)
00317 {
00318 if (is_parent()) {
00319
00320 return(m_fd2[0]);
00321 }
00322 else {
00323
00324 return(m_fd2[1]);
00325 }
00326 }
00327
00328
00329
00330
00331
00332
00333
00334
00335
00336 int execute::err_fd(void)
00337 {
00338 if (is_parent()) {
00339
00340 return(m_fd3[0]);
00341 }
00342 else {
00343
00344 return(m_fd3[1]);
00345 }
00346 }
00347
00348
00349 bool execute::check_write_ready_(int fd)
00350 {
00351 struct timeval timeout = { 0, 0 };
00352 fd_set wset;
00353
00354 FD_ZERO(&wset);
00355 FD_SET(fd, &wset);
00356 select(fd+1, 0, &wset, 0, &timeout);
00357 if (FD_ISSET(fd, &wset)) {
00358 return(true);
00359 }
00360 return(false);
00361 }
00362
00363
00364 bool execute::check_read_ready_(int fd)
00365 {
00366 struct timeval timeout = { 0, 0 };
00367 fd_set rset;
00368
00369 FD_ZERO(&rset);
00370 FD_SET(fd, &rset);
00371 select(fd+1, &rset, 0, 0, &timeout);
00372 if (FD_ISSET(fd, &rset)) {
00373 return(true);
00374 }
00375 return(false);
00376 }
00377
00378
00379 void execute::exec(const std::string command)
00380 {
00381 fork();
00382 if (is_parent())
00383 return;
00384
00385
00386
00387
00388
00389
00390
00391
00392
00393
00394 reroute_stdio();
00395
00396 execl("/bin/sh", "sh", "-c", command.c_str(), (char *)0);
00397 exit(127);
00398 }
00399
00400
00401 void execute::exec(const std::string binary, const std::vector<std::string> argv)
00402 {
00403 char *bin = 0;
00404 char *base = 0;
00405 char **args = 0;
00406 uint16 c;
00407 size_t size;
00408
00409 fork();
00410 if (is_parent())
00411 return;
00412
00413
00414
00415
00416
00417
00418
00419
00420
00421
00422
00423 reroute_stdio();
00424
00425 bin = (char *)binary.c_str();
00426 base = bin+strlen(bin);
00427 while ((base > bin) && (*base != '/')) {
00428 base--;
00429 }
00430 if (*base == '/') {
00431 base++;
00432 }
00433 size = (argv.size() + 2) * sizeof(char *);
00434 args = (char **)malloc(size);
00435 memset((void *)args, 0, size);
00436 if (args == 0) {
00437 exit(127);
00438 }
00439 args[0] = base;
00440 for (c = 0; c < argv.size(); c++) {
00441 args[c+1] = (char *)argv[c].c_str();
00442 }
00443 args[c+1] = 0;
00444
00445 execv(bin, args);
00446 exit(127);
00447 }
00448
00449
00450
00451
00452
00453
00454
00455
00456
00457 bool execute::in_ready(void)
00458 {
00459 bool value;
00460
00461 if (is_parent())
00462 value = check_write_ready_(in_fd());
00463 else
00464 value = check_read_ready_(in_fd());
00465
00466 return(value);
00467 }
00468
00469
00470
00471
00472
00473
00474
00475
00476
00477 bool execute::out_ready(void)
00478 {
00479 bool value;
00480
00481 if (is_parent())
00482 value = check_read_ready_(out_fd());
00483 else
00484 value = check_write_ready_(out_fd());
00485
00486 return(value);
00487 }
00488
00489
00490
00491
00492
00493
00494
00495
00496
00497 bool execute::err_ready(void)
00498 {
00499 bool value;
00500
00501 if (is_parent())
00502 value = check_read_ready_(err_fd());
00503 else
00504 value = check_write_ready_(err_fd());
00505
00506 return(value);
00507 }
00508
00509
00510 bool execute::in_eof(void)
00511 {
00512 return(m_in_eof);
00513 }
00514
00515
00516 bool execute::out_eof(void)
00517 {
00518 return(m_out_eof);
00519 }
00520
00521
00522 bool execute::err_eof(void)
00523 {
00524 return(m_err_eof);
00525 }
00526
00527
00528 int execute::in_read(char* buf, const int len)
00529 {
00530 int n;
00531 int err;
00532
00533 n = read(in_fd(), buf, len);
00534 err = errno;
00535 errno = 0;
00536 if (n > 0) {
00537 return(n);
00538 }
00539 if (child_started() && !child_running() && (err != EAGAIN))
00540 m_in_eof = true;
00541 return(0);
00542 }
00543
00544
00545 int execute::in_write(const char* buf, const int len)
00546 {
00547 int n;
00548 int err;
00549
00550 n = write(in_fd(), buf, len);
00551 err = errno;
00552 errno = 0;
00553 if (n > 0) {
00554 return(n);
00555 }
00556 if (child_started() && !child_running() && (err != EAGAIN))
00557 m_in_eof = true;
00558 return(0);
00559 }
00560
00561
00562 int execute::out_read(char* buf, const int len)
00563 {
00564 int n;
00565 int err;
00566
00567 n = read(out_fd(), buf, len);
00568 err = errno;
00569 errno = 0;
00570 if (n > 0) {
00571 return(n);
00572 }
00573 if (child_started() && !child_running() && (err != EAGAIN))
00574 m_out_eof = true;
00575 return(0);
00576 }
00577
00578
00579 int execute::out_write(const char* buf, const int len)
00580 {
00581 int n;
00582 int err;
00583
00584 n = write(out_fd(), buf, len);
00585 err = errno;
00586 errno = 0;
00587 if (n > 0) {
00588 return(n);
00589 }
00590 if (child_started() && !child_running() && (err != EAGAIN))
00591 m_out_eof = true;
00592 return(0);
00593 }
00594
00595
00596 int execute::err_read(char* buf, const int len)
00597 {
00598 int n;
00599 int err;
00600
00601 n = read(err_fd(), buf, len);
00602 err = errno;
00603 errno = 0;
00604 if (n > 0) {
00605 return(n);
00606 }
00607 if (child_started() && !child_running() && (err != EAGAIN))
00608 m_err_eof = true;
00609 return(0);
00610 }
00611
00612
00613 int execute::err_write(const char* buf, const int len)
00614 {
00615 int n;
00616 int err;
00617
00618 n = write(err_fd(), buf, len);
00619 err = errno;
00620 errno = 0;
00621 if (n > 0) {
00622 return(n);
00623 }
00624 if (child_started() && !child_running() && (err != EAGAIN))
00625 m_err_eof = true;
00626 return(0);
00627 }
00628
00629
00630 void execute::print(std::ostream& out)
00631 {
00632 out << "execute::is_child() = " << is_child() << std::endl;
00633 out << "execute::is_parent() = " << is_parent() << std::endl;
00634 out << "execute::my_pid() = " << my_pid() << std::endl;
00635 out << "execute::child_running() = " << child_running() << std::endl;
00636 out << "execute::child_exited() = " << child_exited() << std::endl;
00637 out << "execute::child_exited_normally() = " << child_exited_normally()
00638 << std::endl;
00639 out << "execute::child_signaled() = " << child_signaled() << std::endl;
00640 out << "execute::child_exit_code() = " << child_exit_code() << std::endl;
00641 out << "execute::child_signal_no() = " << child_signal_no() << std::endl;
00642 out << "execute::in_fd() = " << in_fd() << std::endl;
00643 out << "execute::out_fd() = " << out_fd() << std::endl;
00644 out << "execute::err_fd() = " << err_fd() << std::endl;
00645 out << "execute::in_ready() = " << in_ready() << std::endl;
00646 out << "execute::out_ready() = " << out_ready() << std::endl;
00647 out << "execute::err_ready() = " << err_ready() << std::endl;
00648 }
00649
00650
00651 std::ostream& operator << (std::ostream& out, execute& exe)
00652 {
00653 exe.print(out);
00654
00655 return(out);
00656 }
00657