Line data Source code
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 "mxlib.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 0 : int command_response( const char *cmd, char *resp, size_t respsz )
44 : {
45 : FILE *cmd_ptr;
46 :
47 0 : if( ( cmd_ptr = popen( cmd, "r" ) ) != NULL )
48 : {
49 0 : size_t written = 0;
50 :
51 : char buf[MX_IPC_PI_BUFSZ];
52 :
53 0 : while( fgets( buf, MX_IPC_PI_BUFSZ, cmd_ptr ) != NULL && written + 1 < respsz )
54 : {
55 0 : strcat( resp, buf );
56 0 : written = strlen( resp );
57 : }
58 0 : pclose( cmd_ptr );
59 : }
60 : else
61 : {
62 0 : return -1;
63 : }
64 :
65 0 : return 0;
66 : }
67 :
68 0 : int runCommand(
69 : int &retVal, // [out] the return value of the process. Only meaningful if this returns 0.
70 : std::vector<std::string>
71 : &commandOutput, // [out] the output, line by line. If an error, first entry contains the message.
72 : std::vector<std::string> &commandStderr, // [out] the output of stderr.
73 : const std::vector<std::string> &commandList // [in] command to be run, with one entry per command line word
74 : )
75 : {
76 : int link[2];
77 : int errlink[2];
78 :
79 : pid_t pid;
80 :
81 0 : if( pipe( link ) == -1 )
82 : {
83 0 : internal::mxlib_error_report(errno2error_t(errno), "piping stdout" );
84 0 : return -1;
85 : }
86 :
87 0 : if( pipe( errlink ) == -1 )
88 : {
89 0 : internal::mxlib_error_report(errno2error_t(errno), "piping stderr" );
90 0 : return -1;
91 : }
92 :
93 0 : if( ( pid = fork() ) == -1 )
94 : {
95 0 : internal::mxlib_error_report(errno2error_t(errno), "forking" );
96 0 : return -1;
97 : }
98 :
99 0 : if( pid == 0 )
100 : {
101 0 : if( dup2( link[1], STDOUT_FILENO ) < 0 )
102 : {
103 0 : internal::mxlib_error_report(errno2error_t(errno), "dup2" );
104 0 : return -1;
105 : }
106 :
107 0 : if( close( link[0] ) < 0 )
108 : {
109 0 : internal::mxlib_error_report(errno2error_t(errno), "close" );
110 0 : return -1;
111 : }
112 :
113 0 : if( close( link[1] ) < 0 )
114 : {
115 0 : internal::mxlib_error_report(errno2error_t(errno), "close" );
116 0 : return -1;
117 : }
118 :
119 0 : if( dup2( errlink[1], STDERR_FILENO ) < 0 )
120 : {
121 0 : internal::mxlib_error_report(errno2error_t(errno), "dup2" );
122 0 : return -1;
123 : }
124 :
125 0 : if( close( errlink[0] ) < 0 )
126 : {
127 0 : internal::mxlib_error_report(errno2error_t(errno), "close" );
128 0 : return -1;
129 : }
130 :
131 0 : if( close( errlink[1] ) < 0 )
132 : {
133 0 : internal::mxlib_error_report(errno2error_t(errno), "close" );
134 0 : return -1;
135 : }
136 :
137 0 : std::vector<const char *> charCommandList( commandList.size() + 1, NULL );
138 :
139 0 : for( int index = 0; index < (int)commandList.size(); ++index )
140 : {
141 0 : charCommandList[index] = commandList[index].c_str();
142 : }
143 0 : execvp( charCommandList[0], const_cast<char **>( charCommandList.data() ) );
144 :
145 0 : internal::mxlib_error_report(errno2error_t(errno), "execvp returned" );
146 :
147 0 : return -1;
148 0 : }
149 : else
150 : {
151 : char commandOutput_c[4096];
152 :
153 : int status;
154 :
155 0 : pid_t rvid = waitpid( pid, &status, 0 );
156 :
157 0 : if( rvid < 0 )
158 : {
159 0 : internal::mxlib_error_report( errno2error_t( errno ), "waitpid" );
160 0 : return -1;
161 : }
162 :
163 0 : if( WIFEXITED( status ) )
164 : {
165 0 : retVal = WEXITSTATUS( status );
166 : }
167 : else
168 : {
169 0 : internal::mxlib_error_report( error_t::procerr, "child did not exit" );
170 0 : return -1;
171 : }
172 :
173 0 : if( close( link[1] ) < 0 )
174 : {
175 0 : internal::mxlib_error_report( errno2error_t( errno ), "close" );
176 0 : return -1;
177 : }
178 :
179 0 : if( close( errlink[1] ) < 0 )
180 : {
181 0 : internal::mxlib_error_report( errno2error_t( errno ), "close" );
182 0 : return -1;
183 : }
184 :
185 : int rd;
186 0 : if( ( rd = read( link[0], commandOutput_c, sizeof( commandOutput_c ) ) ) < 0 )
187 : {
188 0 : internal::mxlib_error_report( errno2error_t( errno ), "read" );
189 :
190 0 : if( close( errlink[0] ) < 0 )
191 : {
192 0 : internal::mxlib_error_report( errno2error_t( errno ), "close" );
193 : }
194 0 : if( close( link[0] ) < 0 )
195 : {
196 0 : internal::mxlib_error_report( errno2error_t( errno ), "close" );
197 : }
198 :
199 0 : return -1;
200 : }
201 :
202 0 : if( close( link[0] ) < 0 )
203 : {
204 0 : internal::mxlib_error_report( errno2error_t( errno ), "close" );
205 0 : if( close( errlink[0] ) < 0 )
206 : {
207 0 : internal::mxlib_error_report( errno2error_t( errno ), "close" );
208 : }
209 0 : return -1;
210 : }
211 :
212 0 : std::string line;
213 :
214 0 : commandOutput_c[rd] = '\0';
215 0 : std::string commandOutputString( commandOutput_c );
216 :
217 0 : std::istringstream iss( commandOutputString );
218 :
219 0 : while( getline( iss, line ) )
220 : {
221 0 : commandOutput.push_back( line );
222 : }
223 :
224 : //----stderr
225 0 : if( ( rd = read( errlink[0], commandOutput_c, sizeof( commandOutput_c ) ) ) < 0 )
226 : {
227 0 : commandStderr.push_back( std::string( "Read error on stderr: " ) + strerror( errno ) );
228 0 : if( close( errlink[0] ) < 0 ){internal::mxlib_error_report(errno2error_t(errno), "close" );}
229 0 : return -1;
230 : }
231 :
232 0 : if( close( errlink[0] ) < 0 )
233 : {
234 0 : internal::mxlib_error_report(errno2error_t(errno), "close" );
235 0 : return -1;
236 : }
237 :
238 0 : commandOutput_c[rd] = '\0';
239 0 : commandOutputString = commandOutput_c;
240 :
241 0 : std::istringstream iss2( commandOutputString );
242 :
243 0 : while( getline( iss2, line ) )
244 : {
245 0 : commandStderr.push_back( line );
246 : }
247 :
248 0 : return 0;
249 0 : }
250 : }
251 :
252 : } // namespace ipc
253 : } // namespace mx
|