mxlib
c++ tools for analyzing astronomical data and other tasks by Jared R. Males. [git repo]
processInterface.cpp
Go to the documentation of this file.
1 /** \file processInterface.cpp
2  * \author Jared R. Males (jaredmales@gmail.com)
3  * \brief Process interface facilities
4  * \ingroup IPC
5  *
6 */
7 
8 //***********************************************************************//
9 // Copyright 2021 Jared R. Males (jaredmales@gmail.com)
10 //
11 // This file is part of mxlib.
12 //
13 // mxlib is free software: you can redistribute it and/or modify
14 // it under the terms of the GNU General Public License as published by
15 // the Free Software Foundation, either version 3 of the License, or
16 // (at your option) any later version.
17 //
18 // mxlib is distributed in the hope that it will be useful,
19 // but WITHOUT ANY WARRANTY; without even the implied warranty of
20 // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
21 // GNU General Public License for more details.
22 //
23 // You should have received a copy of the GNU General Public License
24 // along with mxlib. If not, see <http://www.gnu.org/licenses/>.
25 //***********************************************************************//
26 
27 #include "ipc/processInterface.hpp"
28 #include "mxError.hpp"
29 
30 #include <cstring>
31 #include <sstream>
32 #include <cstdio>
33 #include <iostream>
34 
35 #include <unistd.h>
36 #include <sys/wait.h>
37 
38 namespace mx
39 {
40 namespace ipc
41 {
42 
43 int command_response( const char * cmd,
44  char * resp,
45  size_t respsz
46  )
47 {
48  FILE *cmd_ptr;
49 
50  if ( (cmd_ptr = popen(cmd, "r")) != NULL)
51  {
52  size_t written = 0;
53 
54  char buf[MX_IPC_PI_BUFSZ];
55 
56  while (fgets(buf, MX_IPC_PI_BUFSZ, cmd_ptr) != NULL && written+1 < respsz)
57  {
58  strcat(resp, buf);
59  written = strlen(resp);
60  }
61  pclose(cmd_ptr);
62  }
63  else
64  {
65  return -1;
66  }
67 
68  return 0;
69 }
70 
71 int runCommand( int & retVal, // [out] the return value of the process. Only meaningful if this returns 0.
72  std::vector<std::string> & commandOutput, // [out] the output, line by line. If an error, first entry contains the message.
73  std::vector<std::string> & commandStderr, // [out] the output of stderr.
74  const std::vector<std::string> & commandList // [in] command to be run, with one entry per command line word
75  )
76 {
77  int link[2];
78  int errlink[2];
79 
80  pid_t pid;
81 
82  if (pipe(link)==-1)
83  {
84  mxPError("mx::ipc::runCommand",errno, "piping stdout");
85  return -1;
86  }
87 
88  if (pipe(errlink)==-1)
89  {
90  mxPError("mx::ipc::runCommand",errno, "piping stderr");
91  return -1;
92  }
93 
94  if ((pid = fork()) == -1)
95  {
96  mxPError("mx::ipc::runCommand",errno, "forking");
97  return -1;
98  }
99 
100  if(pid == 0)
101  {
102  if(dup2 (link[1], STDOUT_FILENO) < 0)
103  {
104  mxPError("mx::ipc::runCommand",errno, "dup2");
105  return -1;
106  }
107 
108  if(close(link[0]) < 0)
109  {
110  mxPError("mx::ipc::runCommand",errno, "close");
111  return -1;
112  }
113 
114  if(close(link[1]) < 0)
115  {
116  mxPError("mx::ipc::runCommand",errno, "close");
117  return -1;
118  }
119 
120  if(dup2(errlink[1], STDERR_FILENO) < 0)
121  {
122  mxPError("mx::ipc::runCommand",errno, "dup2");
123  return -1;
124  }
125 
126  if(close(errlink[0]) < 0)
127  {
128  mxPError("mx::ipc::runCommand",errno, "close");
129  return -1;
130  }
131 
132  if(close(errlink[1]) < 0)
133  {
134  mxPError("mx::ipc::runCommand",errno, "close");
135  return -1;
136  }
137 
138  std::vector<const char *> charCommandList( commandList.size()+1, NULL);
139 
140  for(int index = 0; index < (int) commandList.size(); ++index)
141  {
142  charCommandList[index]=commandList[index].c_str();
143  }
144  execvp( charCommandList[0], const_cast<char**>(charCommandList.data()));
145 
146  mxPError("mx::ipc::runCommand", errno, "execvp returned");
147 
148  return -1;
149  }
150  else
151  {
152  char commandOutput_c[4096];
153 
154  int status;
155 
156  pid_t rvid = waitpid(pid, &status, 0);
157 
158  if(rvid < 0)
159  {
160  mxPError("mx::ipc::runCommand", errno, "waitpid");
161  return -1;
162  }
163 
164  if(WIFEXITED(status))
165  {
166  retVal = WEXITSTATUS(status);
167  }
168  else
169  {
170  mxError("mx::ipc::runCommand", MXE_PROCERR, "child did not exit");
171  return -1;
172  }
173 
174  if( close(link[1]) < 0 )
175  {
176  mxPError("mx::ipc::runCommand", errno, "close");
177  return -1;
178  }
179 
180  if( close(errlink[1]) < 0 )
181  {
182  mxPError("mx::ipc::runCommand", errno, "close");
183  return -1;
184  }
185 
186  int rd;
187  if ( (rd = read(link[0], commandOutput_c, sizeof(commandOutput_c))) < 0)
188  {
189  mxPError("mx::ipc::runCommand", errno, "read");
190 
191  if(close(errlink[0])< 0) mxPError("mx::ipc::runCommand", errno, "close");
192  if(close(link[0]) < 0) mxPError("mx::ipc::runCommand", errno, "close");
193 
194  return -1;
195  }
196 
197  if( close(link[0]) < 0)
198  {
199  mxPError("mx::ipc::runCommand", errno, "close");
200  if(close(errlink[0])< 0) mxPError("mx::ipc::runCommand", errno, "close");
201  return -1;
202  }
203 
204  std::string line;
205 
206  commandOutput_c[rd] = '\0';
207  std::string commandOutputString(commandOutput_c);
208 
209  std::istringstream iss(commandOutputString);
210 
211  while (getline(iss, line))
212  {
213  commandOutput.push_back(line);
214  }
215 
216  //----stderr
217  if ( (rd = read(errlink[0], commandOutput_c, sizeof(commandOutput_c))) < 0)
218  {
219  commandStderr.push_back(std::string("Read error on stderr: ") + strerror(errno));
220  if(close(errlink[0])< 0) mxPError("mx::ipc::runCommand", errno, "close");
221  return -1;
222  }
223 
224  if(close(errlink[0]) < 0)
225  {
226  mxPError("mx::ipc::runCommand", errno, "close");
227  return -1;
228  }
229 
230  commandOutput_c[rd] = '\0';
231  commandOutputString = commandOutput_c;
232 
233  std::istringstream iss2(commandOutputString);
234 
235  while (getline(iss2, line))
236  {
237  commandStderr.push_back(line);
238  }
239 
240  return 0;
241  }
242 }
243 
244 }//namespace ipc
245 } //namespace mx
246 
int command_response(const char *cmd, char *resp, size_t respsz)
Run a process and copy the output to a string.
int runCommand(int &retVal, std::vector< std::string > &commandOutput, std::vector< std::string > &commandStderr, const std::vector< std::string > &commandList)
Runs a command (with parameters) passed in using fork/exec.
Declares and defines the mxlib error reporting system.
The mxlib c++ namespace.
Definition: mxError.hpp:107
Process interface facilities.