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