process.c 3.7 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206
  1. /*
  2. * Copyright (c) 2009-2011 Nokia Corporation and/or its subsidiary(-ies).
  3. * All rights reserved.
  4. * This component and the accompanying materials are made available
  5. * under the terms of the License "Eclipse Public License v1.0"
  6. * which accompanies this distribution, and is available
  7. * at the URL "http://www.eclipse.org/legal/epl-v10.html".
  8. *
  9. * Initial Contributors:
  10. * Nokia Corporation - initial contribution.
  11. *
  12. * Contributors:
  13. *
  14. * Description:
  15. *
  16. */
  17. #include <unistd.h>
  18. #include "process.h"
  19. #include "buffer.h"
  20. #include <stdlib.h>
  21. #include <string.h>
  22. #include <poll.h>
  23. #include <signal.h>
  24. #include <errno.h>
  25. #include <sys/wait.h>
  26. #include "log.h"
  27. proc *process_new(void)
  28. {
  29. proc *p = malloc(sizeof(proc));
  30. p->output = buffer_new();
  31. if (!p->output)
  32. {
  33. free(p);
  34. return NULL;
  35. }
  36. p->starttime = 0;
  37. p->endtime = 0;
  38. p->returncode = 1;
  39. p->pid = 0;
  40. p->causeofdeath = PROC_NORMALDEATH;
  41. return p;
  42. }
  43. void childsig(int sig)
  44. {
  45. //wait(&stat_loc);
  46. DEBUG(("SIGCHLD\n"));
  47. }
  48. struct sigaction child_action;
  49. proc *process_run(char executable[], char *args[], int timeout)
  50. {
  51. proc *p = process_new();
  52. if (p == NULL)
  53. return NULL;
  54. int status;
  55. int stdout_p[2];
  56. int stderr_p[2];
  57. child_action.sa_handler = childsig;
  58. sigemptyset (&child_action.sa_mask);
  59. child_action.sa_flags = 0;
  60. sigaction (SIGCHLD, &child_action, NULL);
  61. pipe(stdout_p);
  62. pipe(stderr_p);
  63. pid_t child = fork();
  64. if (child == 0)
  65. {
  66. close(stdout_p[0]);
  67. dup2(stdout_p[1], 1);
  68. close(stdout_p[1]);
  69. close(stderr_p[0]);
  70. dup2(stderr_p[1], 2);
  71. close(stderr_p[1]);
  72. execvp(executable, args);
  73. exit(1);
  74. } else if (child == -1) {
  75. p->causeofdeath = PROC_SOMEODDDEATH;
  76. return p;
  77. }
  78. else
  79. {
  80. close(stdout_p[1]);
  81. close(stderr_p[1]);
  82. p->pid = child;
  83. DEBUG(("child running\n"));
  84. }
  85. struct pollfd pf[2];
  86. int pv;
  87. do
  88. {
  89. pf[0].fd = stdout_p[0];
  90. pf[1].fd = stderr_p[0];
  91. pf[0].events = POLLIN;
  92. pf[0].revents = 0;
  93. pf[1].events = POLLIN;
  94. pf[1].revents = 0;
  95. DEBUG(("polling\n"));
  96. pv = poll(pf, 2, timeout);
  97. DEBUG(("polled %d\n", pv));
  98. if (pv == -1)
  99. {
  100. if (errno == EAGAIN)
  101. {
  102. errno = 0;
  103. DEBUG(("errno: \n"));
  104. continue;
  105. } else {
  106. /* EINVAL - can't poll */
  107. process_free(&p);
  108. return NULL;
  109. }
  110. } else if (pv == 0 ) {
  111. /* timeout */
  112. DEBUG(("timeout: \n"));
  113. kill(p->pid, SIGTERM);
  114. p->causeofdeath = PROC_TIMEOUTDEATH;
  115. break;
  116. }
  117. if (pf[0].revents & POLLIN )
  118. {
  119. char *space = buffer_makespace(p->output, 1024);
  120. int nbytes = read(pf[0].fd, space, 1024);
  121. if (nbytes < 0)
  122. break;
  123. buffer_usespace(p->output, nbytes);
  124. }
  125. if (pf[1].revents & POLLIN )
  126. {
  127. char *space = buffer_makespace(p->output, 1024);
  128. int nbytes = read(pf[1].fd, space, 1024);
  129. if (nbytes < 0)
  130. break;
  131. buffer_usespace(p->output, nbytes);
  132. }
  133. if (pf[0].revents & (POLLERR | POLLHUP | POLLNVAL))
  134. {
  135. DEBUG(("stdout: pollerr %d\n", pf[0].revents));
  136. break;
  137. }
  138. if ( pf[1].revents & (POLLERR | POLLHUP | POLLNVAL))
  139. {
  140. DEBUG(("stderr: pollerr %d\n", pf[1].revents));
  141. break;
  142. }
  143. DEBUG(("events: %d %d \n", pf[0].revents, pf[1].revents));
  144. }
  145. while (1);
  146. waitpid(p->pid, &status, 0);
  147. if (WIFEXITED(status))
  148. {
  149. p->causeofdeath = PROC_NORMALDEATH;
  150. p->returncode = WEXITSTATUS(status);
  151. DEBUG(("process exited normally \n"));
  152. } else {
  153. if (p->causeofdeath == PROC_TIMEOUTDEATH)
  154. p->returncode = 128;
  155. else {
  156. p->causeofdeath = PROC_SOMEODDDEATH;
  157. if (WIFSIGNALED(status))
  158. p->returncode = WTERMSIG(status);
  159. else
  160. p->returncode = 128;
  161. }
  162. DEBUG(("process terminated \n"));
  163. }
  164. return p;
  165. }
  166. void process_free(proc **pp)
  167. {
  168. if (!pp)
  169. return;
  170. if (! *pp)
  171. return;
  172. if ((*pp)->output)
  173. buffer_free(&((*pp)->output));
  174. free(*pp);
  175. *pp = NULL;
  176. }