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  if (!theCmd)
425  return EINVAL;
426 
427  // Allocate a buffer for the command as we will be modifying it
428  //
429  origcmd = cmd = (char *)malloc(strlen(theCmd)+1);
430  strcpy(cmd, theCmd);
431 
432  // Construct the argv array based on passed command line.
433  //
434  for (j = 0; j < MaxARGC-1 && *cmd; j++)
435  {while(*cmd == ' ') cmd++;
436  if (!(*cmd)) break;
437  parm[j] = cmd;
438  while(*cmd && *cmd != ' ') cmd++;
439  if (*cmd) {*cmd = '\0'; cmd++;}
440  }
441  parm[j] = (char *)0;
442 
443  // Continue with normal processing
444  //
445  int ret = j > 0 ? Exec(parm, inrd, efd) : EINVAL;
446  free(origcmd);
447  return ret;
448 }
449 
450 int XrdOucStream::Exec(char **parm, int inrd, int efd)
451 {
452  int fildes[2], Child_in = -1, Child_out = -1, Child_log = -1;
453 
454  // Create a pipe. Minimize file descriptor leaks.
455  //
456  if (inrd >= 0)
457  {if (pipe(fildes))
458  return Err(Exec, errno, "create input pipe for", parm[0]);
459  else {
460  fcntl(fildes[0], F_SETFD, FD_CLOEXEC);
461  Attach(fildes[0]); Child_out = fildes[1];
462  }
463 
464  if (inrd)
465  {if (pipe(fildes))
466  return Err(Exec, errno, "create output pipe for", parm[0]);
467  else {
468  fcntl(fildes[1], F_SETFD, FD_CLOEXEC);
469  FE = fildes[1]; Child_in = fildes[0];
470  }
471  }
472  } else {Child_out = FD; Child_in = FE;}
473 
474  // Handle the standard error file descriptor
475  //
476  if (!efd) Child_log = (Eroute ? dup(Eroute->logger()->originalFD()) : -1);
477  else if (efd > 0) Child_log = efd;
478  else if (efd == -2){Child_log = Child_out; Child_out = -1;}
479  else if (efd == -3) Child_log = Child_out;
480 
481  // Fork a process first so we can pick up the next request. We also
482  // set the process group in case the child hasn't been able to do so.
483  // Make sure only one fork occurs at any one time (we are the only one).
484  //
485  forkMutex.Lock();
486  if ((child = fork()))
487  {if (child < 0)
488  {close(Child_in); close(Child_out); forkMutex.UnLock();
489  return Err(Exec, errno, "fork request process for", parm[0]);
490  }
491  close(Child_out);
492  if (inrd) close(Child_in );
493  if (!efd && Child_log >= 0) close(Child_log);
494  forkMutex.UnLock();
495  setpgid(child, child);
496  return 0;
497  }
498 
499  /*****************************************************************/
500  /* C h i l d P r o c e s s */
501  /*****************************************************************/
502 
503  // Redirect standard in if so requested
504  //
505  if (Child_in >= 0)
506  {if (inrd)
507  {if (dup2(Child_in, STDIN_FILENO) < 0)
508  {Erx(Exec, errno, "setting up standard in for " <<parm[0]);
509  _exit(255);
510  } else if (Child_in != Child_out) close(Child_in);
511  }
512  }
513 
514  // Reassign the stream to be standard out to capture all of the output.
515  //
516  if (Child_out >= 0)
517  {if (dup2(Child_out, STDOUT_FILENO) < 0)
518  {Erx(Exec, errno, "setting up standard out for " <<parm[0]);
519  _exit(255);
520  } else if (Child_out != Child_log) close(Child_out);
521  }
522 
523  // Redirect stderr of the stream if we can to avoid keeping the logfile open
524  //
525  if (Child_log >= 0)
526  {if (dup2(Child_log, STDERR_FILENO) < 0)
527  {Erx(Exec, errno, "set up standard err for " <<parm[0]);
528  _exit(255);
529  } else close(Child_log);
530  }
531 
532  // Check if we need to set any envornment variables
533  //
534  if (myEnv)
535  {char **envP;
536  int i = 0;
537  if ((envP = (char **)myEnv->GetPtr("XrdEnvars**")))
538  while(envP[i]) {putenv(envP[i]); i++;}
539  }
540 
541  // Set our process group (the parent should have done this by now) then
542  // invoke the command never to return
543  //
544  setpgid(0,0);
545  execv(parm[0], parm);
546  Erx(Exec, errno, "executing " <<parm[0]);
547  _exit(255);
548 }
549 
550 /******************************************************************************/
551 /* G e t L i n e */
552 /******************************************************************************/
553 
555 {
556  int bcnt, retc;
557  char *bp;
558 
559 // Check if end of message has been reached.
560 //
561  if (flags & XrdOucStream_EOM) return (char *)NULL;
562 
563 // Find the next record in the buffer
564 //
565  if (bleft > 0)
566  {recp = bnext; bcnt = bleft;
567  for (bp = bnext; bcnt--; bp++)
568  if (!*bp || *bp == '\n')
569  {if (!*bp) flags |= XrdOucStream_EOM;
570  *bp = '\0';
571  bnext = ++bp;
572  bleft = bcnt;
573  token = recp;
574  return recp;
575  }
576  else if (notabs && *bp == '\t') *bp = ' ';
577 
578  // There is no next record, so move up data in the buffer.
579  //
580  strncpy(buff, bnext, bleft);
581  bnext = buff + bleft;
582  }
583  else bnext = buff;
584 
585 // Prepare to read in more data.
586 //
587  bcnt = bsize - (bnext - buff) -1;
588  bp = bnext;
589 
590 // Read up to the maximum number of bytes. Stop reading should we see a
591 // new-line character or a null byte -- the end of a record.
592 //
593  recp = token = buff; // This will always be true at this point
594  while(bcnt)
595  {do { retc = read(FD, (void *)bp, (size_t)bcnt); }
596  while (retc < 0 && errno == EINTR);
597 
598  if (retc < 0) {Erp(GetLine,errno,"read request",0); return (char *)0;}
599  if (!retc)
600  {*bp = '\0';
601  flags |= XrdOucStream_EOM;
602  bnext = ++bp;
603  bleft = 0;
604  return buff;
605  }
606 
607  bcnt -= retc;
608  while(retc--)
609  if (!*bp || *bp == '\n')
610  {if (!*bp) flags |= XrdOucStream_EOM;
611  else *bp = '\0';
612  bnext = ++bp;
613  bleft = retc;
614  return buff;
615  } else {
616  if (notabs && *bp == '\t') *bp = ' ';
617  bp++;
618  }
619  }
620 
621 // All done, force an end of record.
622 //
623  Erp(GetLine, EMSGSIZE, "read full message", 0);
624  buff[bsize-1] = '\0';
625  return buff;
626 }
627 
628 /******************************************************************************/
629 /* G e t T o k e n */
630 /******************************************************************************/
631 
632 char *XrdOucStream::GetToken(int lowcase) {
633  char *tpoint;
634 
635  // Verify that we have a token to return;
636  //
637  if (!token) return (char *)NULL;
638 
639  // Skip to the first non-blank character.
640  //
641  while (*token && *token == ' ') token ++;
642  if (!*token) {token = 0; return 0;}
643  tpoint = token;
644 
645  // Find the end of the token.
646  //
647  if (lowcase) while (*token && *token != ' ')
648  {*token = (char)tolower((int)*token); token++;}
649  else while (*token && *token != ' ') {token++;}
650  if (*token) {*token = '\0'; token++;}
651 
652  // All done here.
653  //
654  return tpoint;
655 }
656 
657 char *XrdOucStream::GetToken(char **rest, int lowcase)
658 {
659  char *tpoint;
660 
661  // Get the next token
662  //
663  if (!(tpoint = GetToken(lowcase))) return tpoint;
664 
665  // Skip to the first non-blank character.
666  //
667  while (*token && *token == ' ') token ++;
668  if (rest) *rest = token;
669 
670 
671  // All done.
672  //
673  return tpoint;
674 }
675 
676 /******************************************************************************/
677 /* G e t F i r s t W o r d */
678 /******************************************************************************/
679 
680 char *XrdOucStream::GetFirstWord(int lowcase)
681 {
682  // If in the middle of a line, flush to the end of the line. Suppress
683  // variable substitution when doing this to avoid errors.
684  //
685  if (xline)
686  {XrdOucEnv *oldEnv = SetEnv(0);
687  while(GetWord(lowcase)) {}
688  SetEnv(oldEnv);
689  }
690  return GetWord(lowcase);
691 }
692 
693 /******************************************************************************/
694 /* G e t M y F i r s t W o r d */
695 /******************************************************************************/
696 
698 {
699  char *var;
700  int skip2fi = 0;
701 
702  Echo();
703 
704  if (!myInst)
705  {if (!myEnv) return add2llB(GetFirstWord(lowcase), 1);
706  else {while((var = GetFirstWord(lowcase)) && !isSet(var)) {}
707  return add2llB(var, 1);
708  }
709  }
710 
711  do {if (!(var = GetFirstWord(lowcase)))
712  {if (sawif && !ecode)
713  {ecode = EINVAL;
714  if (Eroute) Eroute->Emsg("Stream", "Missing 'fi' for last 'if'.");
715  }
716  return add2llB(var, 1);
717  }
718 
719  add2llB(var, 1);
720 
721  if (!strcmp("continue", var))
722  {if (!docont()) return 0;
723  continue;
724  }
725 
726  if ( !strcmp("if", var)) var = doif();
727  if (var && !strcmp("else", var)) var = doelse();
728  if (var && !strcmp("fi", var))
729  {if (sawif) sawif = skpel = skip2fi = 0;
730  else {if (Eroute)
731  Eroute->Emsg("Stream", "No preceding 'if' for 'fi'.");
732  ecode = EINVAL;
733  }
734  continue;
735  }
736  if (var && (!myEnv || !isSet(var))) return add2llB(var, 1);
737  } while (1);
738 
739  return 0;
740 }
741 
742 /******************************************************************************/
743 /* G e t W o r d */
744 /******************************************************************************/
745 
746 char *XrdOucStream::GetWord(int lowcase)
747 {
748  char *wp, *ep;
749 
750  // A call means the first token was acceptable and we continuing to
751  // parse, hence the line is echoable.
752  //
753  if (llBok == 1) llBok = 2;
754 
755  // If we have a token, return it
756  //
757  xline = 1;
758  while((wp = GetToken(lowcase)))
759  {if (!myEnv) return add2llB(wp);
760  if ((wp = vSubs(wp)) && *wp) return add2llB(wp);
761  }
762 
763  // If no continuation allowed, return a null (but only once)
764  //
765  if (!xcont) {xcont = 1; xline = 0; return (char *)0;}
766 
767  // Find the next non-blank non-comment line
768  //
769 do {while(GetLine())
770  {// Get the first token (none if it is a blank line)
771  //
772  if (!(wp = GetToken(lowcase))) continue;
773 
774  // If token starts with a pound sign, skip the line
775  //
776  if (*wp == '#') continue;
777 
778  // Process continuations (last non-blank character is a back-slash)
779  //
780  ep = bnext-2;
781  while (ep >= buff && *ep == ' ') ep--;
782  if (ep < buff) continue;
783  if (*ep == '\\') {xcont = 1; *ep = '\0';}
784  else xcont = 0;
785  return add2llB((myEnv ? vSubs(wp) : wp));
786  }
787 
788  if (myInfo && myInfo->fcList)
789  {if (myInfo->itFC == myInfo->fcList->end())
790  {bleft = 0;
791  flags |= XrdOucStream_EOM;
792  break;
793  }
794  const char *path = (*(myInfo->itFC)).c_str();
795  myInfo->itFC++;
796  if (!docontF(path)) break;
797  bleft = 0;
798  flags &= ~XrdOucStream_EOM;
799  } else break;
800  } while(true);
801 
802  xline = 0;
803  return (char *)0;
804 }
805 
806 /******************************************************************************/
807 /* G e t R e s t */
808 /******************************************************************************/
809 
810 int XrdOucStream::GetRest(char *theBuff, int Blen, int lowcase)
811 {
812  char *tp, *myBuff = theBuff;
813  int tlen;
814 
815 // Get remaining tokens
816 //
817  theBuff[0] = '\0';
818  while ((tp = GetWord(lowcase)))
819  {tlen = strlen(tp);
820  if (tlen+1 >= Blen) return 0;
821  if (myBuff != theBuff) {*myBuff++ = ' '; Blen--;}
822  strcpy(myBuff, tp);
823  Blen -= tlen; myBuff += tlen;
824  }
825 
826 // All done
827 //
828  add2llB(0);
829  return 1;
830 }
831 
832 /******************************************************************************/
833 /* R e t T o k e n */
834 /******************************************************************************/
835 
837 {
838  // Check if we can back up
839  //
840  if (!token || token == recp) return;
841 
842  // Find the null byte for the token and remove it, if possible
843  //
844  while(*token && token != recp) token--;
845  if (token != recp)
846  {if (token+1 != bnext) *token = ' ';
847  token--;
848  while(*token && *token != ' ' && token != recp) token--;
849  if (token != recp) token++;
850  }
851 
852  // If saving line, we must do the same for the saved line
853  //
854  if (llBuff)
855  while(llBcur != llBuff && *llBcur != ' ') {llBcur--; llBleft++;}
856 }
857 
858 /******************************************************************************/
859 /* P u t */
860 /******************************************************************************/
861 
862 int XrdOucStream::Put(const char *data, const int dlen) {
863  int dcnt = dlen, retc;
864 
865  if (flags & XrdOucStream_BUSY) {ecode = ETXTBSY; return -1;}
866 
867  while(dcnt)
868  {do { retc = write(FE, (const void *)data, (size_t)dlen);}
869  while (retc < 0 && errno == EINTR);
870  if (retc >= 0) dcnt -= retc;
871  else {flags |= XrdOucStream_BUSY;
872  Erp(Put, errno, "write to stream", 0);
873  flags &= ~XrdOucStream_BUSY;
874  return -1;
875  }
876  }
877  return 0;
878 }
879 
880 int XrdOucStream::Put(const char *datavec[], const int dlenvec[]) {
881  int i, retc, dlen;
882  const char *data;
883 
884  if (flags & XrdOucStream_BUSY) {ecode = ETXTBSY; return -1;}
885 
886  for (i = 0; datavec[i]; i++)
887  {data = datavec[i]; dlen = dlenvec[i];
888  while(dlen)
889  {do { retc = write(FE, (const void *)data, (size_t)dlen);}
890  while (retc < 0 && errno == EINTR);
891  if (retc >= 0) {data += retc; dlen -= retc;}
892  else {flags |= XrdOucStream_BUSY;
893  Erp(Put, errno, "write to stream",0);
894  flags &= ~XrdOucStream_BUSY;
895  return -1;
896  }
897  }
898  }
899  return 0;
900 }
901 
902 /******************************************************************************/
903 /* P u t L i n e */
904 /******************************************************************************/
905 
906 int XrdOucStream::PutLine(const char *data, int dlen)
907 {
908  static const int plSize = 2048;
909 
910 // Allocate a buffer if one is not allocated
911 //
912  if (!buff)
913  {if (!(buff = (char *)malloc(plSize)))
914  return Erq(Attach, errno, "allocate stream buffer");
915  bsize = plSize;
916  }
917 
918 // Adjust dlen
919 //
920  if (dlen <= 0) dlen = strlen(data);
921  if (dlen >= bsize) dlen = bsize-1;
922 
923 // Simply insert the line into the buffer, truncating if need be
924 //
925  bnext = recp = token = buff; // This will always be true at this point
926  if (dlen <= 0)
927  {*buff = '\0';
928  flags |= XrdOucStream_EOM;
929  bleft = 0;
930  } else {
931  strncpy(buff, data, dlen);
932  *(buff+dlen) = 0;
933  bleft = dlen+1;
934  }
935 // All done
936 //
937  return 0;
938 }
939 
940 /******************************************************************************/
941 /* W a i t 4 D a t a */
942 /******************************************************************************/
943 
945 {
946  struct pollfd polltab = {FD, POLLIN|POLLRDNORM, 0};
947  int retc;
948 
949 // Wait until we can actually read something
950 //
951  do {retc = poll(&polltab, 1, msMax);} while(retc < 0 && errno == EINTR);
952  if (retc != 1) return (retc ? errno : -1);
953 
954 // Return correct value
955 //
956  return (polltab.revents & (POLLIN|POLLRDNORM) ? 0 : EIO);
957 }
958 
959 /******************************************************************************/
960 /* P r i v a t e M e t h o d s */
961 /******************************************************************************/
962 /******************************************************************************/
963 /* a d d 2 C F G */
964 /******************************************************************************/
965 
966 void XrdOucStream::add2CFG(const char *data, bool isCMT)
967 {
968  if (isCMT) theCFG->append("# ");
969  theCFG->append(data);
970  theCFG->append('\n');
971 }
972 
973 /******************************************************************************/
974 /* a d d 2 l l B */
975 /******************************************************************************/
976 
977 char *XrdOucStream::add2llB(char *tok, int reset)
978 {
979  int tlen;
980 
981 // Return if not saving data
982 //
983  if (!llBuff) return tok;
984 
985 // Check if we should flush the previous line
986 //
987  if (reset)
988  {llBok = 1;
989  llBcur = llBuff;
990  llBleft= llBsz;
991  *llBuff = '\0';
992  } else if (!llBok) return tok;
993  else {llBok = 2;
994  if (llBleft >= 2)
995  {*llBcur++ = ' '; *llBcur = '\0'; llBleft--;}
996  }
997 
998 // Add in the new token
999 //
1000  if (tok)
1001  {tlen = strlen(tok);
1002  if (tlen < llBleft)
1003  {strcpy(llBcur, tok); llBcur += tlen; llBleft -= tlen;}
1004  }
1005  return tok;
1006 }
1007 
1008 /******************************************************************************/
1009 /* E c h o */
1010 /******************************************************************************/
1011 
1012 bool XrdOucStream::Echo(int ec, const char *t1, const char *t2, const char *t3)
1013 {
1014  if (Eroute)
1015  {if (t1) Eroute->Emsg("Stream", t1, t2, t3);
1016  if (llBok > 1 && Verbose && llBuff) Eroute->Say(llPrefix,llBuff);
1017  }
1018  ecode = ec;
1019  llBok = 0;
1020  return false;
1021 }
1022 
1023 /******************************************************************************/
1024 /* d o c o n t */
1025 /******************************************************************************/
1026 
1027 bool XrdOucStream::docont()
1028 {
1029  char *theWord;
1030 
1031 // A continue is not valid within the scope of an if
1032 //
1033  if (sawif) return Echo(EINVAL, "'continue' invalid within 'if-fi'.");
1034 
1035 // Get the path (keep case), if none then ignore this continue
1036 //
1037  theWord = GetWord();
1038  if (!theWord)
1039  {Echo();
1040  return true;
1041  }
1042 
1043 // Prepare to handle the directive
1044 //
1045  contHandler cH;
1046  cH.path = strdup(theWord);
1047 
1048 // Grab additioal tokens which may be suffixes
1049 //
1050  theWord = GetWord();
1051  while(theWord && *theWord == '*')
1052  {if (!*(theWord+1)) return Echo(EINVAL, "suffix missing after '*'.");
1053  cH.Add(theWord+1);
1054  theWord = GetWord();
1055  }
1056 
1057 // If we have a token, it better be an if
1058 //
1059  if (theWord && strcmp(theWord, "if"))
1060  return Echo(EINVAL, "expecting 'if' but found", theWord);
1061 
1062 // Process the 'if'
1063 //
1064  if (theWord && !XrdOucUtils::doIf(Eroute, *this, "continue directive",
1065  myInfo->myHost,myInfo->myName,myInfo->myExec))
1066  return true;
1067  Echo();
1068 // if (Eroute) Eroute->Say(llPrefix, "continue ", path, " if true");
1069 // if (Eroute) Eroute->Say(llPrefix, "continue ", bnext);
1070  return docont(cH.path, cH.tlP);
1071 }
1072 
1073 /******************************************************************************/
1074 
1075 bool XrdOucStream::docont(const char *path, XrdOucTList *tlP)
1076 {
1077  struct stat Stat;
1078  bool noentok;
1079 
1080 // A continue directive in the context of a continuation is illegal
1081 //
1082  if ((myInfo && myInfo->fcList) || (flags & XrdOucStream_CONT) != 0)
1083  return Echo(EINVAL, "'continue' in a continuation is not allowed.");
1084 
1085 // Check if this file must exist (we also take care of empty paths)
1086 //
1087  if ((noentok = (*path == '?')))
1088  {path++;
1089  if (!(*path)) return true;
1090  }
1091 
1092 // Check if this is a file or directory
1093 //
1094  if (stat(path, &Stat))
1095  {if (errno == ENOENT && noentok) return true;
1096  if (Eroute)
1097  {Eroute->Emsg("Stream", errno, "open", path);
1098  ecode = ECANCELED;
1099  } else ecode = errno;
1100  return false;
1101  }
1102 
1103 // For directory continuation, there is much more to do (this can only happen
1104 // once). Note that we used to allow a limited number of chained file
1105 // continuations. No more, but we are still setup to easily do so.
1106 //
1107  if ((Stat.st_mode & S_IFMT) == S_IFDIR)
1108  {if (!docontD(path, tlP)) return false;
1109  path = (*(myInfo->itFC)).c_str();
1110  myInfo->itFC++;
1111  } else flags |= XrdOucStream_CADD;
1112 
1113 // if ((flags & XrdOucStream_CONT) > XrdOucStream_CMAX)
1114 // {if (Eroute)
1115 // {Eroute->Emsg("Stream", EMLINK, "continue to", path);
1116 // ecode = ECANCELED;
1117 // } else ecode = EMLINK;
1118 // return false;
1119 // }
1120 // }
1121 
1122 // Continue with the next file
1123 //
1124  return docontF(path, noentok);
1125 }
1126 
1127 /******************************************************************************/
1128 /* d o c o n t D */
1129 /******************************************************************************/
1130 
1131 bool XrdOucStream::docontD(const char *path, XrdOucTList *tlP)
1132 {
1133  static const mode_t isXeq = S_IXUSR | S_IXGRP | S_IXOTH;
1134  XrdOucNSWalk nsWalk(Eroute, path, 0, XrdOucNSWalk::retFile);
1135  int rc;
1136 
1137 // Get all of the file entries in this directory
1138 //
1139  XrdOucNSWalk::NSEnt *nsX, *nsP = nsWalk.Index(rc);
1140  if (rc)
1141  {if (Eroute) Eroute->Emsg("Stream", rc, "index config files in", path);
1142  ecode = ECANCELED;
1143  return false;
1144  }
1145 
1146 // Keep only files of interest
1147 //
1148  myInfo->fcList = new std::set<std::string>;
1149  while((nsX = nsP))
1150  {nsP = nsP->Next;
1151  if ((nsX->Stat.st_mode & isXeq) == 0 && KeepFile(nsX->File, tlP))
1152  myInfo->fcList->insert(std::string(nsX->Path));
1153  delete nsX;
1154  }
1155 
1156 // Check if we have anything in the map
1157 //
1158  if (myInfo->fcList->size() == 0)
1159  {delete myInfo->fcList;
1160  myInfo->fcList = 0;
1161  return false;
1162  }
1163 
1164 // All done
1165 //
1166  myInfo->itFC = myInfo->fcList->begin();
1167  return true;
1168 }
1169 
1170 /******************************************************************************/
1171 /* c o n t F */
1172 /******************************************************************************/
1173 
1174 bool XrdOucStream::docontF(const char *path, bool noentok)
1175 {
1176  int cFD;
1177 
1178 // Open the file and handle any errors
1179 //
1180  if ((cFD = XrdSysFD_Open(path, O_RDONLY)) < 0)
1181  {if (errno == ENOENT && noentok) return true;
1182  if (Eroute)
1183  {Eroute->Emsg("Stream", errno, "open", path);
1184  ecode = ECANCELED;
1185  } else ecode = errno;
1186  return false;
1187  }
1188 
1189 // Continue to the next file
1190 //
1191  if (XrdSysFD_Dup2(cFD, FD) < 0)
1192  {if (Eroute)
1193  {Eroute->Emsg("Stream", ecode, "switch to", path);
1194  close(cFD);
1195  ecode = ECANCELED;
1196  } else ecode = errno;
1197  return false;
1198  }
1199 
1200 // Indicate we are switching to anther file
1201 //
1202  if (Eroute) Eroute->Say("Config continuing with file ", path, " ...");
1203  bleft = 0;
1204  close(cFD);
1205  return true;
1206 }
1207 
1208 /******************************************************************************/
1209 /* d o e l s e */
1210 /******************************************************************************/
1211 
1212 char *XrdOucStream::doelse()
1213 {
1214  char *var;
1215 
1216 // An else must be preceeded by an if and not by a naked else
1217 //
1218  if (!sawif || sawif == 2)
1219  {if (Eroute) Eroute->Emsg("Stream", "No preceding 'if' for 'else'.");
1220  ecode = EINVAL;
1221  return 0;
1222  }
1223 
1224 // If skipping all else caluses, skip all lines until we reach a fi
1225 //
1226  if (skpel)
1227  {while((var = GetFirstWord()))
1228  {if (!strcmp("fi", var)) return var;}
1229  if (Eroute) Eroute->Emsg("Stream", "Missing 'fi' for last 'if'.");
1230  ecode = EINVAL;
1231  return 0;
1232  }
1233 
1234 // Elses are still possible then process one of them
1235 //
1236  do {if (!(var = GetWord())) // A naked else will always succeed
1237  {sawif = 2;
1238  return 0;
1239  }
1240  if (strcmp("if", var)) // An else may only be followed by an if
1241  {Eroute->Emsg("Stream","'else",var,"' is invalid.");
1242  ecode = EINVAL;
1243  return 0;
1244  }
1245  sawif = 0;
1246  flags |= XrdOucStream_ELIF;
1247  var = doif();
1248  flags &= ~XrdOucStream_ELIF;
1249  } while(var && !strcmp("else", var));
1250  return var;
1251 }
1252 
1253 /******************************************************************************/
1254 /* d o i f */
1255 /******************************************************************************/
1256 
1257 /* Function: doif
1258 
1259  Purpose: To parse the directive: if [<hlist>] [exec <pgm>] [named <nlist>]
1260  fi
1261 
1262  <hlist> Apply subsequent directives until the 'fi' if this host
1263  is one of the hosts in the blank separated list. Each
1264  host name may have a single asterisk somewhere in the
1265  name to indicate where arbitrry characters lie.
1266 
1267  <pgm> Apply subsequent directives if this program is named <pgm>.
1268 
1269  <nlist> Apply subsequent directives if this host instance name
1270  is in the list of blank separated names.
1271 
1272  Notes: 1) At least one of hlist, pgm, or nlist must be specified.
1273  2) The combination of hlist, pgm, nlist must all be true.
1274 
1275  Output: 0 upon success or !0 upon failure.
1276 */
1277 
1278 char *XrdOucStream::doif()
1279 {
1280  char *var, ifLine[512];
1281  int rc;
1282 
1283 // Check if the previous if was properly closed
1284 //
1285  if (sawif)
1286  {if (Eroute) Eroute->Emsg("Stream", "Missing 'fi' for last 'if'.");
1287  ecode = EINVAL;
1288  }
1289 
1290 // Save the line for context message should we get an error
1291 //
1292  snprintf(ifLine, sizeof(ifLine), "%s", token);
1293 
1294 // Check if we should continue
1295 //
1296  sawif = 1; skpel = 0;
1297  if ((rc = XrdOucUtils::doIf(Eroute,*this,"if directive",
1298  myInfo->myHost,myInfo->myName,myInfo->myExec)))
1299  {if (rc >= 0) skpel = 1;
1300  else {ecode = EINVAL;
1301  if(Eroute) Eroute->Say(llPrefix,
1302  (flags & XrdOucStream_ELIF ? "else " : 0),
1303  "if ", ifLine);
1304  }
1305  return 0;
1306  }
1307 
1308 // Skip all lines until we reach a fi or else
1309 //
1310  while((var = GetFirstWord()))
1311  {if (!strcmp("fi", var)) return var;
1312  if (!strcmp("else", var)) return var;
1313  }
1314 
1315 // Make sure we have a fi
1316 //
1317  if (!var)
1318  {if (Eroute) Eroute->Emsg("Stream", "Missing 'fi' for last 'if'.");
1319  ecode = EINVAL;
1320  }
1321  return 0;
1322 }
1323 
1324 /******************************************************************************/
1325 /* g e t V a l u e */
1326 /******************************************************************************/
1327 
1328 int XrdOucStream::getValue(const char *path, char *vbuff, int vbsz)
1329 {
1330  struct stat Stat;
1331  int n, rc = 0, vFD;
1332 
1333 // Make sure the file exists and it not too big
1334 //
1335  if (stat(path, &Stat)) return errno;
1336  if (Stat.st_size >= vbsz) return EFBIG;
1337 
1338 // Open the file and read it in
1339 //
1340  if ((vFD = XrdSysFD_Open(path, O_RDONLY)) < 0) return errno;
1341  if ((n = read(vFD, vbuff, vbsz-1)) >= 0) vbuff[n] = 0;
1342  else rc = errno;
1343 
1344 // All done
1345 //
1346  close(vFD);
1347  return rc;
1348 }
1349 
1350 /******************************************************************************/
1351 /* i s S e t */
1352 /******************************************************************************/
1353 
1354 int XrdOucStream::isSet(char *var)
1355 {
1356  static const char *Mtxt1[2] = {"setenv", "set"};
1357  static const char *Mtxt2[2] = {"Setenv variable", "Set variable"};
1358  static const char *Mtxt3[2] = {"Variable", "Environmental variable"};
1359  char *tp, *vn, *vp, *pv, Vname[64] = "", ec, Nil = 0, sawIT = 0;
1360  int Set = 1;
1361  char valBuff[1024] = "";
1362 
1363 // Process set var = value | set -v | setenv = value
1364 //
1365  if (!strcmp("setenv", var)) Set = 0;
1366  else if (strcmp("set", var)) return 0;
1367 
1368 // Now get the operand
1369 //
1370  if (!(tp = GetToken()))
1371  return xMsg("Missing variable name after '",Mtxt1[Set],"'.");
1372 
1373 // Option flags only apply to set not setenv
1374 //
1375  if (Set)
1376  {if (!strcmp(tp, "-q")) {if (llBuff) {free(llBuff); llBuff = 0;}; return 1;}
1377  if (!strcmp(tp, "-v") || !strcmp(tp, "-V"))
1378  {if (Eroute)
1379  {if (!llBuff) llBuff = (char *)malloc(llBsz);
1380  llBcur = llBuff; llBok = 0; llBleft = llBsz; *llBuff = '\0';
1381  Verbose = (strcmp(tp, "-V") ? 1 : 2);
1382  }
1383  return 1;
1384  }
1385  }
1386 
1387 // Next may be var= | var | var=val | var< | var<val
1388 //
1389  if ((vp = index(tp, '=')) || (vp = index(tp, '<')))
1390  {sawIT = *vp; *vp = '\0'; vp++;}
1391  if (strlcpy(Vname, tp, sizeof(Vname)) >= sizeof(Vname))
1392  return xMsg(Mtxt2[Set],tp,"is too long.");
1393  if (!Set && !strncmp("XRD", Vname, 3))
1394  return xMsg("Setenv variable",tp,"may not start with 'XRD'.");
1395 
1396 // Verify that variable is only an alphanum
1397 //
1398  tp = Vname;
1399  while (*tp && (*tp == '_' || isalnum(*tp))) tp++;
1400  if (*tp) return xMsg(Mtxt2[Set], Vname, "is non-alphanumeric");
1401 
1402 // Now look for the value
1403 //
1404  if (sawIT) tp = vp;
1405  else if (!(tp = GetToken()) || (*tp != '=' && *tp != '<'))
1406  return xMsg("Missing '=' after", Mtxt1[Set], Vname);
1407  else {sawIT = *tp; tp++;}
1408  if (!*tp && !(tp = GetToken())) tp = (char *)"";
1409 
1410 // Handle reading value from a file
1411 //
1412  if (sawIT == '<')
1413  {int rc;
1414  if (!*tp) return xMsg(Mtxt2[Set], Vname, "path to value not specified");
1415  if ((rc = getValue(tp, valBuff, sizeof(valBuff))))
1416  {char tbuff[512];
1417  snprintf(tbuff, sizeof(tbuff), "cannot be set via path %s; %s",
1418  tp, XrdSysE2T(rc));
1419  return xMsg(Mtxt2[Set], Vname, tbuff);
1420  }
1421  tp = valBuff;
1422  }
1423 
1424 // The value may be '$var', in which case we need to get it out of the env if
1425 // this is a set or from our environment if this is a setenv
1426 //
1427  if (*tp != '$') vp = tp;
1428  else {pv = tp+1;
1429  if (*pv == '(') ec = ')';
1430  else if (*pv == '{') ec = '}';
1431  else if (*pv == '[') ec = ']';
1432  else ec = 0;
1433  if (!ec) vn = tp+1;
1434  else {while(*pv && *pv != ec) pv++;
1435  if (*pv) *pv = '\0';
1436  else ec = 0;
1437  vn = tp+2;
1438  }
1439  if (!*vn) {*pv = ec; return xMsg("Variable", tp, "is malformed.");}
1440  if (!(vp = (Set ? getenv(vn) : myEnv->Get(vn))))
1441  {if (ec != ']')
1442  {xMsg(Mtxt3[Set],vn,"is undefined."); *pv = ec; return 1;}
1443  vp = &Nil;
1444  }
1445  *pv = ec;
1446  }
1447 
1448 // Make sure the value is not too long
1449 //
1450  if ((int)strlen(vp) > maxVLen)
1451  return xMsg(Mtxt3[Set], Vname, "value is too long.");
1452 
1453 // Set the value
1454 //
1455  if (Verbose == 2 && Eroute)
1456  if (!(pv = (Set ? myEnv->Get(Vname) : getenv(Vname))) || strcmp(vp, pv))
1457  {char vbuff[1024];
1458  strcpy(vbuff, Mtxt1[Set]); strcat(vbuff, " "); strcat(vbuff, Vname);
1459  Eroute->Say(vbuff, " = ", vp);
1460  }
1461  if (Set) myEnv->Put(Vname, vp);
1462  else if (!(pv = getenv(Vname)) || strcmp(vp,pv))
1463  XrdOucEnv::Export(Vname, vp);
1464  return 1;
1465 }
1466 
1467 /******************************************************************************/
1468 /* v S u b s */
1469 /******************************************************************************/
1470 
1471 char *XrdOucStream::vSubs(char *Var)
1472 {
1473  char *vp, *sp, *dp, *vnp, ec, bkp, valbuff[maxVLen], Nil = 0;
1474  int n;
1475 
1476 // Check for substitution
1477 //
1478  if (!Var) return Var;
1479  sp = Var; dp = valbuff; n = maxVLen-1; *varVal = '\0';
1480 
1481  while(*sp && n > 0)
1482  {if (*sp == '\\') {*dp++ = *(sp+1); sp +=2; n--; continue;}
1483  if (*sp != '$'
1484  || (!isalnum(*(sp+1)) && !index("({[", *(sp+1))))
1485  {*dp++ = *sp++; n--; continue;}
1486  sp++; vnp = sp;
1487  if (*sp == '(') ec = ')';
1488  else if (*sp == '{') ec = '}';
1489  else if (*sp == '[') ec = ']';
1490  else ec = 0;
1491  if (ec) {sp++; vnp++;}
1492  while(isalnum(*sp)) sp++;
1493  if (ec && *sp != ec)
1494  {xMsg("Variable", vnp-2, "is malformed."); return varVal;}
1495  bkp = *sp; *sp = '\0';
1496  if (!(vp = myEnv->Get(vnp)))
1497  {if (ec != ']') xMsg("Variable", vnp, "is undefined.");
1498  vp = &Nil;
1499  }
1500  while(n && *vp) {*dp++ = *vp++; n--;}
1501  if (*vp) break;
1502  if (ec) sp++;
1503  else *sp = bkp;
1504  }
1505 
1506  if (*sp) xMsg("Substituted text too long using", Var);
1507  else {*dp = '\0'; strcpy(varVal, valbuff);}
1508  return varVal;
1509 }
1510 
1511 /******************************************************************************/
1512 /* x M s g */
1513 /******************************************************************************/
1514 
1515 int XrdOucStream::xMsg(const char *txt1, const char *txt2, const char *txt3)
1516 {
1517  if (Eroute) Eroute->Emsg("Stream", txt1, txt2, txt3);
1518  ecode = EINVAL;
1519  return 1;
1520 }
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:48
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:232
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