cprover
run.cpp
Go to the documentation of this file.
1 /*******************************************************************\
2 
3 Module:
4 
5 Author: Daniel Kroening
6 
7 Date: August 2012
8 
9 \*******************************************************************/
10 
11 #include "run.h"
12 
13 #ifdef _WIN32
14 #include <process.h>
15 #else
16 
17 #include <cstring>
18 #include <unistd.h>
19 #include <cerrno>
20 #include <cstdio>
21 #include <cstdlib>
22 
23 #include <sys/wait.h>
24 #include <sys/types.h>
25 #include <sys/stat.h>
26 #include <fcntl.h>
27 #include <signal.h>
28 
29 #endif
30 
31 #include <util/invariant.h>
32 #include <util/unicode.h>
33 #include <util/signal_catcher.h>
34 
35 int run_shell(const std::string &command)
36 {
37  std::string shell="/bin/sh";
38  std::vector<std::string> argv;
39  argv.push_back(shell);
40  argv.push_back(command);
41  return run(shell, argv, "", "", "");
42 }
43 
44 #ifndef _WIN32
45 static int stdio_redirection(int fd, const std::string &file)
47 {
48  int result_fd = fd;
49 
50  if(file.empty())
51  return result_fd;
52 
53  int flags = 0, mode = 0;
54  std::string name;
55 
56  switch(fd)
57  {
58  case STDIN_FILENO:
59  flags = O_RDONLY;
60  name = "stdin";
61  break;
62 
63  case STDOUT_FILENO:
64  case STDERR_FILENO:
65  flags = O_CREAT | O_WRONLY;
66  mode = S_IRUSR | S_IWUSR;
67  name = fd == STDOUT_FILENO ? "stdout" : "stderr";
68  break;
69 
70  default:
72  }
73 
74  result_fd = open(file.c_str(), flags, mode);
75  if(result_fd == -1)
76  perror(("Failed to open " + name + " file " + file).c_str());
77 
78  return result_fd;
79 }
80 #endif
81 
82 int run(
83  const std::string &what,
84  const std::vector<std::string> &argv,
85  const std::string &std_input,
86  const std::string &std_output,
87  const std::string &std_error)
88 {
89  #ifdef _WIN32
90  // we don't support stdin/stdout/stderr redirection on Windows
91  PRECONDITION(std_input.empty());
92  PRECONDITION(std_output.empty());
93  PRECONDITION(std_error.empty());
94 
95  // unicode version of the arguments
96  std::vector<std::wstring> wargv;
97 
98  wargv.resize(argv.size());
99 
100  for(std::size_t i=0; i<argv.size(); i++)
101  wargv[i]=widen(argv[i]);
102 
103  std::vector<const wchar_t *> _argv(argv.size()+1);
104 
105  for(std::size_t i=0; i<wargv.size(); i++)
106  _argv[i]=wargv[i].c_str();
107 
108  _argv[argv.size()]=NULL;
109 
110  // warning: the arguments may still need escaping
111 
112  std::wstring wide_what=widen(what);
113 
114  int status=_wspawnvp(_P_WAIT, wide_what.c_str(), _argv.data());
115 
116  return status;
117 
118  #else
119  int stdin_fd = stdio_redirection(STDIN_FILENO, std_input);
120  int stdout_fd = stdio_redirection(STDOUT_FILENO, std_output);
121  int stderr_fd = stdio_redirection(STDERR_FILENO, std_error);
122 
123  if(stdin_fd == -1 || stdout_fd == -1 || stderr_fd == -1)
124  return 1;
125 
126  // temporarily suspend all signals
127  sigset_t new_mask, old_mask;
128  sigemptyset(&new_mask);
129  sigprocmask(SIG_SETMASK, &new_mask, &old_mask);
130 
131  /* now create new process */
132  pid_t childpid = fork();
133 
134  if(childpid>=0) /* fork succeeded */
135  {
136  if(childpid==0) /* fork() returns 0 to the child process */
137  {
138  // resume signals
140  sigprocmask(SIG_SETMASK, &old_mask, nullptr);
141 
142  std::vector<char *> _argv(argv.size()+1);
143  for(std::size_t i=0; i<argv.size(); i++)
144  _argv[i]=strdup(argv[i].c_str());
145 
146  _argv[argv.size()]=nullptr;
147 
148  if(stdin_fd!=STDIN_FILENO)
149  dup2(stdin_fd, STDIN_FILENO);
150  if(stdout_fd!=STDOUT_FILENO)
151  dup2(stdout_fd, STDOUT_FILENO);
152  if(stderr_fd != STDERR_FILENO)
153  dup2(stderr_fd, STDERR_FILENO);
154 
155  errno=0;
156  execvp(what.c_str(), _argv.data());
157 
158  /* usually no return */
159  perror(std::string("execvp "+what+" failed").c_str());
160  exit(1);
161  }
162  else /* fork() returns new pid to the parent process */
163  {
164  // resume signals
165  sigprocmask(SIG_SETMASK, &old_mask, nullptr);
166 
167  int status; /* parent process: child's exit status */
168 
169  /* wait for child to exit, and store its status */
170  while(waitpid(childpid, &status, 0)==-1)
171  if(errno==EINTR)
172  continue; // try again
173  else
174  {
175  perror("Waiting for child process failed");
176  if(stdin_fd!=STDIN_FILENO)
177  close(stdin_fd);
178  if(stdout_fd!=STDOUT_FILENO)
179  close(stdout_fd);
180  if(stderr_fd != STDERR_FILENO)
181  close(stderr_fd);
182  return 1;
183  }
184 
185  if(stdin_fd!=STDIN_FILENO)
186  close(stdin_fd);
187  if(stdout_fd!=STDOUT_FILENO)
188  close(stdout_fd);
189  if(stderr_fd != STDERR_FILENO)
190  close(stderr_fd);
191 
192  return WEXITSTATUS(status);
193  }
194  }
195  else /* fork returns -1 on failure */
196  {
197  // resume signals
198  sigprocmask(SIG_SETMASK, &old_mask, nullptr);
199 
200  if(stdin_fd!=STDIN_FILENO)
201  close(stdin_fd);
202  if(stdout_fd!=STDOUT_FILENO)
203  close(stdout_fd);
204  if(stderr_fd != STDERR_FILENO)
205  close(stderr_fd);
206 
207  return 1;
208  }
209  #endif
210 }
std::wstring widen(const char *s)
Definition: unicode.cpp:46
int run(const std::string &what, const std::vector< std::string > &argv, const std::string &std_input, const std::string &std_output, const std::string &std_error)
Definition: run.cpp:82
void remove_signal_catcher()
int run_shell(const std::string &command)
Definition: run.cpp:35
#define PRECONDITION(CONDITION)
Definition: invariant.h:242
static int stdio_redirection(int fd, const std::string &file)
open given file to replace either stdin, stderr, stdout
Definition: run.cpp:46
#define UNREACHABLE
Definition: invariant.h:271
Definition: kdev_t.h:19