XRootD
Loading...
Searching...
No Matches
XrdOucUtils.cc
Go to the documentation of this file.
1/******************************************************************************/
2/* */
3/* X r d O u c U t i l s . c c */
4/* */
5/* (c) 2005 by the Board of Trustees of the Leland Stanford, Jr., University */
6/* All Rights Reserved */
7/* Produced by Andrew Hanushevsky for Stanford University under contract */
8/* DE-AC02-76-SFO0515 with the Department of Energy */
9/* */
10/* This file is part of the XRootD software suite. */
11/* */
12/* XRootD is free software: you can redistribute it and/or modify it under */
13/* the terms of the GNU Lesser General Public License as published by the */
14/* Free Software Foundation, either version 3 of the License, or (at your */
15/* option) any later version. */
16/* */
17/* XRootD is distributed in the hope that it will be useful, but WITHOUT */
18/* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or */
19/* FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public */
20/* License for more details. */
21/* */
22/* You should have received a copy of the GNU Lesser General Public License */
23/* along with XRootD in a file called COPYING.LESSER (LGPL license) and file */
24/* COPYING (GPL license). If not, see <http://www.gnu.org/licenses/>. */
25/* */
26/* The copyright holder's institutional names and contributor's names may not */
27/* be used to endorse or promote products derived from this software without */
28/* specific prior written permission of the institution or contributor. */
29/******************************************************************************/
30
31#include <cctype>
32#include <grp.h>
33#include <cstdio>
34#include <list>
35#include <vector>
36#include <unordered_set>
37#include <algorithm>
38
39#include <regex.h>
40
41#ifdef WIN32
42#include <direct.h>
43#include "XrdSys/XrdWin32.hh"
44#else
45#include <fcntl.h>
46#include <pwd.h>
47#include <sys/stat.h>
48#include <sys/types.h>
49#endif
50#include <map>
51#include "XrdNet/XrdNetUtils.hh"
52#include "XrdOuc/XrdOucCRC.hh"
53#include "XrdOuc/XrdOucEnv.hh"
54#include "XrdOuc/XrdOucSHA3.hh"
57#include "XrdOuc/XrdOucUtils.hh"
59#include "XrdSys/XrdSysE2T.hh"
60#include "XrdSys/XrdSysError.hh"
63
64#ifndef ENODATA
65#define ENODATA ENOATTR
66#endif
67
68/******************************************************************************/
69/* L o c a l M e t h o d s */
70/******************************************************************************/
71
72namespace
73{
74struct idInfo
75{ time_t Expr;
76 char *Name;
77
78 idInfo(const char *name, time_t keep)
79 : Expr(time(0)+keep), Name(strdup(name)) {}
80 ~idInfo() {free(Name);}
81};
82
83typedef std::map<unsigned int, struct idInfo*> idMap_t;
84
85idMap_t gidMap;
86idMap_t uidMap;
87XrdSysMutex idMutex;
88
89void AddID(idMap_t &idMap, unsigned int id, const char *name, time_t keepT)
90{
91 std::pair<idMap_t::iterator,bool> ret;
92 idInfo *infoP = new idInfo(name, keepT);
93
94 idMutex.Lock();
95 ret = idMap.insert(std::pair<unsigned int, struct idInfo*>(id, infoP));
96 if (ret.second == false) delete infoP;
97 idMutex.UnLock();
98}
99
100int LookUp(idMap_t &idMap, unsigned int id, char *buff, int blen)
101{
102 idMap_t::iterator it;
103 int luRet = 0;
104
105 idMutex.Lock();
106 it = idMap.find(id);
107 if (it != idMap.end())
108 {if (it->second->Expr <= time(0))
109 {delete it->second;
110 idMap.erase(it);
111 } else {
112 if (blen > 0) luRet = snprintf(buff, blen, "%s", it->second->Name);
113 }
114 }
115 idMutex.UnLock();
116 return luRet;
117}
118}
119
120/******************************************************************************/
121/* a r g L i s t */
122/******************************************************************************/
123
124int XrdOucUtils::argList(char *args, char **argV, int argC)
125{
126 char *aP = args;
127 int j;
128
129// Construct the argv array based on passed command line.
130//
131for (j = 0; j < argC; j++)
132 {while(*aP == ' ') aP++;
133 if (!(*aP)) break;
134
135 if (*aP == '"' || *aP == '\'')
136 {argV[j] = aP+1;
137 aP = index(aP+1, *aP);
138 if (!aP || (*(aP+1) != ' ' && *(aP+1)))
139 {if (!j) argV[0] = 0; return -EINVAL;}
140 *aP++ = '\0';
141 } else {
142 argV[j] = aP;
143 if ((aP = index(aP+1, ' '))) *aP++ = '\0';
144 else {j++; break;}
145 }
146
147 }
148
149// Make sure we did not overflow the vector
150//
151 if (j > argC-1) return -E2BIG;
152
153// End list with a null pointer and return the actual number of arguments
154//
155 argV[j] = 0;
156 return j;
157}
158
159/******************************************************************************/
160/* b i n 2 h e x */
161/******************************************************************************/
162
163char *XrdOucUtils::bin2hex(char *inbuff, int dlen, char *buff, int blen,
164 bool sep)
165{
166 static char hv[] = "0123456789abcdef";
167 char *outbuff = buff;
168 for (int i = 0; i < dlen && blen > 2; i++) {
169 *outbuff++ = hv[(inbuff[i] >> 4) & 0x0f];
170 *outbuff++ = hv[ inbuff[i] & 0x0f];
171 blen -= 2;
172 if (sep && blen > 1 && ((i & 0x03) == 0x03 || i+1 == dlen))
173 {*outbuff++ = ' '; blen--;}
174 }
175 *outbuff = '\0';
176 return buff;
177}
178
179/******************************************************************************/
180/* e n d s W i t h */
181/******************************************************************************/
182
183bool XrdOucUtils::endsWith(const char *text, const char *ending, int endlen)
184{
185 int tlen = strlen(text);
186
187 return (tlen >= endlen && !strcmp(text+(tlen-endlen), ending));
188}
189
190/******************************************************************************/
191/* e T e x t */
192/******************************************************************************/
193
194// eText() returns the text associated with the error.
195// The text buffer pointer is returned.
196
197char *XrdOucUtils::eText(int rc, char *eBuff, int eBlen)
198{
199 const char *etP;
200
201// Get error text
202//
203 etP = XrdSysE2T(rc);
204
205// Copy the text and lower case the first letter
206//
207 strlcpy(eBuff, etP, eBlen);
208
209// All done
210//
211 return eBuff;
212}
213
214/******************************************************************************/
215/* d o I f */
216/******************************************************************************/
217
218// doIf() parses "if [<hostlist>] [<conds>]"
219// conds: <cond1> | <cond2> | <cond3>
220// cond1: defined <varlist> [&& <conds>]
221// cond2: exec <pgmlist> [&& <cond3>]
222// cond3: named <namelist>
223
224// Returning 1 if true (i.e., this machine is one of the named hosts in hostlist
225// and is running one of the programs pgmlist and named by one of the names in
226// namelist).
227// Return -1 (negative truth) if an error occurred.
228// Otherwise, returns false (0). Some combination of hostlist, pgm, and
229// namelist, must be specified.
230
232 const char *what, const char *hname,
233 const char *nname, const char *pname)
234{
235 static const char *brk[] = {"defined", "exec", "named", 0};
236 XrdOucEnv *theEnv = 0;
237 char *val;
238 int hostok, isDef;
239
240// Make sure that at least one thing appears after the if
241//
242 if (!(val = Config.GetWord()))
243 {if (eDest) eDest->Emsg("Config","Host name missing after 'if' in", what);
244 return -1;
245 }
246
247// Check if we are one of the listed hosts
248//
249 if (!is1of(val, brk))
250 {do {hostok = XrdNetUtils::Match(hname, val);
251 val = Config.GetWord();
252 } while(!hostok && val && !is1of(val, brk));
253 if (hostok)
254 { while(val && !is1of(val, brk)) val = Config.GetWord();
255 // No more directives
256 if (!val) return 1;
257 } else return 0;
258 }
259
260// Check if this is a defined test
261//
262 while(!strcmp(val, "defined"))
263 {if (!(val = Config.GetWord()) || *val != '?')
264 {if (eDest)
265 {eDest->Emsg("Config","'?var' missing after 'defined' in",what);}
266 return -1;
267 }
268 // Get environment if we have none
269 //
270 if (!theEnv && (theEnv = Config.SetEnv(0))) Config.SetEnv(theEnv);
271 if (!theEnv && *(val+1) != '~') return 0;
272
273 // Check if any listed variable is defined.
274 //
275 isDef = 0;
276 while(val && *val == '?')
277 {if (*(val+1) == '~' ? getenv(val+2) : theEnv->Get(val+1)) isDef=1;
278 val = Config.GetWord();
279 }
280 if (!val || !isDef) return isDef;
281 if (strcmp(val, "&&"))
282 {if (eDest)
283 {eDest->Emsg("Config",val,"is invalid for defined test in",what);}
284 return -1;
285 } else {
286 if (!(val = Config.GetWord()))
287 {if (eDest)
288 {eDest->Emsg("Config","missing keyword after '&&' in",what);}
289 return -1;
290 }
291 }
292 if (!is1of(val, brk))
293 {if (eDest)
294 {eDest->Emsg("Config",val,"is invalid after '&&' in",what);}
295 return -1;
296 }
297 }
298
299// Check if we need to compare program names (we are here only if we either
300// passed the hostlist test or there was no hostlist present)
301//
302 if (!strcmp(val, "exec"))
303 {if (!(val = Config.GetWord()) || !strcmp(val, "&&"))
304 {if (eDest)
305 {eDest->Emsg("Config","Program name missing after 'if exec' in",what);}
306 return -1;
307 }
308
309 // Check if we are one of the programs.
310 //
311 if (!pname) return 0;
312 while(val && strcmp(val, pname))
313 if (!strcmp(val, "&&")) return 0;
314 else val = Config.GetWord();
315 if (!val) return 0;
316 while(val && strcmp(val, "&&")) val = Config.GetWord();
317 if (!val) return 1;
318
319 if (!(val = Config.GetWord()))
320 {if (eDest)
321 {eDest->Emsg("Config","Keyword missing after '&&' in",what);}
322 return -1;
323 }
324 if (strcmp(val, "named"))
325 {if (eDest)
326 {eDest->Emsg("Config",val,"is invalid after '&&' in",what);}
327 return -1;
328 }
329 }
330
331// Check if we need to compare net names (we are here only if we either
332// passed the hostlist test or there was no hostlist present)
333//
334 if (!(val = Config.GetWord()))
335 {if (eDest)
336 {eDest->Emsg("Config","Instance name missing after 'if named' in", what);}
337 return -1;
338 }
339
340// Check if we are one of the names
341//
342 if (!nname) return 0;
343 while(val && strcmp(val, nname)) val = Config.GetWord();
344
345// All done
346//
347 return (val != 0);
348}
349
350/******************************************************************************/
351/* f i n d P g m */
352/******************************************************************************/
353
354bool XrdOucUtils::findPgm(const char *pgm, XrdOucString& path)
355{
356 struct stat Stat;
357
358// Check if only executable bit needs to be checked
359//
360 if (*pgm == '/')
361 {if (stat(pgm, &Stat) || !(Stat.st_mode & S_IXOTH)) return false;
362 path = pgm;
363 return true;
364 }
365
366// Make sure we have the paths to check
367//
368 const char *pEnv = getenv("PATH");
369 if (!pEnv) return false;
370
371// Setup to find th executable
372//
373 XrdOucString prog, pList(pEnv);
374 int from = 0;;
375 prog += '/'; prog += pgm;
376
377// Find it!
378//
379 while((from = pList.tokenize(path, from, ':')) != -1)
380 {path += prog;
381 if (!stat(path.c_str(), &Stat) && Stat.st_mode & S_IXOTH) return true;
382 }
383 return false;
384}
385
386/******************************************************************************/
387/* f m t B y t e s */
388/******************************************************************************/
389
390int XrdOucUtils::fmtBytes(long long val, char *buff, int bsz)
391{
392 static const long long Kval = 1024LL;
393 static const long long Mval = 1024LL*1024LL;
394 static const long long Gval = 1024LL*1024LL*1024LL;
395 static const long long Tval = 1024LL*1024LL*1024LL*1024LL;
396 char sName = ' ';
397 int resid;
398
399// Get correct scaling
400//
401 if (val < 1024) return snprintf(buff, bsz, "%lld", val);
402 if (val < Mval) {val = val*10/Kval; sName = 'K';}
403 else if (val < Gval) {val = val*10/Mval; sName = 'M';}
404 else if (val < Tval) {val = val*10/Gval; sName = 'G';}
405 else {val = val*10/Tval; sName = 'T';}
406 resid = val%10LL; val = val/10LL;
407
408// Format it
409//
410 return snprintf(buff, bsz, "%lld.%d%c", val, resid, sName);
411}
412
413/******************************************************************************/
414/* g e n P a t h */
415/******************************************************************************/
416
417char *XrdOucUtils::genPath(const char *p_path, const char *inst,
418 const char *s_path)
419{
420 char buff[2048];
421 int i = strlcpy(buff, p_path, sizeof(buff));
422
423 if (buff[i-1] != '/') {buff[i++] = '/'; buff[i] = '\0';}
424 if (inst) {strcpy(buff+i, inst); strcat(buff, "/");}
425 if (s_path) strcat(buff, s_path);
426
427 i = strlen(buff);
428 if (buff[i-1] != '/') {buff[i++] = '/'; buff[i] = '\0';}
429
430 return strdup(buff);
431}
432
433/******************************************************************************/
434
435int XrdOucUtils::genPath(char *buff, int blen, const char *path, const char *psfx)
436{
437 int i, j;
438
439 i = strlen(path);
440 j = (psfx ? strlen(psfx) : 0);
441 if (i+j+3 > blen) return -ENAMETOOLONG;
442
443 strcpy(buff, path);
444 if (psfx)
445 {if (buff[i-1] != '/') buff[i++] = '/';
446 strcpy(&buff[i], psfx);
447 if (psfx[j-1] != '/') strcat(buff, "/");
448 }
449 return 0;
450}
451
452/******************************************************************************/
453/* g e t F i l e */
454/******************************************************************************/
455
456char *XrdOucUtils::getFile(const char *path, int &rc, int maxsz, bool notempty)
457{
458 struct stat Stat;
459 struct fdHelper
460 {int fd = -1;
461 fdHelper() {}
462 ~fdHelper() {if (fd >= 0) close(fd);}
463 } file;
464 char *buff;
465 int flen;
466
467// Preset RC
468//
469 rc = 0;
470
471// Open the file in read mode
472//
473 if ((file.fd = open(path, O_RDONLY)) < 0) {rc = errno; return 0;}
474
475// Get the size of the file
476//
477 if (fstat(file.fd, &Stat)) {rc = errno; return 0;}
478
479// Check if the size exceeds the maximum allowed
480//
481 if (Stat.st_size > maxsz) {rc = EFBIG; return 0;}
482
483// Make sure the file is not empty if empty files are disallowed
484//
485 if (Stat.st_size == 0 && notempty) {rc = ENODATA; return 0;}
486
487// Allocate a buffer
488//
489 if ((buff = (char *)malloc(Stat.st_size+1)) == 0)
490 {rc = errno; return 0;}
491
492// Read the contents of the file into the buffer
493//
494 if (Stat.st_size)
495 {if ((flen = read(file.fd, buff, Stat.st_size)) < 0)
496 {rc = errno; free(buff); return 0;}
497 } else flen = 0;
498
499// Add null byte. recall the buffer is bigger by one byte
500//
501 buff[flen] = 0;
502
503// Return the size aand the buffer
504//
505 rc = flen;
506 return buff;
507}
508
509/******************************************************************************/
510/* g e t G I D */
511/******************************************************************************/
512
513bool XrdOucUtils::getGID(const char *gName, gid_t &gID)
514{
515 struct group Grp, *result;
516 char buff[65536];
517
518 getgrnam_r(gName, &Grp, buff, sizeof(buff), &result);
519 if (!result) return false;
520
521 gID = Grp.gr_gid;
522 return true;
523}
524
525/******************************************************************************/
526/* g e t U I D */
527/******************************************************************************/
528
529bool XrdOucUtils::getUID(const char *uName, uid_t &uID, gid_t *gID)
530{
531 struct passwd pwd, *result;
532 char buff[16384];
533
534 getpwnam_r(uName, &pwd, buff, sizeof(buff), &result);
535 if (!result) return false;
536
537 uID = pwd.pw_uid;
538 if (gID) *gID = pwd.pw_gid;
539
540 return true;
541}
542
543/******************************************************************************/
544/* G i d N a m e */
545/******************************************************************************/
546
547int XrdOucUtils::GidName(gid_t gID, char *gName, int gNsz, time_t keepT)
548{
549 static const int maxgBsz = 256*1024;
550 static const int addGsz = 4096;
551 struct group *gEnt, gStruct;
552 char gBuff[1024], *gBp = gBuff;
553 int glen = 0, gBsz = sizeof(gBuff), aOK = 1;
554 int n, retVal = 0;
555
556// Get ID from cache, if allowed
557//
558 if (keepT)
559 {int n = LookUp(gidMap, static_cast<unsigned int>(gID),gName,gNsz);
560 if (n > 0) return (n < gNsz ? n : 0);
561 }
562
563// Get the the group struct. If we don't have a large enough buffer, get a
564// larger one and try again up to the maximum buffer we will tolerate.
565//
566 while(( retVal = getgrgid_r(gID, &gStruct, gBp, gBsz, &gEnt) ) == ERANGE)
567 {if (gBsz >= maxgBsz) {aOK = 0; break;}
568 if (gBsz > addGsz) free(gBp);
569 gBsz += addGsz;
570 if (!(gBp = (char *)malloc(gBsz))) {aOK = 0; break;}
571 }
572
573// Return a group name if all went well
574//
575 if (aOK && retVal == 0 && gEnt != NULL)
576 {if (keepT)
577 AddID(gidMap, static_cast<unsigned int>(gID), gEnt->gr_name, keepT);
578 glen = strlen(gEnt->gr_name);
579 if (glen >= gNsz) glen = 0;
580 else strcpy(gName, gEnt->gr_name);
581 } else {
582 n = snprintf(gName, gNsz, "%ud", static_cast<unsigned int>(gID));
583 if (n >= gNsz) glen = 0;
584 }
585
586// Free any allocated buffer and return result
587//
588 if (gBsz > addGsz && gBp) free(gBp);
589 return glen;
590}
591
592/******************************************************************************/
593/* G r o u p N a m e */
594/******************************************************************************/
595
596int XrdOucUtils::GroupName(gid_t gID, char *gName, int gNsz)
597{
598 static const int maxgBsz = 256*1024;
599 static const int addGsz = 4096;
600 struct group *gEnt, gStruct;
601 char gBuff[1024], *gBp = gBuff;
602 int glen, gBsz = sizeof(gBuff), aOK = 1;
603 int retVal = 0;
604
605// Get the the group struct. If we don't have a large enough buffer, get a
606// larger one and try again up to the maximum buffer we will tolerate.
607//
608 while(( retVal = getgrgid_r(gID, &gStruct, gBp, gBsz, &gEnt) ) == ERANGE)
609 {if (gBsz >= maxgBsz) {aOK = 0; break;}
610 if (gBsz > addGsz) free(gBp);
611 gBsz += addGsz;
612 if (!(gBp = (char *)malloc(gBsz))) {aOK = 0; break;}
613 }
614
615// Return a group name if all went well
616//
617 if (aOK && retVal == 0 && gEnt != NULL)
618 {glen = strlen(gEnt->gr_name);
619 if (glen >= gNsz) glen = 0;
620 else strcpy(gName, gEnt->gr_name);
621 } else glen = 0;
622
623// Free any allocated buffer and return result
624//
625 if (gBsz > addGsz && gBp) free(gBp);
626 return glen;
627}
628
629/******************************************************************************/
630/* i 2 b s t r */
631/******************************************************************************/
632
633const char *XrdOucUtils::i2bstr(char *buff, int blen, int val, bool pad)
634{
635 char zo[2] = {'0', '1'};
636
637 if (blen < 2) return "";
638
639 buff[--blen] = 0;
640 if (!val) buff[blen--] = '0';
641 else while(val && blen >= 0)
642 {buff[blen--] = zo[val & 0x01];
643 val >>= 1;
644 }
645
646 if (blen >= 0 && pad) while(blen >= 0) buff[blen--] = '0';
647
648 return &buff[blen+1];
649}
650
651/******************************************************************************/
652/* I d e n t */
653/******************************************************************************/
654
655namespace
656{
657long long genSID(char *&urSID, const char *iHost, int iPort,
658 const char *iName, const char *iProg)
659{
660 static const XrdOucSHA3::MDLen mdLen = XrdOucSHA3::SHA3_512;
661 static const uint32_t fpOffs = 2, fpSize = 6; // 48 bit finger print
662
663 const char *iSite = getenv("XRDSITE");
664 unsigned char mDigest[mdLen];
665 XrdOucString myID;
666 union {uint64_t mdLL; unsigned char mdUC[8];}; // Works for fpSize only!
667
668// Construct our unique identification
669//
670 if (iSite) myID = iSite;
671 myID += iHost;
672 myID += iPort;
673 if (iName) myID += iName;
674 myID += iProg;
675
676// Generate a SHA3 digest of this string.
677//
678 memset(mDigest, 0, sizeof(mDigest));
679 XrdOucSHA3::Calc(myID.c_str(), myID.length(), mDigest, mdLen);
680
681// Generate a CRC32C of the same string
682//
683 uint32_t crc32c = XrdOucCRC::Calc32C(myID.c_str(), myID.length());
684
685// We need a 48-bit fingerprint that has a very low probability of collision.
686// We accomplish this by convoluting the CRC32C checksum with the SHA3 checksum.
687//
688 uint64_t fpPos = crc32c % (((uint32_t)mdLen) - fpSize);
689 mdLL = 0;
690 memcpy(mdUC+fpOffs, mDigest+fpPos, fpSize);
691 long long fpVal = static_cast<long long>(ntohll(mdLL));
692
693// Generate the character version of our fingerprint and return the binary one.
694//
695 char fpBuff[64];
696 snprintf(fpBuff, sizeof(fpBuff), "%lld", fpVal);
697 urSID = strdup(fpBuff);
698 return fpVal;
699}
700}
701
702char *XrdOucUtils::Ident(long long &mySID, char *iBuff, int iBlen,
703 const char *iHost, const char *iProg,
704 const char *iName, int iPort)
705{
706 static char *theSIN;
707 static long long theSID = genSID(theSIN, iHost, iPort, iName, iProg);
708 const char *sP = getenv("XRDSITE");
709 char uName[256];
710 int myPid = static_cast<int>(getpid());
711
712// Get our username
713//
714 if (UserName(getuid(), uName, sizeof(uName)))
715 sprintf(uName, "%d", static_cast<int>(getuid()));
716
717// Create identification record
718//
719 snprintf(iBuff,iBlen,"%s.%d:%s@%s\n&site=%s&port=%d&inst=%s&pgm=%s",
720 uName, myPid, theSIN, iHost, (sP ? sP : ""), iPort, iName, iProg);
721
722// Return a copy of the sid key
723//
724 h2nll(theSID, mySID);
725 return strdup(theSIN);
726}
727
728/******************************************************************************/
729/* I n s t N a m e */
730/******************************************************************************/
731
732const char *XrdOucUtils::InstName(int TranOpt)
733{
734 const char *iName = getenv("XRDNAME");
735
736// If tran is zero, return what we have
737//
738 if (!TranOpt) return iName;
739
740// If trans is positive then make sure iName has a value. Otherwise, make sure
741// iName has no value if it's actually "anon".
742//
743 if (TranOpt > 0) {if (!iName || !*iName) iName = "anon";}
744 else if (iName && !strcmp(iName, "anon")) iName = 0;
745 return iName;
746}
747/******************************************************************************/
748
749const char *XrdOucUtils::InstName(const char *name, int Fillit)
750{ return (Fillit ? name && *name ? name : "anon"
751 : name && strcmp(name,"anon") && *name ? name : 0);
752}
753
754/******************************************************************************/
755/* i s 1 o f */
756/******************************************************************************/
757
758int XrdOucUtils::is1of(char *val, const char **clist)
759{
760 int i = 0;
761 while(clist[i]) if (!strcmp(val, clist[i])) return 1;
762 else i++;
763 return 0;
764}
765
766/******************************************************************************/
767/* i s F W D */
768/******************************************************************************/
769
770int XrdOucUtils::isFWD(const char *path, int *port, char *hBuff, int hBLen,
771 bool pTrim)
772{
773 const char *hName, *hNend, *hPort, *hPend, *hP = path;
774 char *eP;
775 int n;
776
777 if (*path == '/') hP++; // Note: It's assumed an objectid if no slash
778 if (*hP == 'x') hP++;
779 if (strncmp("root:/", hP, 6)) return 0;
780 if (hBuff == 0 || hBLen <= 0) return (hP - path) + 6;
781 hP += 6;
782
783 if (!XrdNetUtils::Parse(hP, &hName, &hNend, &hPort, &hPend)) return 0;
784 if (*hNend == ']') hNend++;
785 else {if (!(*hNend) && !(hNend = index(hName, '/'))) return 0;
786 if (!(*hPend)) hPend = hNend;
787 }
788
789 if (pTrim || !(*hPort)) n = hNend - hP;
790 else n = hPend - hP;
791 if (n >= hBLen) return 0;
792 strncpy(hBuff, hP, n);
793 hBuff[n] = 0;
794
795 if (port)
796 {if (*hNend != ':') *port = 0;
797 else {*port = strtol(hPort, &eP, 10);
798 if (*port < 0 || *port > 65535 || eP != hPend) return 0;
799 }
800 }
801
802 return hPend-path;
803}
804
805/******************************************************************************/
806/* L o g 2 */
807/******************************************************************************/
808
809// Based on an algorithm produced by Todd Lehman. However, this one returns 0
810// when passed 0 (which is invalid). The caller must check the validity of
811// the input prior to calling Log2(). Essentially, the algorithm subtracts
812// away progressively smaller squares in the sequence
813// { 0 <= k <= 5: 2^(2^k) } = { 2**32, 2**16, 2**8 2**4 2**2, 2**1 } =
814// = { 4294967296, 65536, 256, 16, 4, 2 }
815// and sums the exponents k of the subtracted values. It is generally the
816// fastest way to compute log2 for a wide range of possible input values.
817
818int XrdOucUtils::Log2(unsigned long long n)
819{
820 int i = 0;
821
822 #define SHFT(k) if (n >= (1ULL << k)) { i += k; n >>= k; }
823
824 SHFT(32); SHFT(16); SHFT(8); SHFT(4); SHFT(2); SHFT(1); return i;
825
826 #undef SHFT
827}
828
829/******************************************************************************/
830/* L o g 1 0 */
831/******************************************************************************/
832
833int XrdOucUtils::Log10(unsigned long long n)
834{
835 int i = 0;
836
837 #define SHFT(k, m) if (n >= m) { i += k; n /= m; }
838
839 SHFT(16,10000000000000000ULL); SHFT(8,100000000ULL);
840 SHFT(4,10000ULL); SHFT(2,100ULL); SHFT(1,10ULL);
841 return i;
842
843 #undef SHFT
844}
845
846/******************************************************************************/
847/* m a k e H o m e */
848/******************************************************************************/
849
851{
852 char buff[2048];
853
854 if (!inst || !getcwd(buff, sizeof(buff))) return;
855
856 strcat(buff, "/"); strcat(buff, inst);
857 if (MAKEDIR(buff, pathMode) && errno != EEXIST)
858 {eDest.Emsg("Config", errno, "create home directory", buff);
859 return;
860 }
861
862 if (chdir(buff) < 0)
863 eDest.Emsg("Config", errno, "chdir to home directory", buff);
864}
865
866/******************************************************************************/
867
869 const char *path, mode_t mode)
870{
871 char cwDir[2048];
872 const char *slash = "", *slash2 = "";
873 int n, rc;
874
875// Provide backward compatibility for instance name qualification
876//
877
878 if (!path || !(n = strlen(path)))
879 {if (inst) makeHome(eDest, inst);
880 return true;
881 }
882
883// Augment the path with instance name, if need be
884//
885 if (path[n-1] != '/') slash = "/";
886 if (!inst || !(n = strlen(inst))) inst = "";
887 else slash2 = "/";
888 n = snprintf(cwDir, sizeof(cwDir), "%s%s%s%s", path, slash, inst, slash2);
889 if (n >= (int)sizeof(cwDir))
890 {eDest.Emsg("Config", ENAMETOOLONG, "create home directory", cwDir);
891 return false;
892 }
893
894// Create the path if it doesn't exist
895//
896 if ((rc = makePath(cwDir, mode, true)))
897 {eDest.Emsg("Config", rc, "create home directory", cwDir);
898 return false;
899 }
900
901// Switch to this directory
902//
903 if (chdir(cwDir) < 0)
904 {eDest.Emsg("Config", errno, "chdir to home directory", cwDir);
905 return false;
906 }
907
908// All done
909//
910 return true;
911}
912
913/******************************************************************************/
914/* m a k e P a t h */
915/******************************************************************************/
916
917int XrdOucUtils::makePath(char *path, mode_t mode, bool reset)
918{
919 char *next_path = path+1;
920 struct stat buf;
921 bool dochmod = false; // The 1st component stays as is
922
923// Typically, the path exists. So, do a quick check before launching into it
924//
925 if (!reset && !stat(path, &buf)) return 0;
926
927// Start creating directories starting with the root
928//
929 while((next_path = index(next_path, int('/'))))
930 {*next_path = '\0';
931 if (MAKEDIR(path, mode))
932 if (errno != EEXIST) return -errno;
933 if (dochmod) CHMOD(path, mode);
934 dochmod = reset;
935 *next_path = '/';
936 next_path = next_path+1;
937 }
938
939// All done
940//
941 return 0;
942}
943
944/******************************************************************************/
945/* m o d e 2 m a s k */
946/******************************************************************************/
947
948bool XrdOucUtils::mode2mask(const char *mode, mode_t &mask)
949{
950 mode_t mval[3] = {0}, mbit[3] = {0x04, 0x02, 0x01};
951 const char *mok = "rwx";
952 char mlet;
953
954// Accept octal mode
955//
956 if (isdigit(*mode))
957 {char *eP;
958 mask = strtol(mode, &eP, 8);
959 return *eP == 0;
960 }
961
962// Make sure we have the correct number of characters
963//
964 int n = strlen(mode);
965 if (!n || n > 9 || n/3*3 != n) return false;
966
967// Convert groups of three
968//
969 int k = 0;
970 do {for (int i = 0; i < 3; i++)
971 {mlet = *mode++;
972 if (mlet != '-')
973 {if (mlet != mok[i]) return false;
974 mval[k] |= mbit[i];
975 }
976 }
977 } while(++k < 3 && *mode);
978
979// Combine the modes and return success
980//
981 mask = mval[0]<<6 | mval[1]<<3 | mval[2];
982 return true;
983}
984
985/******************************************************************************/
986/* p a r s e L i b */
987/******************************************************************************/
988
990 const char *libName, char *&libPath, char **libParm)
991{
992 char *val, parms[2048];
993
994// Get the next token
995//
996 val = Config.GetWord();
997
998// We do not support stacking as the caller does not support stacking
999//
1000 if (val && !strcmp("++", val))
1001 {eDest.Say("Config warning: stacked plugins are not supported in "
1002 "this context; directive ignored!");
1003 return true;
1004 }
1005
1006// Now skip over any options
1007//
1008 while(val && *val && *val == '+') val = Config.GetWord();
1009
1010// Check if we actually have a path
1011//
1012 if (!val || !val[0])
1013 {eDest.Emsg("Config", libName, "not specified"); return false;}
1014
1015// Record the path
1016//
1017 if (libPath) free(libPath);
1018 libPath = strdup(val);
1019
1020// Handle optional parameter
1021//
1022 if (!libParm) return true;
1023 if (*libParm) free(*libParm);
1024 *libParm = 0;
1025
1026// Record any parms
1027//
1028 *parms = 0;
1029 if (!Config.GetRest(parms, sizeof(parms)))
1030 {eDest.Emsg("Config", libName, "parameters too long"); return false;}
1031 if (*parms) *libParm = strdup(parms);
1032 return true;
1033}
1034
1035/******************************************************************************/
1036/* p a r s e H o m e */
1037/******************************************************************************/
1038
1040{
1041 char *pval, *val, *HomePath = 0;
1042
1043// Get the path
1044//
1045 pval = Config.GetWord();
1046 if (!pval || !pval[0])
1047 {eDest.Emsg("Config", "home path not specified"); return 0;}
1048
1049// Make sure it's an absolute path
1050//
1051 if (*pval != '/')
1052 {eDest.Emsg("Config", "home path not absolute"); return 0;}
1053
1054// Record the path
1055//
1056 HomePath = strdup(pval);
1057
1058// Get the optional access rights
1059//
1060 mode = S_IRWXU;
1061 if ((val = Config.GetWord()) && val[0])
1062 {if (!strcmp("group", val)) mode |= (S_IRGRP | S_IXGRP);
1063 else {eDest.Emsg("Config", "invalid home path modifier -", val);
1064 free(HomePath);
1065 return 0;
1066 }
1067 }
1068 return HomePath;
1069}
1070
1071/******************************************************************************/
1072/* R e L i n k */
1073/******************************************************************************/
1074
1075int XrdOucUtils::ReLink(const char *path, const char *target, mode_t mode)
1076{
1077 const mode_t AMode = S_IRWXU; // Only us as a default
1078 char pbuff[MAXPATHLEN+64];
1079 int n;
1080
1081// Copy the path
1082//
1083 n = strlen(path);
1084 if (n >= (int)sizeof(pbuff)) return ENAMETOOLONG;
1085 strcpy(pbuff, path);
1086
1087// Unlink the target, make the path, and create the symlink
1088//
1089 unlink(path);
1090 makePath(pbuff, (mode ? mode : AMode));
1091 if (symlink(target, path)) return errno;
1092 return 0;
1093}
1094
1095/******************************************************************************/
1096/* S a n i t i z e */
1097/******************************************************************************/
1098
1099void XrdOucUtils::Sanitize(char *str, char subc)
1100{
1101
1102// Sanitize string according to POSIX.1-2008 stanadard using only the
1103// Portable Filename Character Set: a-z A-Z 0-9 ._- with 1st char not being -
1104//
1105 if (*str)
1106 {if (*str == '-') *str = subc;
1107 else if (*str == ' ') *str = subc;
1108 char *blank = rindex(str, ' ');
1109 if (blank) while(*blank == ' ') *blank-- = 0;
1110 while(*str)
1111 {if (!isalnum(*str) && index("_-.", *str) == 0) *str = subc;
1112 str++;
1113 }
1114 }
1115}
1116
1117/******************************************************************************/
1118/* s u b L o g f n */
1119/******************************************************************************/
1120
1121char *XrdOucUtils::subLogfn(XrdSysError &eDest, const char *inst, char *logfn)
1122{
1123 const mode_t lfm = S_IRWXU|S_IRWXG|S_IROTH|S_IXOTH;
1124 char buff[2048], *sp;
1125 int rc;
1126
1127 if (!inst || !*inst) return logfn;
1128 if (!(sp = rindex(logfn, '/'))) strcpy(buff, "./");
1129 else {*sp = '\0'; strcpy(buff, logfn); strcat(buff, "/");}
1130
1131 strcat(buff, inst); strcat(buff, "/");
1132
1133 if ((rc = XrdOucUtils::makePath(buff, lfm)))
1134 {eDest.Emsg("Config", rc, "create log file path", buff);
1135 return 0;
1136 }
1137
1138 if (sp) {*sp = '/'; strcat(buff, sp+1);}
1139 else strcat(buff, logfn);
1140
1141 free(logfn);
1142 return strdup(buff);
1143}
1144
1145/******************************************************************************/
1146/* t o L o w e r */
1147/******************************************************************************/
1148
1150{
1151 unsigned char* ustr = (unsigned char*)str; // Avoid undefined behaviour
1152
1153// Change each character to lower case
1154//
1155 while(*ustr) {*ustr = tolower(*ustr); ustr++;}
1156}
1157
1158/******************************************************************************/
1159/* T o k e n */
1160/******************************************************************************/
1161
1162int XrdOucUtils::Token(const char **str, char delim, char *buff, int bsz)
1163{
1164 const char *eP, *bP = *str;
1165 int aLen, mLen;
1166
1167// Trim off the delimeters. Return zero if nothing left.
1168//
1169 while(*bP && *bP == delim) bP++;
1170 if (*bP == 0) {*buff = 0; return 0;}
1171
1172// Find the next delimiter
1173//
1174 eP = bP;
1175 while(*eP && *eP != delim) eP++;
1176
1177// If we ended at a null, make sure next call will return zero
1178//
1179 if (*eP == 0) *str = eP;
1180 else *str = eP+1;
1181
1182// Calculate length and make sure we don't overrun the buffer
1183//
1184 aLen = eP-bP;
1185 if (aLen >= bsz) mLen = bsz-1;
1186 else mLen = aLen;
1187
1188// Copy token into buffer and end with null byte
1189//
1190 strncpy(buff, bP, mLen);
1191 buff[mLen] = 0;
1192
1193// Return actual length
1194//
1195 return aLen;
1196}
1197
1198/******************************************************************************/
1199/* U n d e r c o v e r */
1200/******************************************************************************/
1201#ifdef WIN32
1202void XrdOucUtils::Undercover(XrdSysError &, int, int *)
1203{
1204}
1205#else
1206void XrdOucUtils::Undercover(XrdSysError &eDest, int noLog, int *pipeFD)
1207{
1208 static const int maxFiles = 256;
1209 pid_t mypid;
1210 int myfd, logFD = eDest.baseFD();
1211
1212// Issue warning if there is no logfile attached
1213//
1214 if (noLog) eDest.Emsg("Config", "Warning! No log file specified; "
1215 "backgrounding disables all logging!");
1216
1217// Fork so that we are not tied to a shell
1218//
1219 if ((mypid = fork()) < 0)
1220 {eDest.Emsg("Config", errno, "fork process 1 for backgrounding");
1221 return;
1222 }
1223 else if (mypid)
1224 {
1225 // we have been given a pair of pipe descriptors to be able to read the
1226 // status of the child process
1227 if( pipeFD )
1228 {
1229 int status = 1;
1230 close( pipeFD[1] );
1231 // read will wait untill the status is communicated by the
1232 // child process, if the child process dies before being able
1233 // to comunicate the status then read will see EOF
1234 if( read( pipeFD[0], &status, sizeof(status) ) != sizeof(status) )
1235 _exit(1);
1236 _exit(status);
1237 }
1238 // no pipes given, return success
1239 else _exit(0);
1240 }
1241
1242 if( pipeFD )
1243 close( pipeFD[0] );
1244
1245// Become the process group leader
1246//
1247 if (setsid() < 0)
1248 {eDest.Emsg("Config", errno, "doing setsid() for backgrounding");
1249 return;
1250 }
1251
1252// Fork to that we are cannot get a controlling terminal
1253//
1254 if ((mypid = fork()) < 0)
1255 {eDest.Emsg("Config", errno, "fork process 2 for backgrounding");
1256 return;
1257 }
1258 else if (mypid) _exit(0);
1259
1260// Switch stdin, stdout, and stderr to /dev/null (we can't use /dev/console
1261// unless we are root which is unlikely).
1262//
1263 if ((myfd = open("/dev/null", O_RDWR)) < 0)
1264 {eDest.Emsg("Config", errno, "open /dev/null for backgrounding");
1265 return;
1266 }
1267 dup2(myfd, 0); dup2(myfd, 1); dup2(myfd, 2); dup2(myfd, logFD);
1268
1269// Close any open file descriptors left open by the parent process
1270// but the communication pipe and the logger's shadow file descriptor.
1271//
1272 for (myfd = 3; myfd < maxFiles; myfd++)
1273 if( (!pipeFD || myfd != pipeFD[1]) && myfd != logFD ) close(myfd);
1274}
1275
1276/******************************************************************************/
1277/* U i d N a m e */
1278/******************************************************************************/
1279
1280int XrdOucUtils::UidName(uid_t uID, char *uName, int uNsz, time_t keepT)
1281{
1282 struct passwd *pEnt, pStruct;
1283 char pBuff[1024];
1284 int n, rc;
1285
1286// Get ID from cache, if allowed
1287//
1288 if (keepT)
1289 {int n = LookUp(uidMap, static_cast<unsigned int>(uID),uName,uNsz);
1290 if (n > 0) return (n < uNsz ? n : 0);
1291 }
1292
1293// Try to obtain the username. We use this form to make sure we are using
1294// the standards conforming version (compilation error otherwise).
1295//
1296 rc = getpwuid_r(uID, &pStruct, pBuff, sizeof(pBuff), &pEnt);
1297 if (rc || !pEnt)
1298 {n = snprintf(uName, uNsz, "%ud", static_cast<unsigned int>(uID));
1299 return (n >= uNsz ? 0 : n);
1300 }
1301
1302// Add entry to the cache if need be
1303//
1304 if (keepT)
1305 AddID(uidMap, static_cast<unsigned int>(uID), pEnt->pw_name, keepT);
1306
1307// Return length of username or zero if it is too big
1308//
1309 n = strlen(pEnt->pw_name);
1310 if (uNsz <= (int)strlen(pEnt->pw_name)) return 0;
1311 strcpy(uName, pEnt->pw_name);
1312 return n;
1313}
1314
1315/******************************************************************************/
1316/* U s e r N a m e */
1317/******************************************************************************/
1318
1319int XrdOucUtils::UserName(uid_t uID, char *uName, int uNsz)
1320{
1321 struct passwd *pEnt, pStruct;
1322 char pBuff[1024];
1323 int rc;
1324
1325// Try to obtain the username. We use this form to make sure we are using
1326// the standards conforming version (compilation error otherwise).
1327//
1328 rc = getpwuid_r(uID, &pStruct, pBuff, sizeof(pBuff), &pEnt);
1329 if (rc) return rc;
1330 if (!pEnt) return ESRCH;
1331
1332// Return length of username or zero if it is too big
1333//
1334 if (uNsz <= (int)strlen(pEnt->pw_name)) return ENAMETOOLONG;
1335 strcpy(uName, pEnt->pw_name);
1336 return 0;
1337}
1338
1339/******************************************************************************/
1340/* V a l P a t h */
1341/******************************************************************************/
1342
1343const char *XrdOucUtils::ValPath(const char *path, mode_t allow, bool isdir)
1344{
1345 static const mode_t mMask = S_IRWXU | S_IRWXG | S_IRWXO;
1346 struct stat buf;
1347
1348// Check if this really exists
1349//
1350 if (stat(path, &buf))
1351 {if (errno == ENOENT) return "does not exist.";
1352 return XrdSysE2T(errno);
1353 }
1354
1355// Verify that this is the correct type of file
1356//
1357 if (isdir)
1358 {if (!S_ISDIR(buf.st_mode)) return "is not a directory.";
1359 } else {
1360 if (!S_ISREG(buf.st_mode)) return "is not a file.";
1361 }
1362
1363// Verify that the does not have excessive privileges
1364//
1365 if ((buf.st_mode & mMask) & ~allow) return "has excessive access rights.";
1366
1367// All went well
1368//
1369 return 0;
1370}
1371
1372/******************************************************************************/
1373/* P i d F i l e */
1374/******************************************************************************/
1375
1377{
1378 char buff[32];
1379 int fd;
1380
1381 if( (fd = open( path, O_WRONLY|O_CREAT|O_TRUNC, 0644 )) < 0 )
1382 {
1383 eDest.Emsg( "Config", errno, "create pidfile" );
1384 return false;
1385 }
1386
1387 if( write( fd, buff, snprintf( buff, sizeof(buff), "%d",
1388 static_cast<int>(getpid()) ) ) < 0 )
1389 {
1390 eDest.Emsg( "Config", errno, "write to pidfile" );
1391 close(fd);
1392 return false;
1393 }
1394
1395 close(fd);
1396 return true;
1397}
1398/******************************************************************************/
1399/* getModificationTime */
1400/******************************************************************************/
1401int XrdOucUtils::getModificationTime(const char *path, time_t &modificationTime) {
1402 struct stat buf;
1403 int statRet = ::stat(path,&buf);
1404 if(!statRet) {
1405 modificationTime = buf.st_mtime;
1406 }
1407 return statRet;
1408}
1409
1410void XrdOucUtils::trim(std::string &str) {
1411 // Trim leading non-letters
1412 while( str.size() && !isgraph(str[0]) ) str.erase(str.begin());
1413
1414 // Trim trailing non-letters
1415
1416 while( str.size() && !isgraph(str[str.size()-1]) )
1417 str.resize (str.size () - 1);
1418}
1419
1424
1425static bool is_token_character(int c)
1426{
1427 if (isalnum(c))
1428 return true;
1429
1430 static constexpr char token_chars[] = "-._~+/=:";
1431
1432 for (char ch : token_chars)
1433 if (c == ch)
1434 return true;
1435
1436 return false;
1437}
1438
1446
1447std::string obfuscateAuth(const std::string& input)
1448{
1449 static const regex_t auth_regex = []() {
1450 constexpr char re[] =
1451 "(authz=|(transferheader)?(www-|proxy-)?auth(orization|enticate)[[:space:]]*:[[:space:]]*)"
1452 "(Bearer([[:space:]]|%20)?(token([[:space:]]|%20)?)?)?";
1453
1454 regex_t regex;
1455
1456 if (regcomp(&regex, re, REG_EXTENDED | REG_ICASE) != 0)
1457 throw std::runtime_error("Failed to compile regular expression");
1458
1459 return regex;
1460 }();
1461
1462 regmatch_t match;
1463 size_t offset = 0;
1464 std::string redacted;
1465 const char *const text = input.c_str();
1466
1467 while (regexec(&auth_regex, text + offset, 1, &match, 0) == 0) {
1468 redacted.append(text + offset, match.rm_eo).append("REDACTED");
1469
1470 offset += match.rm_eo;
1471
1472 while (offset < input.size() && is_token_character(input[offset]))
1473 ++offset;
1474 }
1475
1476 return redacted.append(text + offset);
1477}
1478
1479#endif
struct stat Stat
Definition XrdCks.cc:49
static XrdSysError eDest(0,"crypto_")
#define ENODATA
uint32_t crc32c(uint32_t crc, void const *buf, size_t len)
#define SHFT(k)
static bool is_token_character(int c)
std::string obfuscateAuth(const std::string &input)
#define close(a)
Definition XrdPosix.hh:43
#define fstat(a, b)
Definition XrdPosix.hh:57
#define write(a, b, c)
Definition XrdPosix.hh:110
#define open
Definition XrdPosix.hh:71
#define chdir(a)
Definition XrdPosix.hh:41
#define unlink(a)
Definition XrdPosix.hh:108
#define stat(a, b)
Definition XrdPosix.hh:96
#define read(a, b, c)
Definition XrdPosix.hh:77
const char * XrdSysE2T(int errcode)
Definition XrdSysE2T.cc:104
size_t strlcpy(char *dst, const char *src, size_t sz)
#define CHMOD(path, mode)
#define MAKEDIR(path, mode)
static bool Match(const char *hName, const char *pattern)
static bool Parse(const char *hSpec, const char **hName, const char **hNend, const char **hPort, const char **hPend)
static uint32_t Calc32C(const void *data, size_t count, uint32_t prevcs=0)
Definition XrdOucCRC.cc:190
char * Get(const char *varname)
Definition XrdOucEnv.hh:69
MDLen
SHA3 digest lengths (bits to bytes).
Definition XrdOucSHA3.hh:56
static void * Calc(const void *in, size_t inlen, void *md, MDLen mdlen)
int length() const
int tokenize(XrdOucString &tok, int from, char del=':')
const char * c_str() const
static char * parseHome(XrdSysError &eDest, XrdOucStream &Config, int &mode)
static void Sanitize(char *instr, char subc='_')
static bool getGID(const char *gName, gid_t &gID)
static const mode_t pathMode
static int isFWD(const char *path, int *port=0, char *hBuff=0, int hBLen=0, bool pTrim=false)
static int UserName(uid_t uID, char *uName, int uNsz)
static char * Ident(long long &mySID, char *iBuff, int iBlen, const char *iHost, const char *iProg, const char *iName, int Port)
static bool getUID(const char *uName, uid_t &uID, gid_t *gID=0)
static int getModificationTime(const char *path, time_t &modificationTime)
static const char * ValPath(const char *path, mode_t allow, bool isdir)
static char * genPath(const char *path, const char *inst, const char *psfx=0)
static int Token(const char **str, char delim, char *buff, int bsz)
static int ReLink(const char *path, const char *target, mode_t mode=0)
static bool parseLib(XrdSysError &eDest, XrdOucStream &Config, const char *libName, char *&path, char **libparm)
static int is1of(char *val, const char **clist)
static const char * InstName(int TranOpt=0)
static char * eText(int rc, char *eBuff, int eBlen)
static int argList(char *args, char **argV, int argC)
static bool mode2mask(const char *mode, mode_t &mask)
static int GidName(gid_t gID, char *gName, int gNsz, time_t keepT=0)
static int UidName(uid_t uID, char *uName, int uNsz, time_t keepT=0)
static char * bin2hex(char *inbuff, int dlen, char *buff, int blen, bool sep=true)
static int Log10(unsigned long long n)
static int doIf(XrdSysError *eDest, XrdOucStream &Config, const char *what, const char *hname, const char *nname, const char *pname)
static int makePath(char *path, mode_t mode, bool reset=false)
static int GroupName(gid_t gID, char *gName, int gNsz)
static void trim(std::string &str)
static bool findPgm(const char *pgm, XrdOucString &path)
static bool PidFile(XrdSysError &eDest, const char *path)
static const char * i2bstr(char *buff, int blen, int val, bool pad=false)
static void toLower(char *str)
static int fmtBytes(long long val, char *buff, int bsz)
static int Log2(unsigned long long n)
static void makeHome(XrdSysError &eDest, const char *inst)
static bool endsWith(const char *text, const char *ending, int endlen)
static void Undercover(XrdSysError &eDest, int noLog, int *pipeFD=0)
static char * getFile(const char *path, int &rc, int maxsz=10240, bool notempty=true)
static char * subLogfn(XrdSysError &eDest, const char *inst, char *logfn)