XRootD
Loading...
Searching...
No Matches
XrdOucProg.cc
Go to the documentation of this file.
1/******************************************************************************/
2/* */
3/* X r d O u c P r o g . c c */
4/* */
5/* (c) 2004 by the Board of Trustees of the Leland Stanford, Jr., University */
6/* Produced by Andrew Hanushevsky for Stanford University under contract */
7/* DE-AC02-76-SFO0515 with the Deprtment of Energy */
8/* */
9/* This file is part of the XRootD software suite. */
10/* */
11/* XRootD is free software: you can redistribute it and/or modify it under */
12/* the terms of the GNU Lesser General Public License as published by the */
13/* Free Software Foundation, either version 3 of the License, or (at your */
14/* option) any later version. */
15/* */
16/* XRootD is distributed in the hope that it will be useful, but WITHOUT */
17/* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or */
18/* FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public */
19/* License for more details. */
20/* */
21/* You should have received a copy of the GNU Lesser General Public License */
22/* along with XRootD in a file called COPYING.LESSER (LGPL license) and file */
23/* COPYING (GPL license). If not, see <http://www.gnu.org/licenses/>. */
24/* */
25/* The copyright holder's institutional names and contributor's names may not */
26/* be used to endorse or promote products derived from this software without */
27/* specific prior written permission of the institution or contributor. */
28/******************************************************************************/
29
30#include <cerrno>
31#include <cstdio>
32#include <cstring>
33#ifndef WIN32
34#include <unistd.h>
35#include <sys/types.h>
36#include <sys/wait.h>
37#else
38#include <sys/types.h>
39#include "XrdSys/XrdWin32.hh"
40#endif
41
42#include "XrdOuc/XrdOucEnv.hh"
43#include "XrdOuc/XrdOucProg.hh"
45#include "XrdOuc/XrdOucUtils.hh"
46#include "XrdSys/XrdSysError.hh"
48
49/******************************************************************************/
50/* D e s t r u c t o r */
51/******************************************************************************/
52
54{
55 Reset();
56 if (myStream) delete myStream;
57}
58
59/******************************************************************************/
60/* F e e d */
61/******************************************************************************/
62
63int XrdOucProg::Feed(const char *data[], const int dlen[])
64{
65 static XrdSysMutex feedMutex;
66 XrdSysMutexHelper feedHelper;
67 int rc;
68
69// Make sure we have a stream
70//
71 if (!myStream) return EPIPE;
72 feedHelper.Lock(&feedMutex);
73
74// Check if this command is still running
75//
76 if (!myStream->isAlive() && !Restart())
77 {if (eDest) eDest->Emsg("Prog" "Unable to restart", Arg[0]);
78 return EPIPE;
79 }
80
81// Send the line to the program
82//
83 if (!myStream->Put((const char **)data, (const int *)dlen)) return 0;
84 if (eDest)
85 eDest->Emsg("Prog", myStream->LastError(), "feed", Arg[0]);
86 if ((rc = Restart()))
87 {if (eDest) eDest->Emsg("Prog", rc, "restart", Arg[0]);
88 return EPIPE;
89 }
90 if (!myStream->Put((const char **)data, (const int *)dlen)) return 0;
91 if (eDest)
92 eDest->Emsg("Prog", myStream->LastError(), "refeed", Arg[0]);
93 return EPIPE;
94}
95
96/******************************************************************************/
97/* R u n */
98/******************************************************************************/
99
100#define runWithVec(strmP, theRC)\
101 const char *argV[4]; int argC = 0;\
102 if (arg1) argV[argC++] = arg1;\
103 if (arg2) argV[argC++] = arg2;\
104 if (arg3) argV[argC++] = arg3;\
105 if (arg4) argV[argC++] = arg4;\
106 theRC = Run(strmP, argV, argC)
107
108int XrdOucProg::Run(XrdOucStream *Sp, const char *argV[], int argC,
109 const char *envV[]) const
110{
111 char **myArgs;
112 int rc, totArgs = numArgs + argC;
113
114// If we have no program, return an error
115//
116 if (!ArgBuff)
117 {if (eDest) eDest->Emsg("Run", "No program specified");
118 return -ENOEXEC;
119 }
120
121// Copy arguments to stack storage (we could avoid this but not with the stack).
122//
123 myArgs = (char**)alloca(sizeof(char *) * (totArgs + 1));
124 if (numArgs) memcpy(myArgs, Arg, sizeof(char*)*numArgs);
125 if (argC) memcpy(&myArgs[numArgs], argV, sizeof(char*)*argC);
126 myArgs[totArgs] = 0;
127
128// If this is a local process then just execute it inline on this thread
129//
130 if (myProc) return (*myProc)(Sp, myArgs, totArgs);
131
132// Execute the command, possibly setting an environment.
133//
134 if (envV)
135 {XrdOucEnv progEnv, *oldEnv = Sp->SetEnv(&progEnv);
136 progEnv.PutPtr("XrdEnvars**", (void *)envV);
137 rc = Sp->Exec(myArgs, 1, theEFD);
138 Sp->SetEnv(oldEnv);
139 } else rc = Sp->Exec(myArgs, 1, theEFD);
140
141// Diagnose any errors
142//
143 if (rc)
144 {rc = Sp->LastError();
145 if (eDest) eDest->Emsg("Run", rc, "execute", Arg[0]);
146 return -rc;
147 }
148
149// All done, caller will drain output
150//
151 return 0;
152}
153
154/******************************************************************************/
155
156int XrdOucProg::Run(const char *argV[], int argC, const char *envV[]) const
157{
158 XrdOucStream cmd;
159 char *lp;
160 int rc;
161
162// Execute the command
163//
164 rc = Run(&cmd, argV, argC, envV);
165 if (rc) return rc;
166
167// Drain all output
168//
169 while((lp = cmd.GetLine()))
170 if (eDest && *lp) eDest->Emsg("Run", lp);
171
172// All done
173//
174 return RunDone(cmd);
175}
176
177/******************************************************************************/
178
179int XrdOucProg::Run(XrdOucStream *Sp, const char *arg1, const char *arg2,
180 const char *arg3, const char *arg4) const
181{
182 int rc;
183
184// Execute the command
185//
186 runWithVec(Sp, rc);
187 return rc;
188}
189
190/******************************************************************************/
191
192int XrdOucProg::Run(const char *arg1, const char *arg2,
193 const char *arg3, const char *arg4) const
194{
195 XrdOucStream cmd;
196 char *lp;
197 int rc;
198
199// Execute the command
200//
201 runWithVec(&cmd, rc);
202 if (rc) return rc;
203
204// Drain all output
205//
206 while((lp = cmd.GetLine()))
207 if (eDest && *lp) eDest->Emsg("Run", lp);
208
209// All done
210//
211 return RunDone(cmd);
212}
213
214/******************************************************************************/
215
216int XrdOucProg::Run(char *outBuff, int outBsz,
217 const char *arg1, const char *arg2,
218 const char *arg3, const char *arg4) const
219{
220 XrdOucStream cmd;
221 char *lp, *tp;
222 int n, rc;
223
224// Execute the command
225//
226 runWithVec(&cmd, rc);
227 if (rc) return rc;
228
229// Drain the first line to the output buffer
230//
231 if (outBuff && outBsz > 0)
232 {if ((lp = cmd.GetLine()))
233 {while (*lp && *lp == ' ') lp++;
234 if ((n = strlen(lp)))
235 {tp = lp+n-1;
236 while(*tp-- == ' ') n--;
237 if (n >= outBsz) n = outBsz-1;
238 strncpy(outBuff, lp, n); outBuff += n;
239 }
240 }
241 *outBuff = 0;
242 }
243
244// Drain remaining output
245//
246 while((lp = cmd.GetLine())) {}
247
248// All done
249//
250 return RunDone(cmd);
251}
252
253/******************************************************************************/
254/* R u n D o n e */
255/******************************************************************************/
256
258{
259 int rc;
260
261// If this is an inline program then just return 0. There is no external process
262// and the return code was returned at the time the inline process was run.
263//
264 if (myProc) return 0;
265
266// Drain the command
267//
268 rc = cmd.Drain();
269
270// Determine ending status
271//
272 if (WIFSIGNALED(rc))
273 {if (eDest)
274 {char buff[16];
275 sprintf(buff, "%d", WTERMSIG(rc));
276 eDest->Emsg("Run", Arg[0], "killed by signal", buff);
277 }
278 return -EPIPE;
279 }
280 if (WIFEXITED(rc))
281 {rc = WEXITSTATUS(rc);
282 if (rc && eDest)
283 {char buff[16];
284 sprintf(buff, "%d", rc);
285 eDest->Emsg("Run", Arg[0], "ended with status", buff);
286 }
287 return -rc;
288 }
289 return 0; // We'll assume all went well here
290}
291
292/******************************************************************************/
293/* S e t u p */
294/******************************************************************************/
295
296int XrdOucProg::Setup(const char *prog, XrdSysError *errP,
297 int (*Proc)(XrdOucStream *, char **, int))
298{
299 static const int maxArgs = 65;
300 char *argV[maxArgs];
301 int rc;
302
303// Prepare to handle the program
304//
305 Reset();
306 if (!errP) errP = eDest;
307 myProc = 0;
308 ArgBuff = strdup(prog);
309
310// Construct the argv array based on passed command line.
311//
312 rc = XrdOucUtils::argList(ArgBuff, argV, maxArgs);
313 if (rc <= 0)
314 {if (errP)
315 {if (!rc || !argV[0])
316 {const char *pgm = (Proc ? "procedure" : "program");
317 errP->Emsg("Run", pgm, "name not specified.");
318 } else errP->Emsg("Run", rc, "set up", argV[0]);
319 }
320 return (rc ? rc : -EINVAL);
321 }
322
323// Record the arguments including the phamtom null pointer. We must have
324// atleast one, the program or procedure name.
325//
326 numArgs = rc;
327 Arg = new char*[rc+1];
328 memcpy(Arg, argV, sizeof(char *) * (rc+1));
329
330// If this is a local process then just record its address
331//
332 if ((myProc = Proc)) return 0;
333
334// Make sure the program is really executable
335//
336 if (access(Arg[0], X_OK))
337 {rc = errno;
338 if (errP) errP->Emsg("Run", rc, "set up", Arg[0]);
339 Reset();
340 return rc;
341 }
342 return 0;
343}
344
345/******************************************************************************/
346/* S t a r t */
347/******************************************************************************/
348
350{
351
352// Create a stream for this command (it is an eror if we are already started)
353//
354 if (myStream) return EBUSY;
355 if (!(myStream = new XrdOucStream(eDest))) return ENOMEM;
356
357// Execute the command and let it linger
358//
359 theEFD = 0;
360 return Run(myStream);
361}
362
363/******************************************************************************/
364/* P r i v a t e M e t h o d s */
365/******************************************************************************/
366/******************************************************************************/
367/* R e s e t */
368/******************************************************************************/
369
370void XrdOucProg::Reset()
371{
372
373 if (ArgBuff) {free(ArgBuff); ArgBuff = 0;}
374 if (numArgs) delete [] Arg;
375 Arg = &ArgBuff;
376 numArgs = 0;
377}
378
379/******************************************************************************/
380/* R e s t a r t */
381/******************************************************************************/
382
383int XrdOucProg::Restart()
384{
385 myStream->Close();
386 return Run(myStream);
387}
#define runWithVec(strmP, theRC)
#define access(a, b)
Definition XrdPosix.hh:44
void PutPtr(const char *varname, void *value)
Definition XrdOucEnv.cc:298
int Start(void)
int RunDone(XrdOucStream &cmd) const
int Run(XrdOucStream *Sp, const char *argV[], int argc=0, const char *envV[]=0) const
int Feed(const char *data[], const int dlen[])
Definition XrdOucProg.cc:63
int Setup(const char *prog, XrdSysError *errP=0, int(*Proc)(XrdOucStream *, char **, int)=0)
XrdOucEnv * SetEnv(XrdOucEnv *newEnv)
char * GetLine()
int Exec(const char *, int inrd=0, int efd=0)
static int argList(char *args, char **argV, int argC)
int Emsg(const char *esfx, int ecode, const char *text1, const char *text2=0)
void Lock(XrdSysMutex *Mutex)