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 pid_t value;
00198 value = waitpid(m_pid, &m_status, 0);
00199 }
00200 }
00201
00202
00203 pid_t execute::check_child_(void)
00204 {
00205 pid_t value;
00206
00207 errno = 0;
00208 value = waitpid(m_pid, &m_status, WNOHANG|WUNTRACED);
00209
00210 return(value);
00211 }
00212
00213
00214 bool execute::child_started(void) const
00215 {
00216 return(m_child_started);
00217 }
00218
00219
00220 bool execute::child_running(void)
00221 {
00222 pid_t pid;
00223
00224 pid = check_child_();
00225 if (pid > 0) return(false);
00226 if ((pid < 0) && (errno == ECHILD)) return(false);
00227 return(true);
00228 }
00229
00230
00231 bool execute::child_exited(void)
00232 {
00233 pid_t pid;
00234
00235 pid = check_child_();
00236 if (pid > 0) return(true);
00237 if ((pid < 0) && (errno == ECHILD)) return(true);
00238 return(false);
00239 }
00240
00241
00242 bool execute::child_exited_normally(void)
00243 {
00244 bool value;
00245
00246 value = (child_exited() && (child_exit_code() == 0));
00247
00248 return(value);
00249 }
00250
00251
00252 bool execute::child_signaled(void)
00253 {
00254 bool value;
00255
00256 check_child_();
00257 value = WIFSIGNALED(m_status);
00258
00259 return(value);
00260 }
00261
00262
00263 bool execute::child_exited_success(void)
00264 {
00265 bool value;
00266
00267 value = (child_exited() && (child_exit_code() == 0) && !child_signaled());
00268
00269 return(value);
00270 }
00271
00272
00273 int execute::child_exit_code(void)
00274 {
00275 int value;
00276
00277 check_child_();
00278 value = WEXITSTATUS(m_status);
00279
00280 return(value);
00281 }
00282
00283
00284 int execute::child_signal_no(void)
00285 {
00286 int value;
00287
00288 check_child_();
00289 if (child_exited()) {
00290 value = WTERMSIG(m_status);
00291 return(value);
00292 }
00293 else {
00294 value = WSTOPSIG(m_status);
00295 return(value);
00296 }
00297 }
00298
00299
00300
00301
00302
00303
00304
00305
00306
00307 int execute::in_fd(void)
00308 {
00309 if (is_parent()) {
00310
00311 return(m_fd1[1]);
00312 }
00313 else {
00314
00315 return(m_fd1[0]);
00316 }
00317 }
00318
00319
00320
00321
00322
00323
00324
00325
00326
00327 int execute::out_fd(void)
00328 {
00329 if (is_parent()) {
00330
00331 return(m_fd2[0]);
00332 }
00333 else {
00334
00335 return(m_fd2[1]);
00336 }
00337 }
00338
00339
00340
00341
00342
00343
00344
00345
00346
00347 int execute::err_fd(void)
00348 {
00349 if (is_parent()) {
00350
00351 return(m_fd3[0]);
00352 }
00353 else {
00354
00355 return(m_fd3[1]);
00356 }
00357 }
00358
00359
00360 bool execute::check_write_ready_(int fd)
00361 {
00362 struct timeval timeout = { 0, 0 };
00363 fd_set wset;
00364
00365 FD_ZERO(&wset);
00366 FD_SET(fd, &wset);
00367 select(fd+1, 0, &wset, 0, &timeout);
00368 if (FD_ISSET(fd, &wset)) {
00369 return(true);
00370 }
00371 return(false);
00372 }
00373
00374
00375 bool execute::check_read_ready_(int fd)
00376 {
00377 struct timeval timeout = { 0, 0 };
00378 fd_set rset;
00379
00380 FD_ZERO(&rset);
00381 FD_SET(fd, &rset);
00382 select(fd+1, &rset, 0, 0, &timeout);
00383 if (FD_ISSET(fd, &rset)) {
00384 return(true);
00385 }
00386 return(false);
00387 }
00388
00389
00390 void execute::exec(const std::string command)
00391 {
00392 fork();
00393 if (is_parent())
00394 return;
00395
00396
00397
00398
00399
00400
00401
00402
00403
00404
00405 reroute_stdio();
00406
00407 execl("/bin/sh", "sh", "-c", command.c_str(), (char *)0);
00408 exit(127);
00409 }
00410
00411
00412 void execute::exec(const std::string binary, const std::vector<std::string> argv)
00413 {
00414 char *bin = 0;
00415 char *base = 0;
00416 char **args = 0;
00417 uint16 c;
00418 size_t size;
00419
00420 fork();
00421 if (is_parent())
00422 return;
00423
00424
00425
00426
00427
00428
00429
00430
00431
00432
00433
00434 reroute_stdio();
00435
00436 bin = (char *)binary.c_str();
00437 base = bin+strlen(bin);
00438 while ((base > bin) && (*base != '/')) {
00439 base--;
00440 }
00441 if (*base == '/') {
00442 base++;
00443 }
00444 size = (argv.size() + 2) * sizeof(char *);
00445 args = (char **)malloc(size);
00446 memset((void *)args, 0, size);
00447 if (args == 0) {
00448 exit(127);
00449 }
00450 args[0] = base;
00451 for (c = 0; c < argv.size(); c++) {
00452 args[c+1] = (char *)argv[c].c_str();
00453 }
00454 args[c+1] = 0;
00455
00456 execv(bin, args);
00457 exit(127);
00458 }
00459
00460
00461
00462
00463
00464
00465
00466
00467
00468 bool execute::in_ready(void)
00469 {
00470 bool value;
00471
00472 if (is_parent())
00473 value = check_write_ready_(in_fd());
00474 else
00475 value = check_read_ready_(in_fd());
00476
00477 return(value);
00478 }
00479
00480
00481
00482
00483
00484
00485
00486
00487
00488 bool execute::out_ready(void)
00489 {
00490 bool value;
00491
00492 if (is_parent())
00493 value = check_read_ready_(out_fd());
00494 else
00495 value = check_write_ready_(out_fd());
00496
00497 return(value);
00498 }
00499
00500
00501
00502
00503
00504
00505
00506
00507
00508 bool execute::err_ready(void)
00509 {
00510 bool value;
00511
00512 if (is_parent())
00513 value = check_read_ready_(err_fd());
00514 else
00515 value = check_write_ready_(err_fd());
00516
00517 return(value);
00518 }
00519
00520
00521 bool execute::in_eof(void)
00522 {
00523 return(m_in_eof);
00524 }
00525
00526
00527 bool execute::out_eof(void)
00528 {
00529 return(m_out_eof);
00530 }
00531
00532
00533 bool execute::err_eof(void)
00534 {
00535 return(m_err_eof);
00536 }
00537
00538
00539 int execute::in_read(char* buf, const int len)
00540 {
00541 int n;
00542 int err;
00543
00544 n = read(in_fd(), buf, len);
00545 err = errno;
00546 errno = 0;
00547 if (n > 0) {
00548 return(n);
00549 }
00550 if (child_started() && !child_running() && (err != EAGAIN))
00551 m_in_eof = true;
00552 return(0);
00553 }
00554
00555
00556 int execute::in_write(const char* buf, const int len)
00557 {
00558 int n;
00559 int err;
00560
00561 n = write(in_fd(), buf, len);
00562 err = errno;
00563 errno = 0;
00564 if (n > 0) {
00565 return(n);
00566 }
00567 if (child_started() && !child_running() && (err != EAGAIN))
00568 m_in_eof = true;
00569 return(0);
00570 }
00571
00572
00573 int execute::out_read(char* buf, const int len)
00574 {
00575 int n;
00576 int err;
00577
00578 n = read(out_fd(), buf, len);
00579 err = errno;
00580 errno = 0;
00581 if (n > 0) {
00582 return(n);
00583 }
00584 if (child_started() && !child_running() && (err != EAGAIN))
00585 m_out_eof = true;
00586 return(0);
00587 }
00588
00589
00590 int execute::out_write(const char* buf, const int len)
00591 {
00592 int n;
00593 int err;
00594
00595 n = write(out_fd(), buf, len);
00596 err = errno;
00597 errno = 0;
00598 if (n > 0) {
00599 return(n);
00600 }
00601 if (child_started() && !child_running() && (err != EAGAIN))
00602 m_out_eof = true;
00603 return(0);
00604 }
00605
00606
00607 int execute::err_read(char* buf, const int len)
00608 {
00609 int n;
00610 int err;
00611
00612 n = read(err_fd(), buf, len);
00613 err = errno;
00614 errno = 0;
00615 if (n > 0) {
00616 return(n);
00617 }
00618 if (child_started() && !child_running() && (err != EAGAIN))
00619 m_err_eof = true;
00620 return(0);
00621 }
00622
00623
00624 int execute::err_write(const char* buf, const int len)
00625 {
00626 int n;
00627 int err;
00628
00629 n = write(err_fd(), buf, len);
00630 err = errno;
00631 errno = 0;
00632 if (n > 0) {
00633 return(n);
00634 }
00635 if (child_started() && !child_running() && (err != EAGAIN))
00636 m_err_eof = true;
00637 return(0);
00638 }
00639
00640
00641 void execute::print(std::ostream& out)
00642 {
00643 out << "execute::is_child() = " << is_child() << std::endl;
00644 out << "execute::is_parent() = " << is_parent() << std::endl;
00645 out << "execute::my_pid() = " << my_pid() << std::endl;
00646 out << "execute::child_running() = " << child_running() << std::endl;
00647 out << "execute::child_exited() = " << child_exited() << std::endl;
00648 out << "execute::child_exited_normally() = " << child_exited_normally()
00649 << std::endl;
00650 out << "execute::child_exited_success() = " << child_exited_success()
00651 << std::endl;
00652 out << "execute::child_signaled() = " << child_signaled() << std::endl;
00653 out << "execute::child_exit_code() = " << child_exit_code() << std::endl;
00654 out << "execute::child_signal_no() = " << child_signal_no() << std::endl;
00655 out << "execute::in_fd() = " << in_fd() << std::endl;
00656 out << "execute::out_fd() = " << out_fd() << std::endl;
00657 out << "execute::err_fd() = " << err_fd() << std::endl;
00658 out << "execute::in_ready() = " << in_ready() << std::endl;
00659 out << "execute::out_ready() = " << out_ready() << std::endl;
00660 out << "execute::err_ready() = " << err_ready() << std::endl;
00661 }
00662
00663
00664 std::ostream& operator << (std::ostream& out, execute& exe)
00665 {
00666 exe.print(out);
00667
00668 return(out);
00669 }
00670