XRootD
XrdOucStream.cc
Go to the documentation of this file.
1 /******************************************************************************/
2 /* */
3 /* X r d O u c S t r e a m . 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 <cctype>
31 #include <fcntl.h>
32 #include <cstdlib>
33 #include <cstring>
34 #include <cstdio>
35 #ifndef WIN32
36 #include <poll.h>
37 #include <unistd.h>
38 #include <strings.h>
39 #if !defined(__linux__) && !defined(__CYGWIN__) && !defined(__GNU__) && !defined(__FreeBSD__)
40 #include <sys/conf.h>
41 #endif
42 #include <sys/stat.h>
43 #include <termios.h>
44 #include <sys/types.h>
45 #include <sys/wait.h>
46 #else // WIN32
47 #include "XrdSys/XrdWin32.hh"
48 #include <process.h>
49 #endif // WIN32
50 
51 #include <set>
52 #include <string>
53 
54 #include "XrdOuc/XrdOucEnv.hh"
55 #include "XrdOuc/XrdOucNSWalk.hh"
56 #include "XrdOuc/XrdOucString.hh"
57 #include "XrdOuc/XrdOucStream.hh"
58 #include "XrdOuc/XrdOucTList.hh"
59 #include "XrdOuc/XrdOucUtils.hh"
60 #include "XrdSys/XrdSysE2T.hh"
61 #include "XrdSys/XrdSysFD.hh"
62 #include "XrdSys/XrdSysHeaders.hh"
63 #include "XrdSys/XrdSysLogger.hh"
64 #include "XrdSys/XrdSysPlatform.hh"
65 #include "XrdSys/XrdSysPthread.hh"
66 
67 /******************************************************************************/
68 /* l o c a l d e f i n e s */
69 /******************************************************************************/
70 
71 #define MaxARGC 64
72 #define XrdOucStream_EOM 0x01
73 #define XrdOucStream_BUSY 0x02
74 #define XrdOucStream_ELIF 0x80
75 
76 #define XrdOucStream_CADD 0x010000
77 #define XrdOucStream_CONT 0xff0000
78 #define XrdOucStream_CMAX 0x0f0000
79 
80 #define Erq(p, a, b) Err(p, a, b, (char *)0)
81 #define Err(p, a, b, c) (ecode=(Eroute ? Eroute->Emsg(#p, a, b, c) : a), -1)
82 #define Erp(p, a, b, c) ecode=(Eroute ? Eroute->Emsg(#p, a, b, c) : a)
83 
84 // The following is used by child processes prior to exec() to avoid deadlocks
85 //
86 #define Erx(p, a, b) std::cerr <<#p <<": " <<XrdSysE2T(a) <<' ' <<b <<std::endl;
87 
88 /******************************************************************************/
89 /* S t a t i c M e m b e r s & O b j e c t s */
90 /******************************************************************************/
91 
92 // The following mutex is used to allow only one fork at a time so that
93 // we do not leak file descriptors. It is a short-lived lock.
94 //
95 namespace {XrdSysMutex forkMutex;}
96 
97 XrdOucString *XrdOucStream::theCFG = 0;
98 
99 /******************************************************************************/
100 /* L o c a l C l a s s e s */
101 /******************************************************************************/
102 
104  {char *myHost;
105  char *myName;
106  char *myExec;
107 
108  std::set<std::string> *fcList;
109  std::set<std::string>::iterator itFC;
110 
111  StreamInfo() : myHost(0), myName(0), myExec(0),
112  fcList(0) {}
113  ~StreamInfo() {if (fcList) delete fcList;}
114  };
115 
116 namespace
117 {
118 class contHandler
119 {
120 public:
121 
122 char *path;
123 XrdOucTList *tlP;
124 
125 void Add(const char *sfx) {tlP = new XrdOucTList(sfx,(int)strlen(sfx),tlP);}
126 
127  contHandler() : path(0), tlP(0) {}
128  ~contHandler() {XrdOucTList *tlN;
129  while(tlP) {tlN = tlP; tlP = tlP->next; delete tlN;}
130  if (path) free(path);
131  }
132 };
133 }
134 
135 /******************************************************************************/
136 /* L o c a l F u n c t i o n s */
137 /******************************************************************************/
138 
139 namespace
140 {
141 bool KeepFile(const char *fname, XrdOucTList *tlP)
142 {
143  struct sfxList {const char *txt; int len;};
144  static sfxList sfx[] = {{".cfsaved", 8},
145  {".rpmsave", 8},
146  {".rpmnew", 7},
147  {".dpkg-old", 9},
148  {".dpkg-dist", 10},
149  {"~", 1}
150  };
151  static int sfxLNum = sizeof(sfx)/sizeof(struct sfxList);
152  int n;
153 
154 // We don't keep file that start with a dot
155 //
156  if (*fname == '.') return false;
157  n = strlen(fname);
158 
159 // Process white list first, otherwise use the black list
160 //
161  if (tlP)
162  {while(tlP)
163  {if (tlP->ival[0] < n && !strcmp(tlP->text, fname+n-tlP->ival[0]))
164  return true;
165  tlP = tlP->next;
166  }
167  return false;
168  }
169 
170 // Check all other suffixes we wish to avoid
171 //
172  for (int i = 0; i < sfxLNum; i++)
173  {if (sfx[i].len < n && !strcmp(sfx[i].txt, fname+n-sfx[i].len))
174  return false;
175  }
176 
177 // This file can be kept
178 //
179  return true;
180 }
181 }
182 
183 /******************************************************************************/
184 /* o o u c _ S t r e a m C o n s t r u c t o r */
185 /******************************************************************************/
186 
187 XrdOucStream::XrdOucStream(XrdSysError *erobj, const char *ifname,
188  XrdOucEnv *anEnv, const char *Pfx)
189 {
190  char *cp;
191 
192 
193  if (ifname)
194  {myInst = strdup(ifname);
195  myInfo = new StreamInfo;
196  if (!(cp = index(myInst, ' '))) {cp = myInst; myInfo->myExec = 0;}
197  else {*cp = '\0'; cp++;
198  myInfo->myExec = (*myInst ? myInst : 0);
199  }
200  if ( (myInfo->myHost = index(cp, '@')))
201  {*(myInfo->myHost) = '\0';
202  myInfo->myHost++;
203  myInfo->myName = (*cp ? cp : 0);
204  } else {myInfo->myHost = cp; myInfo->myName = 0;}
205  } else {myInst = 0; myInfo = 0;}
206  myRsv1 = myRsv2 = 0;
207 
208  FD = -1;
209  FE = -1;
210  bsize = 0;
211  buff = 0;
212  bnext = 0;
213  bleft = 0;
214  recp = 0;
215  token = 0;
216  flags = 0;
217  child = 0;
218  ecode = 0;
219  notabs = 0;
220  xcont = 1;
221  xline = 0;
222  Eroute = erobj;
223  myEnv = anEnv;
224  sawif = 0;
225  skpel = 0;
226  if (myEnv && Eroute)
227  {llBuff = (char *)malloc(llBsz);
228  llBcur = llBuff; llBok = 0; llBleft = llBsz; *llBuff = '\0';
229  Verbose= 1;
230  } else {
231  Verbose= 0;
232  llBuff = 0;
233  llBcur = 0;
234  llBleft= 0;
235  llBok = 0;
236  }
237  varVal = (myEnv ? new char[maxVLen+1] : 0);
238  llPrefix = Pfx;
239 }
240 
241 /******************************************************************************/
242 /* A t t a c h */
243 /******************************************************************************/
244 
245 int XrdOucStream::AttachIO(int infd, int outfd, int bsz)
246 {
247  if (Attach(infd, bsz)) return -1;
248  FE = outfd;
249  return 0;
250 }
251 
252 int XrdOucStream::Attach(int FileDescriptor, int bsz)
253 {
254 
255  // Close the current stream. Close will handle unopened streams.
256  //
257  StreamInfo *saveInfo = myInfo; myInfo = 0;
258  Close();
259  myInfo = saveInfo;
260 
261  // Allocate a new buffer for this stream
262  //
263  if (!bsz) buff = 0;
264  else if (!(buff = (char *)malloc(bsz+1)))
265  return Erq(Attach, errno, "allocate stream buffer");
266 
267  // Initialize the stream
268  //
269  FD= FE = FileDescriptor;
270  bnext = buff;
271  bsize = bsz+1;
272  bleft = 0;
273  recp = 0;
274  token = 0;
275  flags = 0;
276  ecode = 0;
277  xcont = 1;
278  xline = 0;
279  sawif = 0;
280  skpel = 0;
281  if (llBuff)
282  {llBcur = llBuff; *llBuff = '\0'; llBleft = llBsz; llBok = 0;}
283  return 0;
284 }
285 
286 /******************************************************************************/
287 /* C a p t u r e */
288 /******************************************************************************/
289 
290 void XrdOucStream::Capture(const char **cVec, bool linefeed)
291 {
292 // Make sure we can handle this
293 //
294  if (theCFG && cVec && cVec[0])
295  {if (linefeed) theCFG->append("\n# ");
296  else theCFG->append("# ");
297  int i = 0;
298  while(cVec[i]) theCFG->append(cVec[i++]);
299  theCFG->append('\n');
300  }
301 }
302 
303 /******************************************************************************/
304 
306 {
307  XrdOucString *oldCFG = theCFG;
308  theCFG = newCFG;
309  return oldCFG;
310 }
311 
312 /******************************************************************************/
313 
315 {
316  return theCFG;
317 }
318 
319 /******************************************************************************/
320 /* C l o s e */
321 /******************************************************************************/
322 
323 void XrdOucStream::Close(int hold)
324 {
325 
326  // Wait for any associated process on this stream
327  //
328  if (!hold && child) Drain();
329  else child = 0;
330 
331  // Close the associated file descriptor if it was open
332  //
333  if (FD >= 0) close(FD);
334  if (FE >= 0 && FE != FD) close(FE);
335 
336  // Release the buffer if it was allocated.
337  //
338  if (buff) free(buff);
339 
340  // Clear all data values by attaching a dummy FD
341  //
342  FD = FE = -1;
343  buff = 0;
344 
345  // Check if we should echo the last line
346  //
347  if (llBuff)
348  {if (Verbose && *llBuff && llBok > 1)
349  {if (Eroute) Eroute->Say(llPrefix, llBuff);
350  if (theCFG) add2CFG(llBuff);
351  }
352  llBok = 0;
353  }
354 
355  // Delete any info object we have allocated
356  //
357  if (myInfo)
358  {delete myInfo;
359  myInfo = 0;
360  }
361 }
362 
363 /******************************************************************************/
364 /* D r a i n */
365 /******************************************************************************/
366 
368 {
369  int Status = 0;
370 
371  // Drain any outstanding processes (i.e., kill the process group)
372  //
373 #ifndef WIN32
374  int retc;
375  if (child) {kill(-child, 9);
376  do {retc = waitpid(child, &Status, 0);}
377  while(retc > 0 || (retc == -1 && errno == EINTR));
378  child = 0;
379  }
380 #else
381  if (child) {
382  TerminateProcess((HANDLE)child, 0);
383  child = 0;
384  }
385 #endif
386  return Status;
387 }
388 
389 /******************************************************************************/
390 /* E c h o */
391 /******************************************************************************/
392 
394 {
395  if (llBok > 1 && Verbose && llBuff)
396  {if (Eroute) Eroute->Say(llPrefix,llBuff);
397  if (theCFG) add2CFG(llBuff);
398  }
399  llBok = 0;
400 }
401 
402 /******************************************************************************/
403 /* E c h o O n l y */
404 /******************************************************************************/
405 
406 void XrdOucStream::Echo(bool capture)
407 {
408  if (llBok && Verbose && llBuff)
409  {if (Eroute) Eroute->Say(llPrefix,llBuff);
410  if (capture && theCFG) add2CFG(llBuff);
411  }
412  llBok = 0;
413 }
414 
415 /******************************************************************************/
416 /* E x e c */
417 /******************************************************************************/
418 
419 int XrdOucStream::Exec(const char *theCmd, int inrd, int efd)
420 {
421  int j;
422  char *cmd, *origcmd, *parm[MaxARGC];
423 
424  // Allocate a buffer for the command as we will be modifying it
425  //
426  origcmd = cmd = (char *)malloc(strlen(theCmd)+1);
427  strcpy(cmd, theCmd);
428 
429  // Construct the argv array based on passed command line.
430  //
431  for (j = 0; j < MaxARGC-1 && *cmd; j++)
432  {while(*cmd == ' ') cmd++;
433  if (!(*cmd)) break;
434  parm[j] = cmd;
435  while(*cmd && *cmd != ' ') cmd++;
436  if (*cmd) {*cmd = '\0'; cmd++;}
437  }
438  parm[j] = (char *)0;
439 
440  // Continue with normal processing
441  //
442  j = Exec(parm, inrd, efd);
443  free(origcmd);
444  return j;
445 }
446 
447 int XrdOucStream::Exec(char **parm, int inrd, int efd)
448 {
449  int fildes[2], Child_in = -1, Child_out = -1, Child_log = -1;
450 
451  // Create a pipe. Minimize file descriptor leaks.
452  //
453  if (inrd >= 0)
454  {if (pipe(fildes))
455  return Err(Exec, errno, "create input pipe for", parm[0]);
456  else {
457  fcntl(fildes[0], F_SETFD, FD_CLOEXEC);
458  Attach(fildes[0]); Child_out = fildes[1];
459  }
460 
461  if (inrd)
462  {if (pipe(fildes))
463  return Err(Exec, errno, "create output pipe for", parm[0]);
464  else {
465  fcntl(fildes[1], F_SETFD, FD_CLOEXEC);
466  FE = fildes[1]; Child_in = fildes[0];
467  }
468  }
469  } else {Child_out = FD; Child_in = FE;}
470 
471  // Handle the standard error file descriptor
472  //
473  if (!efd) Child_log = (Eroute ? dup(Eroute->logger()->originalFD()) : -1);
474  else if (efd > 0) Child_log = efd;
475  else if (efd == -2){Child_log = Child_out; Child_out = -1;}
476  else if (efd == -3) Child_log = Child_out;
477 
478  // Fork a process first so we can pick up the next request. We also
479  // set the process group in case the child hasn't been able to do so.
480  // Make sure only one fork occurs at any one time (we are the only one).
481  //
482  forkMutex.Lock();
483  if ((child = fork()))
484  {if (child < 0)
485  {close(Child_in); close(Child_out); forkMutex.UnLock();
486  return Err(Exec, errno, "fork request process for", parm[0]);
487  }
488  close(Child_out);
489  if (inrd) close(Child_in );
490  if (!efd && Child_log >= 0) close(Child_log);
491  forkMutex.UnLock();
492  setpgid(child, child);
493  return 0;
494  }
495 
496  /*****************************************************************/
497  /* C h i l d P r o c e s s */
498  /*****************************************************************/
499 
500  // Redirect standard in if so requested
501  //
502  if (Child_in >= 0)
503  {if (inrd)
504  {if (dup2(Child_in, STDIN_FILENO) < 0)
505  {Erx(Exec, errno, "setting up standard in for " <<parm[0]);
506  _exit(255);
507  } else if (Child_in != Child_out) close(Child_in);
508  }
509  }
510 
511  // Reassign the stream to be standard out to capture all of the output.
512  //
513  if (Child_out >= 0)
514  {if (dup2(Child_out, STDOUT_FILENO) < 0)
515  {Erx(Exec, errno, "setting up standard out for " <<parm[0]);
516  _exit(255);
517  } else if (Child_out != Child_log) close(Child_out);
518  }
519 
520  // Redirect stderr of the stream if we can to avoid keeping the logfile open
521  //
522  if (Child_log >= 0)
523  {if (dup2(Child_log, STDERR_FILENO) < 0)
524  {Erx(Exec, errno, "set up standard err for " <<parm[0]);
525  _exit(255);
526  } else close(Child_log);
527  }
528 
529  // Check if we need to set any envornment variables
530  //
531  if (myEnv)
532  {char **envP;
533  int i = 0;
534  if ((envP = (char **)myEnv->GetPtr("XrdEnvars**")))
535  while(envP[i]) {putenv(envP[i]); i++;}
536  }
537 
538  // Set our process group (the parent should have done this by now) then
539  // invoke the command never to return
540  //
541  setpgid(0,0);
542  execv(parm[0], parm);
543  Erx(Exec, errno, "executing " <<parm[0]);
544  _exit(255);
545 }
546 
547 /******************************************************************************/
548 /* G e t L i n e */
549 /******************************************************************************/
550 
552 {
553  int bcnt, retc;
554  char *bp;
555 
556 // Check if end of message has been reached.
557 //
558  if (flags & XrdOucStream_EOM) return (char *)NULL;
559 
560 // Find the next record in the buffer
561 //
562  if (bleft > 0)
563  {recp = bnext; bcnt = bleft;
564  for (bp = bnext; bcnt--; bp++)
565  if (!*bp || *bp == '\n')
566  {if (!*bp) flags |= XrdOucStream_EOM;
567  *bp = '\0';
568  bnext = ++bp;
569  bleft = bcnt;
570  token = recp;
571  return recp;
572  }
573  else if (notabs && *bp == '\t') *bp = ' ';
574 
575  // There is no next record, so move up data in the buffer.
576  //
577  strncpy(buff, bnext, bleft);
578  bnext = buff + bleft;
579  }
580  else bnext = buff;
581 
582 // Prepare to read in more data.
583 //
584  bcnt = bsize - (bnext - buff) -1;
585  bp = bnext;
586 
587 // Read up to the maximum number of bytes. Stop reading should we see a
588 // new-line character or a null byte -- the end of a record.
589 //
590  recp = token = buff; // This will always be true at this point
591  while(bcnt)
592  {do { retc = read(FD, (void *)bp, (size_t)bcnt); }
593  while (retc < 0 && errno == EINTR);
594 
595  if (retc < 0) {Erp(GetLine,errno,"read request",0); return (char *)0;}
596  if (!retc)
597  {*bp = '\0';
598  flags |= XrdOucStream_EOM;
599  bnext = ++bp;
600  bleft = 0;
601  return buff;
602  }
603 
604  bcnt -= retc;
605  while(retc--)
606  if (!*bp || *bp == '\n')
607  {if (!*bp) flags |= XrdOucStream_EOM;
608  else *bp = '\0';
609  bnext = ++bp;
610  bleft = retc;
611  return buff;
612  } else {
613  if (notabs && *bp == '\t') *bp = ' ';
614  bp++;
615  }
616  }
617 
618 // All done, force an end of record.
619 //
620  Erp(GetLine, EMSGSIZE, "read full message", 0);
621  buff[bsize-1] = '\0';
622  return buff;
623 }
624 
625 /******************************************************************************/
626 /* G e t T o k e n */
627 /******************************************************************************/
628 
629 char *XrdOucStream::GetToken(int lowcase) {
630  char *tpoint;
631 
632  // Verify that we have a token to return;
633  //
634  if (!token) return (char *)NULL;
635 
636  // Skip to the first non-blank character.
637  //
638  while (*token && *token == ' ') token ++;
639  if (!*token) {token = 0; return 0;}
640  tpoint = token;
641 
642  // Find the end of the token.
643  //
644  if (lowcase) while (*token && *token != ' ')
645  {*token = (char)tolower((int)*token); token++;}
646  else while (*token && *token != ' ') {token++;}
647  if (*token) {*token = '\0'; token++;}
648 
649  // All done here.
650  //
651  return tpoint;
652 }
653 
654 char *XrdOucStream::GetToken(char **rest, int lowcase)
655 {
656  char *tpoint;
657 
658  // Get the next token
659  //
660  if (!(tpoint = GetToken(lowcase))) return tpoint;
661 
662  // Skip to the first non-blank character.
663  //
664  while (*token && *token == ' ') token ++;
665  if (rest) *rest = token;
666 
667 
668  // All done.
669  //
670  return tpoint;
671 }
672 
673 /******************************************************************************/
674 /* G e t F i r s t W o r d */
675 /******************************************************************************/
676 
677 char *XrdOucStream::GetFirstWord(int lowcase)
678 {
679  // If in the middle of a line, flush to the end of the line. Suppress
680  // variable substitution when doing this to avoid errors.
681  //
682  if (xline)
683  {XrdOucEnv *oldEnv = SetEnv(0);
684  while(GetWord(lowcase)) {}
685  SetEnv(oldEnv);
686  }
687  return GetWord(lowcase);
688 }
689 
690 /******************************************************************************/
691 /* G e t M y F i r s t W o r d */
692 /******************************************************************************/
693 
695 {
696  char *var;
697  int skip2fi = 0;
698 
699  Echo();
700 
701  if (!myInst)
702  {if (!myEnv) return add2llB(GetFirstWord(lowcase), 1);
703  else {while((var = GetFirstWord(lowcase)) && !isSet(var)) {}
704  return add2llB(var, 1);
705  }
706  }
707 
708  do {if (!(var = GetFirstWord(lowcase)))
709  {if (sawif && !ecode)
710  {ecode = EINVAL;
711  if (Eroute) Eroute->Emsg("Stream", "Missing 'fi' for last 'if'.");
712  }
713  return add2llB(var, 1);
714  }
715 
716  add2llB(var, 1);
717 
718  if (!strcmp("continue", var))
719  {if (!docont()) return 0;
720  continue;
721  }
722 
723  if ( !strcmp("if", var)) var = doif();
724  if (var && !strcmp("else", var)) var = doelse();
725  if (var && !strcmp("fi", var))
726  {if (sawif) sawif = skpel = skip2fi = 0;
727  else {if (Eroute)
728  Eroute->Emsg("Stream", "No preceding 'if' for 'fi'.");
729  ecode = EINVAL;
730  }
731  continue;
732  }
733  if (var && (!myEnv || !isSet(var))) return add2llB(var, 1);
734  } while (1);
735 
736  return 0;
737 }
738 
739 /******************************************************************************/
740 /* G e t W o r d */
741 /******************************************************************************/
742 
743 char *XrdOucStream::GetWord(int lowcase)
744 {
745  char *wp, *ep;
746 
747  // A call means the first token was acceptable and we continuing to
748  // parse, hence the line is echoable.
749  //
750  if (llBok == 1) llBok = 2;
751 
752  // If we have a token, return it
753  //
754  xline = 1;
755  while((wp = GetToken(lowcase)))
756  {if (!myEnv) return add2llB(wp);
757  if ((wp = vSubs(wp)) && *wp) return add2llB(wp);
758  }
759 
760  // If no continuation allowed, return a null (but only once)
761  //
762  if (!xcont) {xcont = 1; xline = 0; return (char *)0;}
763 
764  // Find the next non-blank non-comment line
765  //
766 do {while(GetLine())
767  {// Get the first token (none if it is a blank line)
768  //
769  if (!(wp = GetToken(lowcase))) continue;
770 
771  // If token starts with a pound sign, skip the line
772  //
773  if (*wp == '#') continue;
774 
775  // Process continuations (last non-blank character is a back-slash)
776  //
777  ep = bnext-2;
778  while (ep >= buff && *ep == ' ') ep--;
779  if (ep < buff) continue;
780  if (*ep == '\\') {xcont = 1; *ep = '\0';}
781  else xcont = 0;
782  return add2llB((myEnv ? vSubs(wp) : wp));
783  }
784 
785  if (myInfo && myInfo->fcList)
786  {if (myInfo->itFC == myInfo->fcList->end())
787  {bleft = 0;
788  flags |= XrdOucStream_EOM;
789  break;
790  }
791  const char *path = (*(myInfo->itFC)).c_str();
792  myInfo->itFC++;
793  if (!docontF(path)) break;
794  bleft = 0;
795  flags &= ~XrdOucStream_EOM;
796  } else break;
797  } while(true);
798 
799  xline = 0;
800  return (char *)0;
801 }
802 
803 /******************************************************************************/
804 /* G e t R e s t */
805 /******************************************************************************/
806 
807 int XrdOucStream::GetRest(char *theBuff, int Blen, int lowcase)
808 {
809  char *tp, *myBuff = theBuff;
810  int tlen;
811 
812 // Get remaining tokens
813 //
814  theBuff[0] = '\0';
815  while ((tp = GetWord(lowcase)))
816  {tlen = strlen(tp);
817  if (tlen+1 >= Blen) return 0;
818  if (myBuff != theBuff) {*myBuff++ = ' '; Blen--;}
819  strcpy(myBuff, tp);
820  Blen -= tlen; myBuff += tlen;
821  }
822 
823 // All done
824 //
825  add2llB(0);
826  return 1;
827 }
828 
829 /******************************************************************************/
830 /* R e t T o k e n */
831 /******************************************************************************/
832 
834 {
835  // Check if we can back up
836  //
837  if (!token || token == recp) return;
838 
839  // Find the null byte for the token and remove it, if possible
840  //
841  while(*token && token != recp) token--;
842  if (token != recp)
843  {if (token+1 != bnext) *token = ' ';
844  token--;
845  while(*token && *token != ' ' && token != recp) token--;
846  if (token != recp) token++;
847  }
848 
849  // If saving line, we must do the same for the saved line
850  //
851  if (llBuff)
852  while(llBcur != llBuff && *llBcur != ' ') {llBcur--; llBleft++;}
853 }
854 
855 /******************************************************************************/
856 /* P u t */
857 /******************************************************************************/
858 
859 int XrdOucStream::Put(const char *data, const int dlen) {
860  int dcnt = dlen, retc;
861 
862  if (flags & XrdOucStream_BUSY) {ecode = ETXTBSY; return -1;}
863 
864  while(dcnt)
865  {do { retc = write(FE, (const void *)data, (size_t)dlen);}
866  while (retc < 0 && errno == EINTR);
867  if (retc >= 0) dcnt -= retc;
868  else {flags |= XrdOucStream_BUSY;
869  Erp(Put, errno, "write to stream", 0);
870  flags &= ~XrdOucStream_BUSY;
871  return -1;
872  }
873  }
874  return 0;
875 }
876 
877 int XrdOucStream::Put(const char *datavec[], const int dlenvec[]) {
878  int i, retc, dlen;
879  const char *data;
880 
881  if (flags & XrdOucStream_BUSY) {ecode = ETXTBSY; return -1;}
882 
883  for (i = 0; datavec[i]; i++)
884  {data = datavec[i]; dlen = dlenvec[i];
885  while(dlen)
886  {do { retc = write(FE, (const void *)data, (size_t)dlen);}
887  while (retc < 0 && errno == EINTR);
888  if (retc >= 0) {data += retc; dlen -= retc;}
889  else {flags |= XrdOucStream_BUSY;
890  Erp(Put, errno, "write to stream",0);
891  flags &= ~XrdOucStream_BUSY;
892  return -1;
893  }
894  }
895  }
896  return 0;
897 }
898 
899 /******************************************************************************/
900 /* P u t L i n e */
901 /******************************************************************************/
902 
903 int XrdOucStream::PutLine(const char *data, int dlen)
904 {
905  static const int plSize = 2048;
906 
907 // Allocate a buffer if one is not allocated
908 //
909  if (!buff)
910  {if (!(buff = (char *)malloc(plSize)))
911  return Erq(Attach, errno, "allocate stream buffer");
912  bsize = plSize;
913  }
914 
915 // Adjust dlen
916 //
917  if (dlen <= 0) dlen = strlen(data);
918  if (dlen >= bsize) dlen = bsize-1;
919 
920 // Simply insert the line into the buffer, truncating if need be
921 //
922  bnext = recp = token = buff; // This will always be true at this point
923  if (dlen <= 0)
924  {*buff = '\0';
925  flags |= XrdOucStream_EOM;
926  bleft = 0;
927  } else {
928  strncpy(buff, data, dlen);
929  *(buff+dlen) = 0;
930  bleft = dlen+1;
931  }
932 // All done
933 //
934  return 0;
935 }
936 
937 /******************************************************************************/
938 /* W a i t 4 D a t a */
939 /******************************************************************************/
940 
942 {
943  struct pollfd polltab = {FD, POLLIN|POLLRDNORM, 0};
944  int retc;
945 
946 // Wait until we can actually read something
947 //
948  do {retc = poll(&polltab, 1, msMax);} while(retc < 0 && errno == EINTR);
949  if (retc != 1) return (retc ? errno : -1);
950 
951 // Return correct value
952 //
953  return (polltab.revents & (POLLIN|POLLRDNORM) ? 0 : EIO);
954 }
955 
956 /******************************************************************************/
957 /* P r i v a t e M e t h o d s */
958 /******************************************************************************/
959 /******************************************************************************/
960 /* a d d 2 C F G */
961 /******************************************************************************/
962 
963 void XrdOucStream::add2CFG(const char *data, bool isCMT)
964 {
965  if (isCMT) theCFG->append("# ");
966  theCFG->append(data);
967  theCFG->append('\n');
968 }
969 
970 /******************************************************************************/
971 /* a d d 2 l l B */
972 /******************************************************************************/
973 
974 char *XrdOucStream::add2llB(char *tok, int reset)
975 {
976  int tlen;
977 
978 // Return if not saving data
979 //
980  if (!llBuff) return tok;
981 
982 // Check if we should flush the previous line
983 //
984  if (reset)
985  {llBok = 1;
986  llBcur = llBuff;
987  llBleft= llBsz;
988  *llBuff = '\0';
989  } else if (!llBok) return tok;
990  else {llBok = 2;
991  if (llBleft >= 2)
992  {*llBcur++ = ' '; *llBcur = '\0'; llBleft--;}
993  }
994 
995 // Add in the new token
996 //
997  if (tok)
998  {tlen = strlen(tok);
999  if (tlen < llBleft)
1000  {strcpy(llBcur, tok); llBcur += tlen; llBleft -= tlen;}
1001  }
1002  return tok;
1003 }
1004 
1005 /******************************************************************************/
1006 /* E c h o */
1007 /******************************************************************************/
1008 
1009 bool XrdOucStream::Echo(int ec, const char *t1, const char *t2, const char *t3)
1010 {
1011  if (Eroute)
1012  {if (t1) Eroute->Emsg("Stream", t1, t2, t3);
1013  if (llBok > 1 && Verbose && llBuff) Eroute->Say(llPrefix,llBuff);
1014  }
1015  ecode = ec;
1016  llBok = 0;
1017  return false;
1018 }
1019 
1020 /******************************************************************************/
1021 /* d o c o n t */
1022 /******************************************************************************/
1023 
1024 bool XrdOucStream::docont()
1025 {
1026  char *theWord;
1027 
1028 // A continue is not valid within the scope of an if
1029 //
1030  if (sawif) return Echo(EINVAL, "'continue' invalid within 'if-fi'.");
1031 
1032 // Get the path (keep case), if none then ignore this continue
1033 //
1034  theWord = GetWord();
1035  if (!theWord)
1036  {Echo();
1037  return true;
1038  }
1039 
1040 // Prepare to handle the directive
1041 //
1042  contHandler cH;
1043  cH.path = strdup(theWord);
1044 
1045 // Grab additioal tokens which may be suffixes
1046 //
1047  theWord = GetWord();
1048  while(theWord && *theWord == '*')
1049  {if (!*(theWord+1)) return Echo(EINVAL, "suffix missing after '*'.");
1050  cH.Add(theWord+1);
1051  theWord = GetWord();
1052  }
1053 
1054 // If we have a token, it better be an if
1055 //
1056  if (theWord && strcmp(theWord, "if"))
1057  return Echo(EINVAL, "expecting 'if' but found", theWord);
1058 
1059 // Process the 'if'
1060 //
1061  if (theWord && !XrdOucUtils::doIf(Eroute, *this, "continue directive",
1062  myInfo->myHost,myInfo->myName,myInfo->myExec))
1063  return true;
1064  Echo();
1065 // if (Eroute) Eroute->Say(llPrefix, "continue ", path, " if true");
1066 // if (Eroute) Eroute->Say(llPrefix, "continue ", bnext);
1067  return docont(cH.path, cH.tlP);
1068 }
1069 
1070 /******************************************************************************/
1071 
1072 bool XrdOucStream::docont(const char *path, XrdOucTList *tlP)
1073 {
1074  struct stat Stat;
1075  bool noentok;
1076 
1077 // A continue directive in the context of a continuation is illegal
1078 //
1079  if ((myInfo && myInfo->fcList) || (flags & XrdOucStream_CONT) != 0)
1080  return Echo(EINVAL, "'continue' in a continuation is not allowed.");
1081 
1082 // Check if this file must exist (we also take care of empty paths)
1083 //
1084  if ((noentok = (*path == '?')))
1085  {path++;
1086  if (!(*path)) return true;
1087  }
1088 
1089 // Check if this is a file or directory
1090 //
1091  if (stat(path, &Stat))
1092  {if (errno == ENOENT && noentok) return true;
1093  if (Eroute)
1094  {Eroute->Emsg("Stream", errno, "open", path);
1095  ecode = ECANCELED;
1096  } else ecode = errno;
1097  return false;
1098  }
1099 
1100 // For directory continuation, there is much more to do (this can only happen
1101 // once). Note that we used to allow a limited number of chained file
1102 // continuations. No more, but we are still setup to easily do so.
1103 //
1104  if ((Stat.st_mode & S_IFMT) == S_IFDIR)
1105  {if (!docontD(path, tlP)) return false;
1106  path = (*(myInfo->itFC)).c_str();
1107  myInfo->itFC++;
1108  } else flags |= XrdOucStream_CADD;
1109 
1110 // if ((flags & XrdOucStream_CONT) > XrdOucStream_CMAX)
1111 // {if (Eroute)
1112 // {Eroute->Emsg("Stream", EMLINK, "continue to", path);
1113 // ecode = ECANCELED;
1114 // } else ecode = EMLINK;
1115 // return false;
1116 // }
1117 // }
1118 
1119 // Continue with the next file
1120 //
1121  return docontF(path, noentok);
1122 }
1123 
1124 /******************************************************************************/
1125 /* d o c o n t D */
1126 /******************************************************************************/
1127 
1128 bool XrdOucStream::docontD(const char *path, XrdOucTList *tlP)
1129 {
1130  static const mode_t isXeq = S_IXUSR | S_IXGRP | S_IXOTH;
1131  XrdOucNSWalk nsWalk(Eroute, path, 0, XrdOucNSWalk::retFile);
1132  int rc;
1133 
1134 // Get all of the file entries in this directory
1135 //
1136  XrdOucNSWalk::NSEnt *nsX, *nsP = nsWalk.Index(rc);
1137  if (rc)
1138  {if (Eroute) Eroute->Emsg("Stream", rc, "index config files in", path);
1139  ecode = ECANCELED;
1140  return false;
1141  }
1142 
1143 // Keep only files of interest
1144 //
1145  myInfo->fcList = new std::set<std::string>;
1146  while((nsX = nsP))
1147  {nsP = nsP->Next;
1148  if ((nsX->Stat.st_mode & isXeq) == 0 && KeepFile(nsX->File, tlP))
1149  myInfo->fcList->insert(std::string(nsX->Path));
1150  delete nsX;
1151  }
1152 
1153 // Check if we have anything in the map
1154 //
1155  if (myInfo->fcList->size() == 0)
1156  {delete myInfo->fcList;
1157  myInfo->fcList = 0;
1158  return false;
1159  }
1160 
1161 // All done
1162 //
1163  myInfo->itFC = myInfo->fcList->begin();
1164  return true;
1165 }
1166 
1167 /******************************************************************************/
1168 /* c o n t F */
1169 /******************************************************************************/
1170 
1171 bool XrdOucStream::docontF(const char *path, bool noentok)
1172 {
1173  int cFD;
1174 
1175 // Open the file and handle any errors
1176 //
1177  if ((cFD = XrdSysFD_Open(path, O_RDONLY)) < 0)
1178  {if (errno == ENOENT && noentok) return true;
1179  if (Eroute)
1180  {Eroute->Emsg("Stream", errno, "open", path);
1181  ecode = ECANCELED;
1182  } else ecode = errno;
1183  return false;
1184  }
1185 
1186 // Continue to the next file
1187 //
1188  if (XrdSysFD_Dup2(cFD, FD) < 0)
1189  {if (Eroute)
1190  {Eroute->Emsg("Stream", ecode, "switch to", path);
1191  close(cFD);
1192  ecode = ECANCELED;
1193  } else ecode = errno;
1194  return false;
1195  }
1196 
1197 // Indicate we are switching to anther file
1198 //
1199  if (Eroute) Eroute->Say("Config continuing with file ", path, " ...");
1200  bleft = 0;
1201  close(cFD);
1202  return true;
1203 }
1204 
1205 /******************************************************************************/
1206 /* d o e l s e */
1207 /******************************************************************************/
1208 
1209 char *XrdOucStream::doelse()
1210 {
1211  char *var;
1212 
1213 // An else must be preceeded by an if and not by a naked else
1214 //
1215  if (!sawif || sawif == 2)
1216  {if (Eroute) Eroute->Emsg("Stream", "No preceding 'if' for 'else'.");
1217  ecode = EINVAL;
1218  return 0;
1219  }
1220 
1221 // If skipping all else caluses, skip all lines until we reach a fi
1222 //
1223  if (skpel)
1224  {while((var = GetFirstWord()))
1225  {if (!strcmp("fi", var)) return var;}
1226  if (Eroute) Eroute->Emsg("Stream", "Missing 'fi' for last 'if'.");
1227  ecode = EINVAL;
1228  return 0;
1229  }
1230 
1231 // Elses are still possible then process one of them
1232 //
1233  do {if (!(var = GetWord())) // A naked else will always succeed
1234  {sawif = 2;
1235  return 0;
1236  }
1237  if (strcmp("if", var)) // An else may only be followed by an if
1238  {Eroute->Emsg("Stream","'else",var,"' is invalid.");
1239  ecode = EINVAL;
1240  return 0;
1241  }
1242  sawif = 0;
1243  flags |= XrdOucStream_ELIF;
1244  var = doif();
1245  flags &= ~XrdOucStream_ELIF;
1246  } while(var && !strcmp("else", var));
1247  return var;
1248 }
1249 
1250 /******************************************************************************/
1251 /* d o i f */
1252 /******************************************************************************/
1253 
1254 /* Function: doif
1255 
1256  Purpose: To parse the directive: if [<hlist>] [exec <pgm>] [named <nlist>]
1257  fi
1258 
1259  <hlist> Apply subsequent directives until the 'fi' if this host
1260  is one of the hosts in the blank separated list. Each
1261  host name may have a single asterisk somewhere in the
1262  name to indicate where arbitrry characters lie.
1263 
1264  <pgm> Apply subsequent directives if this program is named <pgm>.
1265 
1266  <nlist> Apply subsequent directives if this host instance name
1267  is in the list of blank separated names.
1268 
1269  Notes: 1) At least one of hlist, pgm, or nlist must be specified.
1270  2) The combination of hlist, pgm, nlist must all be true.
1271 
1272  Output: 0 upon success or !0 upon failure.
1273 */
1274 
1275 char *XrdOucStream::doif()
1276 {
1277  char *var, ifLine[512];
1278  int rc;
1279 
1280 // Check if the previous if was properly closed
1281 //
1282  if (sawif)
1283  {if (Eroute) Eroute->Emsg("Stream", "Missing 'fi' for last 'if'.");
1284  ecode = EINVAL;
1285  }
1286 
1287 // Save the line for context message should we get an error
1288 //
1289  snprintf(ifLine, sizeof(ifLine), "%s", token);
1290 
1291 // Check if we should continue
1292 //
1293  sawif = 1; skpel = 0;
1294  if ((rc = XrdOucUtils::doIf(Eroute,*this,"if directive",
1295  myInfo->myHost,myInfo->myName,myInfo->myExec)))
1296  {if (rc >= 0) skpel = 1;
1297  else {ecode = EINVAL;
1298  if(Eroute) Eroute->Say(llPrefix,
1299  (flags & XrdOucStream_ELIF ? "else " : 0),
1300  "if ", ifLine);
1301  }
1302  return 0;
1303  }
1304 
1305 // Skip all lines until we reach a fi or else
1306 //
1307  while((var = GetFirstWord()))
1308  {if (!strcmp("fi", var)) return var;
1309  if (!strcmp("else", var)) return var;
1310  }
1311 
1312 // Make sure we have a fi
1313 //
1314  if (!var)
1315  {if (Eroute) Eroute->Emsg("Stream", "Missing 'fi' for last 'if'.");
1316  ecode = EINVAL;
1317  }
1318  return 0;
1319 }
1320 
1321 /******************************************************************************/
1322 /* g e t V a l u e */
1323 /******************************************************************************/
1324 
1325 int XrdOucStream::getValue(const char *path, char *vbuff, int vbsz)
1326 {
1327  struct stat Stat;
1328  int n, rc = 0, vFD;
1329 
1330 // Make sure the file exists and it not too big
1331 //
1332  if (stat(path, &Stat)) return errno;
1333  if (Stat.st_size >= vbsz) return EFBIG;
1334 
1335 // Open the file and read it in
1336 //
1337  if ((vFD = XrdSysFD_Open(path, O_RDONLY)) < 0) return errno;
1338  if ((n = read(vFD, vbuff, vbsz-1)) >= 0) vbuff[n] = 0;
1339  else rc = errno;
1340 
1341 // All done
1342 //
1343  close(vFD);
1344  return rc;
1345 }
1346 
1347 /******************************************************************************/
1348 /* i s S e t */
1349 /******************************************************************************/
1350 
1351 int XrdOucStream::isSet(char *var)
1352 {
1353  static const char *Mtxt1[2] = {"setenv", "set"};
1354  static const char *Mtxt2[2] = {"Setenv variable", "Set variable"};
1355  static const char *Mtxt3[2] = {"Variable", "Environmental variable"};
1356  char *tp, *vn, *vp, *pv, Vname[64], ec, Nil = 0, sawIT = 0;
1357  int Set = 1;
1358  char valBuff[1024];
1359 
1360 // Process set var = value | set -v | setenv = value
1361 //
1362  if (!strcmp("setenv", var)) Set = 0;
1363  else if (strcmp("set", var)) return 0;
1364 
1365 // Now get the operand
1366 //
1367  if (!(tp = GetToken()))
1368  return xMsg("Missing variable name after '",Mtxt1[Set],"'.");
1369 
1370 // Option flags only apply to set not setenv
1371 //
1372  if (Set)
1373  {if (!strcmp(tp, "-q")) {if (llBuff) {free(llBuff); llBuff = 0;}; return 1;}
1374  if (!strcmp(tp, "-v") || !strcmp(tp, "-V"))
1375  {if (Eroute)
1376  {if (!llBuff) llBuff = (char *)malloc(llBsz);
1377  llBcur = llBuff; llBok = 0; llBleft = llBsz; *llBuff = '\0';
1378  Verbose = (strcmp(tp, "-V") ? 1 : 2);
1379  }
1380  return 1;
1381  }
1382  }
1383 
1384 // Next may be var= | var | var=val | var< | var<val
1385 //
1386  if ((vp = index(tp, '=')) || (vp = index(tp, '<')))
1387  {sawIT = *vp; *vp = '\0'; vp++;}
1388  if (strlcpy(Vname, tp, sizeof(Vname)) >= sizeof(Vname))
1389  return xMsg(Mtxt2[Set],tp,"is too long.");
1390  if (!Set && !strncmp("XRD", Vname, 3))
1391  return xMsg("Setenv variable",tp,"may not start with 'XRD'.");
1392 
1393 // Verify that variable is only an alphanum
1394 //
1395  tp = Vname;
1396  while (*tp && (*tp == '_' || isalnum(*tp))) tp++;
1397  if (*tp) return xMsg(Mtxt2[Set], Vname, "is non-alphanumeric");
1398 
1399 // Now look for the value
1400 //
1401  if (sawIT) tp = vp;
1402  else if (!(tp = GetToken()) || (*tp != '=' && *tp != '<'))
1403  return xMsg("Missing '=' after", Mtxt1[Set], Vname);
1404  else {sawIT = *tp; tp++;}
1405  if (!*tp && !(tp = GetToken())) tp = (char *)"";
1406 
1407 // Handle reading value from a file
1408 //
1409  if (sawIT == '<')
1410  {int rc;
1411  if (!*tp) return xMsg(Mtxt2[Set], Vname, "path to value not specified");
1412  if ((rc = getValue(tp, valBuff, sizeof(valBuff))))
1413  {char tbuff[512];
1414  snprintf(tbuff, sizeof(tbuff), "cannot be set via path %s; %s",
1415  tp, XrdSysE2T(rc));
1416  return xMsg(Mtxt2[Set], Vname, tbuff);
1417  }
1418  tp = valBuff;
1419  }
1420 
1421 // The value may be '$var', in which case we need to get it out of the env if
1422 // this is a set or from our environment if this is a setenv
1423 //
1424  if (*tp != '$') vp = tp;
1425  else {pv = tp+1;
1426  if (*pv == '(') ec = ')';
1427  else if (*pv == '{') ec = '}';
1428  else if (*pv == '[') ec = ']';
1429  else ec = 0;
1430  if (!ec) vn = tp+1;
1431  else {while(*pv && *pv != ec) pv++;
1432  if (*pv) *pv = '\0';
1433  else ec = 0;
1434  vn = tp+2;
1435  }
1436  if (!*vn) {*pv = ec; return xMsg("Variable", tp, "is malformed.");}
1437  if (!(vp = (Set ? getenv(vn) : myEnv->Get(vn))))
1438  {if (ec != ']')
1439  {xMsg(Mtxt3[Set],vn,"is undefined."); *pv = ec; return 1;}
1440  vp = &Nil;
1441  }
1442  *pv = ec;
1443  }
1444 
1445 // Make sure the value is not too long
1446 //
1447  if ((int)strlen(vp) > maxVLen)
1448  return xMsg(Mtxt3[Set], Vname, "value is too long.");
1449 
1450 // Set the value
1451 //
1452  if (Verbose == 2 && Eroute)
1453  if (!(pv = (Set ? myEnv->Get(Vname) : getenv(Vname))) || strcmp(vp, pv))
1454  {char vbuff[1024];
1455  strcpy(vbuff, Mtxt1[Set]); strcat(vbuff, " "); strcat(vbuff, Vname);
1456  Eroute->Say(vbuff, " = ", vp);
1457  }
1458  if (Set) myEnv->Put(Vname, vp);
1459  else if (!(pv = getenv(Vname)) || strcmp(vp,pv))
1460  XrdOucEnv::Export(Vname, vp);
1461  return 1;
1462 }
1463 
1464 /******************************************************************************/
1465 /* v S u b s */
1466 /******************************************************************************/
1467 
1468 char *XrdOucStream::vSubs(char *Var)
1469 {
1470  char *vp, *sp, *dp, *vnp, ec, bkp, valbuff[maxVLen], Nil = 0;
1471  int n;
1472 
1473 // Check for substitution
1474 //
1475  if (!Var) return Var;
1476  sp = Var; dp = valbuff; n = maxVLen-1; *varVal = '\0';
1477 
1478  while(*sp && n > 0)
1479  {if (*sp == '\\') {*dp++ = *(sp+1); sp +=2; n--; continue;}
1480  if (*sp != '$'
1481  || (!isalnum(*(sp+1)) && !index("({[", *(sp+1))))
1482  {*dp++ = *sp++; n--; continue;}
1483  sp++; vnp = sp;
1484  if (*sp == '(') ec = ')';
1485  else if (*sp == '{') ec = '}';
1486  else if (*sp == '[') ec = ']';
1487  else ec = 0;
1488  if (ec) {sp++; vnp++;}
1489  while(isalnum(*sp)) sp++;
1490  if (ec && *sp != ec)
1491  {xMsg("Variable", vnp-2, "is malformed."); return varVal;}
1492  bkp = *sp; *sp = '\0';
1493  if (!(vp = myEnv->Get(vnp)))
1494  {if (ec != ']') xMsg("Variable", vnp, "is undefined.");
1495  vp = &Nil;
1496  }
1497  while(n && *vp) {*dp++ = *vp++; n--;}
1498  if (*vp) break;
1499  if (ec) sp++;
1500  else *sp = bkp;
1501  }
1502 
1503  if (*sp) xMsg("Substituted text too long using", Var);
1504  else {*dp = '\0'; strcpy(varVal, valbuff);}
1505  return varVal;
1506 }
1507 
1508 /******************************************************************************/
1509 /* x M s g */
1510 /******************************************************************************/
1511 
1512 int XrdOucStream::xMsg(const char *txt1, const char *txt2, const char *txt3)
1513 {
1514  if (Eroute) Eroute->Emsg("Stream", txt1, txt2, txt3);
1515  ecode = EINVAL;
1516  return 1;
1517 }
struct stat Stat
Definition: XrdCks.cc:49
#define XrdOucStream_EOM
Definition: XrdOucStream.cc:72
#define XrdOucStream_BUSY
Definition: XrdOucStream.cc:73
#define XrdOucStream_ELIF
Definition: XrdOucStream.cc:74
#define XrdOucStream_CADD
Definition: XrdOucStream.cc:76
#define Erx(p, a, b)
Definition: XrdOucStream.cc:86
#define Erp(p, a, b, c)
Definition: XrdOucStream.cc:82
#define XrdOucStream_CONT
Definition: XrdOucStream.cc:77
#define Err(p, a, b, c)
Definition: XrdOucStream.cc:81
#define MaxARGC
Definition: XrdOucStream.cc:71
#define Erq(p, a, b)
Definition: XrdOucStream.cc:80
int stat(const char *path, struct stat *buf)
int fcntl(int fd, int cmd,...)
ssize_t write(int fildes, const void *buf, size_t nbyte)
ssize_t read(int fildes, void *buf, size_t nbyte)
#define close(a)
Definition: XrdPosix.hh:43
const char * XrdSysE2T(int errcode)
Definition: XrdSysE2T.cc:104
size_t strlcpy(char *dst, const char *src, size_t sz)
static int Export(const char *Var, const char *Val)
Definition: XrdOucEnv.cc:188
void * GetPtr(const char *varname)
Definition: XrdOucEnv.cc:281
char * Get(const char *varname)
Definition: XrdOucEnv.hh:69
void Put(const char *varname, const char *value)
Definition: XrdOucEnv.hh:85
static const int retFile
XrdOucStream(XrdSysError *erobj=0, const char *ifname=0, XrdOucEnv *anEnv=0, const char *Pfx=0)
char * GetMyFirstWord(int lowcase=0)
int PutLine(const char *data, int dlen=0)
static XrdOucString * Capture()
char * GetLine()
char * GetFirstWord(int lowcase=0)
char * GetWord(int lowcase=0)
int Attach(int FileDescriptor, int bsz=2047)
int AttachIO(int infd, int outfd, int bsz=2047)
int Put(const char *data, const int dlen)
int Exec(const char *, int inrd=0, int efd=0)
int Wait4Data(int msMax=-1)
void Close(int hold=0)
XrdOucEnv * SetEnv(XrdOucEnv *newEnv)
char * GetToken(int lowcase=0)
int GetRest(char *theBuf, int Blen, int lowcase=0)
void append(const int i)
XrdOucTList * next
Definition: XrdOucTList.hh:45
char * text
Definition: XrdOucTList.hh:46
static int doIf(XrdSysError *eDest, XrdOucStream &Config, const char *what, const char *hname, const char *nname, const char *pname)
Definition: XrdOucUtils.cc:231
int Emsg(const char *esfx, int ecode, const char *text1, const char *text2=0)
Definition: XrdSysError.cc:95
void Say(const char *text1, const char *text2=0, const char *txt3=0, const char *text4=0, const char *text5=0, const char *txt6=0)
Definition: XrdSysError.cc:141
XrdSysLogger * logger(XrdSysLogger *lp=0)
Definition: XrdSysError.hh:141
XrdOucEnv * envP
Definition: XrdPss.cc:109
std::set< std::string > * fcList
std::set< std::string >::iterator itFC
char * myExec
char * myName
char * myHost
struct NSEnt * Next
Definition: XrdOucNSWalk.hh:48