39#if !defined(__linux__) && !defined(__CYGWIN__) && !defined(__GNU__) && !defined(__FreeBSD__)
47#include "XrdSys/XrdWin32.hh"
72#define XrdOucStream_EOM 0x01
73#define XrdOucStream_BUSY 0x02
74#define XrdOucStream_ELIF 0x80
76#define XrdOucStream_CADD 0x010000
77#define XrdOucStream_CONT 0xff0000
78#define XrdOucStream_CMAX 0x0f0000
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)
86#define Erx(p, a, b) std::cerr <<#p <<": " <<XrdSysE2T(a) <<' ' <<b <<std::endl;
109 std::set<std::string>::iterator
itFC;
125void Add(
const char *sfx) {tlP =
new XrdOucTList(sfx,(
int)strlen(sfx),tlP);}
127 contHandler() : path(0), tlP(0) {}
129 while(tlP) {tlN = tlP; tlP = tlP->
next;
delete tlN;}
130 if (path) free(path);
143 struct sfxList {
const char *txt;
int len;};
144 static sfxList sfx[] = {{
".cfsaved", 8},
151 static int sfxLNum =
sizeof(sfx)/
sizeof(
struct sfxList);
156 if (*fname ==
'.')
return false;
163 {
if (tlP->ival[0] < n && !strcmp(tlP->
text, fname+n-tlP->ival[0]))
172 for (
int i = 0; i < sfxLNum; i++)
173 {
if (sfx[i].len < n && !strcmp(sfx[i].txt, fname+n-sfx[i].len))
194 {myInst = strdup(ifname);
196 if (!(cp = index(myInst,
' '))) {cp = myInst; myInfo->
myExec = 0;}
197 else {*cp =
'\0'; cp++;
198 myInfo->
myExec = (*myInst ? myInst : 0);
200 if ( (myInfo->
myHost = index(cp,
'@')))
201 {*(myInfo->
myHost) =
'\0';
203 myInfo->
myName = (*cp ? cp : 0);
205 }
else {myInst = 0; myInfo = 0;}
227 {llBuff = (
char *)malloc(llBsz);
228 llBcur = llBuff; llBok = 0; llBleft = llBsz; *llBuff =
'\0';
237 varVal = (myEnv ?
new char[maxVLen+1] : 0);
247 if (
Attach(infd, bsz))
return -1;
264 else if (!(buff = (
char *)malloc(bsz+1)))
265 return Erq(
Attach, errno,
"allocate stream buffer");
269 FD= FE = FileDescriptor;
282 {llBcur = llBuff; *llBuff =
'\0'; llBleft = llBsz; llBok = 0;}
294 if (theCFG && cVec && cVec[0])
295 {
if (linefeed) theCFG->
append(
"\n# ");
296 else theCFG->
append(
"# ");
298 while(cVec[i]) theCFG->
append(cVec[i++]);
328 if (!hold && child)
Drain();
333 if (FD >= 0)
close(FD);
334 if (FE >= 0 && FE != FD)
close(FE);
338 if (buff) free(buff);
348 {
if (Verbose && *llBuff && llBok > 1)
349 {
if (Eroute) Eroute->
Say(llPrefix, llBuff);
350 if (theCFG) add2CFG(llBuff);
375 if (child) {kill(-child, 9);
376 do {retc = waitpid(child, &Status, 0);}
377 while(retc > 0 || (retc == -1 && errno == EINTR));
382 TerminateProcess((HANDLE)child, 0);
395 if (llBok > 1 && Verbose && llBuff)
396 {
if (Eroute) Eroute->
Say(llPrefix,llBuff);
397 if (theCFG) add2CFG(llBuff);
408 if (llBok && Verbose && llBuff)
409 {
if (Eroute) Eroute->
Say(llPrefix,llBuff);
410 if (capture && theCFG) add2CFG(llBuff);
422 char *cmd, *origcmd, *parm[
MaxARGC];
429 origcmd = cmd = (
char *)malloc(strlen(theCmd)+1);
434 for (j = 0; j <
MaxARGC-1 && *cmd; j++)
435 {
while(*cmd ==
' ') cmd++;
438 while(*cmd && *cmd !=
' ') cmd++;
439 if (*cmd) {*cmd =
'\0'; cmd++;}
445 int ret = j > 0 ?
Exec(parm, inrd, efd) : EINVAL;
452 int fildes[2], Child_in = -1, Child_out = -1, Child_log = -1;
458 return Err(
Exec, errno,
"create input pipe for", parm[0]);
460 fcntl(fildes[0], F_SETFD, FD_CLOEXEC);
461 Attach(fildes[0]); Child_out = fildes[1];
466 return Err(
Exec, errno,
"create output pipe for", parm[0]);
468 fcntl(fildes[1], F_SETFD, FD_CLOEXEC);
469 FE = fildes[1]; Child_in = fildes[0];
472 }
else {Child_out = FD; Child_in = FE;}
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;
486 if ((child = fork()))
488 {
close(Child_in);
close(Child_out); forkMutex.UnLock();
489 return Err(
Exec, errno,
"fork request process for", parm[0]);
492 if (inrd)
close(Child_in );
493 if (!efd && Child_log >= 0)
close(Child_log);
495 setpgid(child, child);
507 {
if (dup2(Child_in, STDIN_FILENO) < 0)
508 {
Erx(
Exec, errno,
"setting up standard in for " <<parm[0]);
510 }
else if (Child_in != Child_out)
close(Child_in);
517 {
if (dup2(Child_out, STDOUT_FILENO) < 0)
518 {
Erx(
Exec, errno,
"setting up standard out for " <<parm[0]);
520 }
else if (Child_out != Child_log)
close(Child_out);
526 {
if (dup2(Child_log, STDERR_FILENO) < 0)
527 {
Erx(
Exec, errno,
"set up standard err for " <<parm[0]);
529 }
else close(Child_log);
537 if ((envP = (
char **)myEnv->
GetPtr(
"XrdEnvars**")))
538 while(envP[i]) {putenv(envP[i]); i++;}
545 execv(parm[0], parm);
546 Erx(
Exec, errno,
"executing " <<parm[0]);
566 {recp = bnext; bcnt = bleft;
567 for (bp = bnext; bcnt--; bp++)
568 if (!*bp || *bp ==
'\n')
576 else if (notabs && *bp ==
'\t') *bp =
' ';
580 bnext = stpncpy(buff, bnext, bleft);
586 bcnt = bsize - (bnext - buff) -1;
594 {
do { retc =
read(FD, (
void *)bp, (
size_t)bcnt); }
595 while (retc < 0 && errno == EINTR);
597 if (retc < 0) {
Erp(
GetLine,errno,
"read request",0);
return (
char *)0;}
608 if (!*bp || *bp ==
'\n')
615 if (notabs && *bp ==
'\t') *bp =
' ';
622 Erp(
GetLine, EMSGSIZE,
"read full message", 0);
623 buff[bsize-1] =
'\0';
636 if (!token)
return (
char *)NULL;
640 while (*token && *token ==
' ') token ++;
641 if (!*token) {token = 0;
return 0;}
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++;}
662 if (!(tpoint =
GetToken(lowcase)))
return tpoint;
666 while (*token && *token ==
' ') token ++;
667 if (rest) *rest = token;
705 else {
while((var =
GetFirstWord(lowcase)) && !isSet(var)) {}
706 return add2llB(var, 1);
711 {
if (sawif && !ecode)
713 if (Eroute) Eroute->
Emsg(
"Stream",
"Missing 'fi' for last 'if'.");
715 return add2llB(var, 1);
720 if (!strcmp(
"continue", var))
721 {
if (!docont())
return 0;
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;
730 Eroute->
Emsg(
"Stream",
"No preceding 'if' for 'fi'.");
735 if (var && (!myEnv || !isSet(var)))
return add2llB(var, 1);
752 if (llBok == 1) llBok = 2;
758 {
if (!myEnv)
return add2llB(wp);
759 if ((wp = vSubs(wp)) && *wp)
return add2llB(wp);
764 if (!xcont) {xcont = 1; xline = 0;
return (
char *)0;}
771 if (!(wp =
GetToken(lowcase)))
continue;
775 if (*wp ==
'#')
continue;
780 while (ep >= buff && *ep ==
' ') ep--;
781 if (ep < buff)
continue;
782 if (*ep ==
'\\') {xcont = 1; *ep =
'\0';}
784 return add2llB((myEnv ? vSubs(wp) : wp));
787 if (myInfo && myInfo->
fcList)
793 const char *path = (*(myInfo->
itFC)).c_str();
795 if (!docontF(path))
break;
797 flags &= ~XrdOucStream_EOM;
811 char *tp, *myBuff = theBuff;
817 while ((tp =
GetWord(lowcase)))
819 if (tlen+1 >= Blen)
return 0;
820 if (myBuff != theBuff) {*myBuff++ =
' '; Blen--;}
822 Blen -= tlen; myBuff += tlen;
839 if (!token || token == recp)
return;
843 while(*token && token != recp) token--;
845 {
if (token+1 != bnext) *token =
' ';
847 while(*token && *token !=
' ' && token != recp) token--;
848 if (token != recp) token++;
854 while(llBcur != llBuff && *llBcur !=
' ') {llBcur--; llBleft++;}
862 int dcnt = dlen, retc;
867 {
do { retc =
write(FE, (
const void *)data, (
size_t)dlen);}
868 while (retc < 0 && errno == EINTR);
869 if (retc >= 0) dcnt -= retc;
871 Erp(
Put, errno,
"write to stream", 0);
872 flags &= ~XrdOucStream_BUSY;
885 for (i = 0; datavec[i]; i++)
886 {data = datavec[i]; dlen = dlenvec[i];
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;}
892 Erp(
Put, errno,
"write to stream",0);
893 flags &= ~XrdOucStream_BUSY;
907 static const int plSize = 2048;
912 {
if (!(buff = (
char *)malloc(plSize)))
913 return Erq(
Attach, errno,
"allocate stream buffer");
919 if (dlen <= 0) dlen = strlen(data);
920 if (dlen >= bsize) dlen = bsize-1;
924 bnext = recp = token = buff;
930 strncpy(buff, data, dlen);
945 struct pollfd polltab = {FD, POLLIN|POLLRDNORM, 0};
950 do {retc = poll(&polltab, 1, msMax);}
while(retc < 0 && errno == EINTR);
951 if (retc != 1)
return (retc ? errno : -1);
955 return (polltab.revents & (POLLIN|POLLRDNORM) ? 0 : EIO);
965void XrdOucStream::add2CFG(
const char *data,
bool isCMT)
967 if (isCMT) theCFG->
append(
"# ");
976char *XrdOucStream::add2llB(
char *tok,
int reset)
982 if (!llBuff)
return tok;
991 }
else if (!llBok)
return tok;
994 {*llBcur++ =
' '; *llBcur =
'\0'; llBleft--;}
1000 {tlen = strlen(tok);
1002 {strcpy(llBcur, tok); llBcur += tlen; llBleft -= tlen;}
1014 {
if (t1) Eroute->
Emsg(
"Stream", t1, t2, t3);
1015 if (llBok > 1 && Verbose && llBuff) Eroute->
Say(llPrefix,llBuff);
1026bool XrdOucStream::docont()
1032 if (sawif)
return Echo(EINVAL,
"'continue' invalid within 'if-fi'.");
1045 cH.path = strdup(theWord);
1050 while(theWord && *theWord ==
'*')
1051 {
if (!*(theWord+1))
return Echo(EINVAL,
"suffix missing after '*'.");
1058 if (theWord && strcmp(theWord,
"if"))
1059 return Echo(EINVAL,
"expecting 'if' but found", theWord);
1069 return docont(cH.path, cH.tlP);
1074bool XrdOucStream::docont(
const char *path,
XrdOucTList *tlP)
1082 return Echo(EINVAL,
"'continue' in a continuation is not allowed.");
1086 if ((noentok = (*path ==
'?')))
1088 if (!(*path))
return true;
1094 {
if (errno == ENOENT && noentok)
return true;
1096 {Eroute->
Emsg(
"Stream", errno,
"open", path);
1098 }
else ecode = errno;
1106 if ((
Stat.st_mode & S_IFMT) == S_IFDIR)
1107 {
if (!docontD(path, tlP))
return false;
1108 path = (*(myInfo->
itFC)).c_str();
1123 return docontF(path, noentok);
1130bool XrdOucStream::docontD(
const char *path,
XrdOucTList *tlP)
1132 static const mode_t isXeq = S_IXUSR | S_IXGRP | S_IXOTH;
1140 {
if (Eroute) Eroute->
Emsg(
"Stream", rc,
"index config files in", path);
1147 myInfo->
fcList =
new std::set<std::string>;
1150 if ((nsX->
Stat.st_mode & isXeq) == 0 && KeepFile(nsX->
File, tlP))
1151 myInfo->
fcList->insert(std::string(nsX->
Path));
1157 if (myInfo->
fcList->size() == 0)
1173bool XrdOucStream::docontF(
const char *path,
bool noentok)
1179 if ((cFD = XrdSysFD_Open(path, O_RDONLY)) < 0)
1180 {
if (errno == ENOENT && noentok)
return true;
1182 {Eroute->
Emsg(
"Stream", errno,
"open", path);
1184 }
else ecode = errno;
1190 if (XrdSysFD_Dup2(cFD, FD) < 0)
1192 {Eroute->
Emsg(
"Stream", ecode,
"switch to", path);
1195 }
else ecode = errno;
1201 if (Eroute) Eroute->
Say(
"Config continuing with file ", path,
" ...");
1211char *XrdOucStream::doelse()
1217 if (!sawif || sawif == 2)
1218 {
if (Eroute) Eroute->
Emsg(
"Stream",
"No preceding 'if' for 'else'.");
1227 {
if (!strcmp(
"fi", var))
return var;}
1228 if (Eroute) Eroute->
Emsg(
"Stream",
"Missing 'fi' for last 'if'.");
1239 if (strcmp(
"if", var))
1240 {Eroute->
Emsg(
"Stream",
"'else",var,
"' is invalid.");
1247 flags &= ~XrdOucStream_ELIF;
1248 }
while(var && !strcmp(
"else", var));
1277char *XrdOucStream::doif()
1279 char *var, ifLine[512];
1285 {
if (Eroute) Eroute->
Emsg(
"Stream",
"Missing 'fi' for last 'if'.");
1291 snprintf(ifLine,
sizeof(ifLine),
"%s", token);
1295 sawif = 1; skpel = 0;
1298 {
if (rc >= 0) skpel = 1;
1299 else {ecode = EINVAL;
1300 if(Eroute) Eroute->
Say(llPrefix,
1310 {
if (!strcmp(
"fi", var))
return var;
1311 if (!strcmp(
"else", var))
return var;
1317 {
if (Eroute) Eroute->
Emsg(
"Stream",
"Missing 'fi' for last 'if'.");
1327int XrdOucStream::getValue(
const char *path,
char *vbuff,
int vbsz)
1334 if (
stat(path, &
Stat))
return errno;
1335 if (
Stat.st_size >= vbsz)
return EFBIG;
1339 if ((vFD = XrdSysFD_Open(path, O_RDONLY)) < 0)
return errno;
1340 if ((n =
read(vFD, vbuff, vbsz-1)) >= 0) vbuff[n] = 0;
1353int XrdOucStream::isSet(
char *var)
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;
1360 char valBuff[1024] =
"";
1364 if (!strcmp(
"setenv", var)) Set = 0;
1365 else if (strcmp(
"set", var))
return 0;
1370 return xMsg(
"Missing variable name after '",Mtxt1[Set],
"'.");
1375 {
if (!strcmp(tp,
"-q")) {
if (llBuff) {free(llBuff); llBuff = 0;};
return 1;}
1376 if (!strcmp(tp,
"-v") || !strcmp(tp,
"-V"))
1378 {
if (!llBuff) llBuff = (
char *)malloc(llBsz);
1379 llBcur = llBuff; llBok = 0; llBleft = llBsz; *llBuff =
'\0';
1380 Verbose = (strcmp(tp,
"-V") ? 1 : 2);
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'.");
1398 while (*tp && (*tp ==
'_' || isalnum(*tp))) tp++;
1399 if (*tp)
return xMsg(Mtxt2[Set], Vname,
"is non-alphanumeric");
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 *)
"";
1413 if (!*tp)
return xMsg(Mtxt2[Set], Vname,
"path to value not specified");
1414 if ((rc = getValue(tp, valBuff,
sizeof(valBuff))))
1416 snprintf(tbuff,
sizeof(tbuff),
"cannot be set via path %s; %s",
1418 return xMsg(Mtxt2[Set], Vname, tbuff);
1426 if (*tp !=
'$') vp = tp;
1428 if (*pv ==
'(')
ec =
')';
1429 else if (*pv ==
'{')
ec =
'}';
1430 else if (*pv ==
'[')
ec =
']';
1433 else {
while(*pv && *pv !=
ec) pv++;
1434 if (*pv) *pv =
'\0';
1438 if (!*vn) {*pv =
ec;
return xMsg(
"Variable", tp,
"is malformed.");}
1439 if (!(vp = (Set ? getenv(vn) : myEnv->Get(vn))))
1441 {xMsg(Mtxt3[Set],vn,
"is undefined."); *pv =
ec;
return 1;}
1449 if ((
int)strlen(vp) > maxVLen)
1450 return xMsg(Mtxt3[Set], Vname,
"value is too long.");
1454 if (Verbose == 2 && Eroute)
1455 if (!(pv = (Set ? myEnv->
Get(Vname) : getenv(Vname))) || strcmp(vp, pv))
1457 strcpy(vbuff, Mtxt1[Set]); strcat(vbuff,
" "); strcat(vbuff, Vname);
1458 Eroute->
Say(vbuff,
" = ", vp);
1460 if (Set) myEnv->
Put(Vname, vp);
1461 else if (!(pv = getenv(Vname)) || strcmp(vp,pv))
1470char *XrdOucStream::vSubs(
char *Var)
1472 char *vp, *sp, *dp, *vnp,
ec, bkp, valbuff[maxVLen], Nil = 0;
1477 if (!Var)
return Var;
1478 sp = Var; dp = valbuff; n = maxVLen-1; *varVal =
'\0';
1481 {
if (*sp ==
'\\') {*dp++ = *(sp+1); sp +=2; n--;
continue;}
1483 || (!isalnum(*(sp+1)) && !index(
"({[", *(sp+1))))
1484 {*dp++ = *sp++; n--;
continue;}
1486 if (*sp ==
'(')
ec =
')';
1487 else if (*sp ==
'{')
ec =
'}';
1488 else if (*sp ==
'[')
ec =
']';
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.");
1499 while(n && *vp) {*dp++ = *vp++; n--;}
1505 if (*sp) xMsg(
"Substituted text too long using", Var);
1506 else {*dp =
'\0'; strcpy(varVal, valbuff);}
1514int XrdOucStream::xMsg(
const char *txt1,
const char *txt2,
const char *txt3)
1516 if (Eroute) Eroute->
Emsg(
"Stream", txt1, txt2, txt3);
#define XrdOucStream_BUSY
#define XrdOucStream_ELIF
#define XrdOucStream_CADD
#define XrdOucStream_CONT
const char * XrdSysE2T(int errcode)
char * Get(const char *varname)
static int Export(const char *Var, const char *Val)
void * GetPtr(const char *varname)
void Put(const char *varname, const char *value)
XrdOucEnv * SetEnv(XrdOucEnv *newEnv)
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 * 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)
char * GetToken(int lowcase=0)
int GetRest(char *theBuf, int Blen, int lowcase=0)
static int doIf(XrdSysError *eDest, XrdOucStream &Config, const char *what, const char *hname, const char *nname, const char *pname)
int Emsg(const char *esfx, int ecode, const char *text1, const char *text2=0)
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)
XrdSysLogger * logger(XrdSysLogger *lp=0)
std::set< std::string > * fcList
std::set< std::string >::iterator itFC