39 #if !defined(__linux__) && !defined(__CYGWIN__) && !defined(__GNU__) && !defined(__FreeBSD__)
44 #include <sys/types.h>
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;
125 void 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];
426 origcmd = cmd = (
char *)malloc(strlen(theCmd)+1);
431 for (j = 0; j <
MaxARGC-1 && *cmd; j++)
432 {
while(*cmd ==
' ') cmd++;
435 while(*cmd && *cmd !=
' ') cmd++;
436 if (*cmd) {*cmd =
'\0'; cmd++;}
442 j =
Exec(parm, inrd, efd);
449 int fildes[2], Child_in = -1, Child_out = -1, Child_log = -1;
455 return Err(
Exec, errno,
"create input pipe for", parm[0]);
457 fcntl(fildes[0], F_SETFD, FD_CLOEXEC);
458 Attach(fildes[0]); Child_out = fildes[1];
463 return Err(
Exec, errno,
"create output pipe for", parm[0]);
465 fcntl(fildes[1], F_SETFD, FD_CLOEXEC);
466 FE = fildes[1]; Child_in = fildes[0];
469 }
else {Child_out = FD; Child_in = FE;}
474 else if (efd > 0) Child_log = efd;
475 else if (efd == -2){Child_log = Child_out; Child_out = -1;}
476 else if (efd == -3) Child_log = Child_out;
483 if ((child = fork()))
485 {
close(Child_in);
close(Child_out); forkMutex.UnLock();
486 return Err(
Exec, errno,
"fork request process for", parm[0]);
489 if (inrd)
close(Child_in );
490 if (!efd && Child_log >= 0)
close(Child_log);
492 setpgid(child, child);
504 {
if (dup2(Child_in, STDIN_FILENO) < 0)
505 {
Erx(
Exec, errno,
"setting up standard in for " <<parm[0]);
507 }
else if (Child_in != Child_out)
close(Child_in);
514 {
if (dup2(Child_out, STDOUT_FILENO) < 0)
515 {
Erx(
Exec, errno,
"setting up standard out for " <<parm[0]);
517 }
else if (Child_out != Child_log)
close(Child_out);
523 {
if (dup2(Child_log, STDERR_FILENO) < 0)
524 {
Erx(
Exec, errno,
"set up standard err for " <<parm[0]);
526 }
else close(Child_log);
534 if ((
envP = (
char **)myEnv->
GetPtr(
"XrdEnvars**")))
535 while(
envP[i]) {putenv(
envP[i]); i++;}
542 execv(parm[0], parm);
543 Erx(
Exec, errno,
"executing " <<parm[0]);
563 {recp = bnext; bcnt = bleft;
564 for (bp = bnext; bcnt--; bp++)
565 if (!*bp || *bp ==
'\n')
573 else if (notabs && *bp ==
'\t') *bp =
' ';
577 strncpy(buff, bnext, bleft);
578 bnext = buff + bleft;
584 bcnt = bsize - (bnext - buff) -1;
592 {
do { retc =
read(FD, (
void *)bp, (
size_t)bcnt); }
593 while (retc < 0 && errno == EINTR);
595 if (retc < 0) {
Erp(
GetLine,errno,
"read request",0);
return (
char *)0;}
606 if (!*bp || *bp ==
'\n')
613 if (notabs && *bp ==
'\t') *bp =
' ';
620 Erp(
GetLine, EMSGSIZE,
"read full message", 0);
621 buff[bsize-1] =
'\0';
634 if (!token)
return (
char *)NULL;
638 while (*token && *token ==
' ') token ++;
639 if (!*token) {token = 0;
return 0;}
644 if (lowcase)
while (*token && *token !=
' ')
645 {*token = (char)tolower((
int)*token); token++;}
646 else while (*token && *token !=
' ') {token++;}
647 if (*token) {*token =
'\0'; token++;}
660 if (!(tpoint =
GetToken(lowcase)))
return tpoint;
664 while (*token && *token ==
' ') token ++;
665 if (rest) *rest = token;
703 else {
while((var =
GetFirstWord(lowcase)) && !isSet(var)) {}
704 return add2llB(var, 1);
709 {
if (sawif && !ecode)
711 if (Eroute) Eroute->
Emsg(
"Stream",
"Missing 'fi' for last 'if'.");
713 return add2llB(var, 1);
718 if (!strcmp(
"continue", var))
719 {
if (!docont())
return 0;
723 if ( !strcmp(
"if", var)) var = doif();
724 if (var && !strcmp(
"else", var)) var = doelse();
725 if (var && !strcmp(
"fi", var))
726 {
if (sawif) sawif = skpel = skip2fi = 0;
728 Eroute->
Emsg(
"Stream",
"No preceding 'if' for 'fi'.");
733 if (var && (!myEnv || !isSet(var)))
return add2llB(var, 1);
750 if (llBok == 1) llBok = 2;
756 {
if (!myEnv)
return add2llB(wp);
757 if ((wp = vSubs(wp)) && *wp)
return add2llB(wp);
762 if (!xcont) {xcont = 1; xline = 0;
return (
char *)0;}
769 if (!(wp =
GetToken(lowcase)))
continue;
773 if (*wp ==
'#')
continue;
778 while (ep >= buff && *ep ==
' ') ep--;
779 if (ep < buff)
continue;
780 if (*ep ==
'\\') {xcont = 1; *ep =
'\0';}
782 return add2llB((myEnv ? vSubs(wp) : wp));
785 if (myInfo && myInfo->
fcList)
791 const char *path = (*(myInfo->
itFC)).c_str();
793 if (!docontF(path))
break;
809 char *tp, *myBuff = theBuff;
815 while ((tp =
GetWord(lowcase)))
817 if (tlen+1 >= Blen)
return 0;
818 if (myBuff != theBuff) {*myBuff++ =
' '; Blen--;}
820 Blen -= tlen; myBuff += tlen;
837 if (!token || token == recp)
return;
841 while(*token && token != recp) token--;
843 {
if (token+1 != bnext) *token =
' ';
845 while(*token && *token !=
' ' && token != recp) token--;
846 if (token != recp) token++;
852 while(llBcur != llBuff && *llBcur !=
' ') {llBcur--; llBleft++;}
860 int dcnt = dlen, retc;
865 {
do { retc =
write(FE, (
const void *)data, (
size_t)dlen);}
866 while (retc < 0 && errno == EINTR);
867 if (retc >= 0) dcnt -= retc;
869 Erp(
Put, errno,
"write to stream", 0);
883 for (i = 0; datavec[i]; i++)
884 {data = datavec[i]; dlen = dlenvec[i];
886 {
do { retc =
write(FE, (
const void *)data, (
size_t)dlen);}
887 while (retc < 0 && errno == EINTR);
888 if (retc >= 0) {data += retc; dlen -= retc;}
890 Erp(
Put, errno,
"write to stream",0);
905 static const int plSize = 2048;
910 {
if (!(buff = (
char *)malloc(plSize)))
911 return Erq(
Attach, errno,
"allocate stream buffer");
917 if (dlen <= 0) dlen = strlen(data);
918 if (dlen >= bsize) dlen = bsize-1;
922 bnext = recp = token = buff;
928 strncpy(buff, data, dlen);
943 struct pollfd polltab = {FD, POLLIN|POLLRDNORM, 0};
948 do {retc = poll(&polltab, 1, msMax);}
while(retc < 0 && errno == EINTR);
949 if (retc != 1)
return (retc ? errno : -1);
953 return (polltab.revents & (POLLIN|POLLRDNORM) ? 0 : EIO);
963 void XrdOucStream::add2CFG(
const char *data,
bool isCMT)
965 if (isCMT) theCFG->
append(
"# ");
974 char *XrdOucStream::add2llB(
char *tok,
int reset)
980 if (!llBuff)
return tok;
989 }
else if (!llBok)
return tok;
992 {*llBcur++ =
' '; *llBcur =
'\0'; llBleft--;}
1000 {strcpy(llBcur, tok); llBcur += tlen; llBleft -= tlen;}
1012 {
if (t1) Eroute->
Emsg(
"Stream", t1, t2, t3);
1013 if (llBok > 1 && Verbose && llBuff) Eroute->
Say(llPrefix,llBuff);
1024 bool XrdOucStream::docont()
1030 if (sawif)
return Echo(EINVAL,
"'continue' invalid within 'if-fi'.");
1043 cH.path = strdup(theWord);
1048 while(theWord && *theWord ==
'*')
1049 {
if (!*(theWord+1))
return Echo(EINVAL,
"suffix missing after '*'.");
1056 if (theWord && strcmp(theWord,
"if"))
1057 return Echo(EINVAL,
"expecting 'if' but found", theWord);
1067 return docont(cH.path, cH.tlP);
1072 bool XrdOucStream::docont(
const char *path,
XrdOucTList *tlP)
1080 return Echo(EINVAL,
"'continue' in a continuation is not allowed.");
1084 if ((noentok = (*path ==
'?')))
1086 if (!(*path))
return true;
1092 {
if (errno == ENOENT && noentok)
return true;
1094 {Eroute->
Emsg(
"Stream", errno,
"open", path);
1096 }
else ecode = errno;
1104 if ((
Stat.st_mode & S_IFMT) == S_IFDIR)
1105 {
if (!docontD(path, tlP))
return false;
1106 path = (*(myInfo->
itFC)).c_str();
1121 return docontF(path, noentok);
1128 bool XrdOucStream::docontD(
const char *path,
XrdOucTList *tlP)
1130 static const mode_t isXeq = S_IXUSR | S_IXGRP | S_IXOTH;
1138 {
if (Eroute) Eroute->
Emsg(
"Stream", rc,
"index config files in", path);
1145 myInfo->
fcList =
new std::set<std::string>;
1148 if ((nsX->
Stat.st_mode & isXeq) == 0 && KeepFile(nsX->
File, tlP))
1149 myInfo->
fcList->insert(std::string(nsX->
Path));
1155 if (myInfo->
fcList->size() == 0)
1171 bool XrdOucStream::docontF(
const char *path,
bool noentok)
1177 if ((cFD = XrdSysFD_Open(path, O_RDONLY)) < 0)
1178 {
if (errno == ENOENT && noentok)
return true;
1180 {Eroute->
Emsg(
"Stream", errno,
"open", path);
1182 }
else ecode = errno;
1188 if (XrdSysFD_Dup2(cFD, FD) < 0)
1190 {Eroute->
Emsg(
"Stream", ecode,
"switch to", path);
1193 }
else ecode = errno;
1199 if (Eroute) Eroute->
Say(
"Config continuing with file ", path,
" ...");
1209 char *XrdOucStream::doelse()
1215 if (!sawif || sawif == 2)
1216 {
if (Eroute) Eroute->
Emsg(
"Stream",
"No preceding 'if' for 'else'.");
1225 {
if (!strcmp(
"fi", var))
return var;}
1226 if (Eroute) Eroute->
Emsg(
"Stream",
"Missing 'fi' for last 'if'.");
1237 if (strcmp(
"if", var))
1238 {Eroute->
Emsg(
"Stream",
"'else",var,
"' is invalid.");
1246 }
while(var && !strcmp(
"else", var));
1275 char *XrdOucStream::doif()
1277 char *var, ifLine[512];
1283 {
if (Eroute) Eroute->
Emsg(
"Stream",
"Missing 'fi' for last 'if'.");
1289 snprintf(ifLine,
sizeof(ifLine),
"%s", token);
1293 sawif = 1; skpel = 0;
1296 {
if (rc >= 0) skpel = 1;
1297 else {ecode = EINVAL;
1298 if(Eroute) Eroute->
Say(llPrefix,
1308 {
if (!strcmp(
"fi", var))
return var;
1309 if (!strcmp(
"else", var))
return var;
1315 {
if (Eroute) Eroute->
Emsg(
"Stream",
"Missing 'fi' for last 'if'.");
1325 int XrdOucStream::getValue(
const char *path,
char *vbuff,
int vbsz)
1332 if (
stat(path, &
Stat))
return errno;
1333 if (
Stat.st_size >= vbsz)
return EFBIG;
1337 if ((vFD = XrdSysFD_Open(path, O_RDONLY)) < 0)
return errno;
1338 if ((n =
read(vFD, vbuff, vbsz-1)) >= 0) vbuff[n] = 0;
1351 int XrdOucStream::isSet(
char *var)
1353 static const char *Mtxt1[2] = {
"setenv",
"set"};
1354 static const char *Mtxt2[2] = {
"Setenv variable",
"Set variable"};
1355 static const char *Mtxt3[2] = {
"Variable",
"Environmental variable"};
1356 char *tp, *vn, *vp, *pv, Vname[64],
ec, Nil = 0, sawIT = 0;
1362 if (!strcmp(
"setenv", var)) Set = 0;
1363 else if (strcmp(
"set", var))
return 0;
1368 return xMsg(
"Missing variable name after '",Mtxt1[Set],
"'.");
1373 {
if (!strcmp(tp,
"-q")) {
if (llBuff) {free(llBuff); llBuff = 0;};
return 1;}
1374 if (!strcmp(tp,
"-v") || !strcmp(tp,
"-V"))
1376 {
if (!llBuff) llBuff = (
char *)malloc(llBsz);
1377 llBcur = llBuff; llBok = 0; llBleft = llBsz; *llBuff =
'\0';
1378 Verbose = (strcmp(tp,
"-V") ? 1 : 2);
1386 if ((vp = index(tp,
'=')) || (vp = index(tp,
'<')))
1387 {sawIT = *vp; *vp =
'\0'; vp++;}
1388 if (
strlcpy(Vname, tp,
sizeof(Vname)) >=
sizeof(Vname))
1389 return xMsg(Mtxt2[Set],tp,
"is too long.");
1390 if (!Set && !strncmp(
"XRD", Vname, 3))
1391 return xMsg(
"Setenv variable",tp,
"may not start with 'XRD'.");
1396 while (*tp && (*tp ==
'_' || isalnum(*tp))) tp++;
1397 if (*tp)
return xMsg(Mtxt2[Set], Vname,
"is non-alphanumeric");
1402 else if (!(tp =
GetToken()) || (*tp !=
'=' && *tp !=
'<'))
1403 return xMsg(
"Missing '=' after", Mtxt1[Set], Vname);
1404 else {sawIT = *tp; tp++;}
1405 if (!*tp && !(tp =
GetToken())) tp = (
char *)
"";
1411 if (!*tp)
return xMsg(Mtxt2[Set], Vname,
"path to value not specified");
1412 if ((rc = getValue(tp, valBuff,
sizeof(valBuff))))
1414 snprintf(tbuff,
sizeof(tbuff),
"cannot be set via path %s; %s",
1416 return xMsg(Mtxt2[Set], Vname, tbuff);
1424 if (*tp !=
'$') vp = tp;
1426 if (*pv ==
'(')
ec =
')';
1427 else if (*pv ==
'{')
ec =
'}';
1428 else if (*pv ==
'[')
ec =
']';
1431 else {
while(*pv && *pv !=
ec) pv++;
1432 if (*pv) *pv =
'\0';
1436 if (!*vn) {*pv =
ec;
return xMsg(
"Variable", tp,
"is malformed.");}
1437 if (!(vp = (Set ? getenv(vn) : myEnv->
Get(vn))))
1439 {xMsg(Mtxt3[Set],vn,
"is undefined."); *pv =
ec;
return 1;}
1447 if ((
int)strlen(vp) > maxVLen)
1448 return xMsg(Mtxt3[Set], Vname,
"value is too long.");
1452 if (Verbose == 2 && Eroute)
1453 if (!(pv = (Set ? myEnv->
Get(Vname) : getenv(Vname))) || strcmp(vp, pv))
1455 strcpy(vbuff, Mtxt1[Set]); strcat(vbuff,
" "); strcat(vbuff, Vname);
1456 Eroute->
Say(vbuff,
" = ", vp);
1458 if (Set) myEnv->
Put(Vname, vp);
1459 else if (!(pv = getenv(Vname)) || strcmp(vp,pv))
1468 char *XrdOucStream::vSubs(
char *Var)
1470 char *vp, *sp, *dp, *vnp,
ec, bkp, valbuff[maxVLen], Nil = 0;
1475 if (!Var)
return Var;
1476 sp = Var; dp = valbuff; n = maxVLen-1; *varVal =
'\0';
1479 {
if (*sp ==
'\\') {*dp++ = *(sp+1); sp +=2; n--;
continue;}
1481 || (!isalnum(*(sp+1)) && !index(
"({[", *(sp+1))))
1482 {*dp++ = *sp++; n--;
continue;}
1484 if (*sp ==
'(')
ec =
')';
1485 else if (*sp ==
'{')
ec =
'}';
1486 else if (*sp ==
'[')
ec =
']';
1488 if (
ec) {sp++; vnp++;}
1489 while(isalnum(*sp)) sp++;
1490 if (
ec && *sp !=
ec)
1491 {xMsg(
"Variable", vnp-2,
"is malformed.");
return varVal;}
1492 bkp = *sp; *sp =
'\0';
1493 if (!(vp = myEnv->
Get(vnp)))
1494 {
if (
ec !=
']') xMsg(
"Variable", vnp,
"is undefined.");
1497 while(n && *vp) {*dp++ = *vp++; n--;}
1503 if (*sp) xMsg(
"Substituted text too long using", Var);
1504 else {*dp =
'\0'; strcpy(varVal, valbuff);}
1512 int XrdOucStream::xMsg(
const char *txt1,
const char *txt2,
const char *txt3)
1514 if (Eroute) Eroute->
Emsg(
"Stream", txt1, txt2, txt3);
#define XrdOucStream_BUSY
#define XrdOucStream_ELIF
#define XrdOucStream_CADD
#define XrdOucStream_CONT
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)
const char * XrdSysE2T(int errcode)
static int Export(const char *Var, const char *Val)
void * GetPtr(const char *varname)
char * Get(const char *varname)
void Put(const char *varname, const char *value)
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)
XrdOucEnv * SetEnv(XrdOucEnv *newEnv)
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