XrdProofdAux.cxx

Go to the documentation of this file.
00001 // @(#)root/proofd:$Id: XrdProofdAux.cxx 35228 2010-09-10 14:36:15Z ganis $
00002 // Author: G. Ganis  June 2007
00003 
00004 /*************************************************************************
00005  * Copyright (C) 1995-2005, Rene Brun and Fons Rademakers.               *
00006  * All rights reserved.                                                  *
00007  *                                                                       *
00008  * For the licensing terms see $ROOTSYS/LICENSE.                         *
00009  * For the list of contributors see $ROOTSYS/README/CREDITS.             *
00010  *************************************************************************/
00011 
00012 //////////////////////////////////////////////////////////////////////////
00013 //                                                                      //
00014 // XrdProofdAux                                                          //
00015 //                                                                      //
00016 // Authors: G. Ganis, CERN, 2007                                        //
00017 //                                                                      //
00018 // Small auxilliary classes used in XrdProof                            //
00019 //                                                                      //
00020 //////////////////////////////////////////////////////////////////////////
00021 #include "XrdProofdPlatform.h"
00022 
00023 #include "XrdOuc/XrdOucStream.hh"
00024 #include "XrdSys/XrdSysPriv.hh"
00025 
00026 #include "XrdProofdAux.h"
00027 #include "XrdProofdConfig.h"
00028 #include "XrdProofdProtocol.h"
00029 
00030 // Tracing
00031 #include "XrdProofdTrace.h"
00032 
00033 // Local definitions
00034 #ifdef XPD_MAXLEN
00035 #undefine XPD_MAXLEN
00036 #endif
00037 #define XPD_MAXLEN 1024
00038 
00039 XrdSysRecMutex XrdProofdAux::fgFormMutex;
00040 
00041 //______________________________________________________________________________
00042 const char *XrdProofdAux::AdminMsgType(int type)
00043 {
00044    // Translates the admin message type in a human readable string.
00045    // Must be consistent with the values in XProofProtocol.h
00046 
00047    static const char *msgtypes[] = { "Undef",
00048      "QuerySessions", "SessionTag", "SessionAlias", "GetWorkers", "QueryWorkers",
00049      "CleanupSessions", "QueryLogPaths", "ReadBuffer", "QueryROOTVersions",
00050      "ROOTVersion", "GroupProperties", "SendMsgToUser", "ReleaseWorker",
00051      "Exec", "GetFile", "PutFile", "CpFile"};
00052 
00053    if (type < 1000 || type >= kUndef) {
00054       return msgtypes[0];
00055    } else {
00056       int t = type - 999;
00057       return msgtypes[t];
00058    }
00059 }
00060 
00061 //______________________________________________________________________________
00062 const char *XrdProofdAux::ProofRequestTypes(int type)
00063 {
00064    // Translates the proof request type in a human readable string.
00065    // Must be consistent with the values in XProofProtocol.h.
00066    // The reserved ones are for un
00067 
00068    static const char *reqtypes[] = { "Undef",
00069       "XP_login", "XP_auth", "XP_create", "XP_destroy", "XP_attach", "XP_detach",
00070       "XP_3107", "XP_3108", "XP_3109", "XP_3110",
00071       "XP_urgent", "XP_sendmsg", "XP_admin", "XP_interrupt", "XP_ping",
00072       "XP_cleanup", "XP_readbuf", "XP_touch", "XP_ctrlc" };
00073 
00074    if (type < 3101 || type >= kXP_Undef) {
00075       return reqtypes[0];
00076    } else {
00077       int t = type - 3100;
00078       return reqtypes[t];
00079    }
00080 }
00081 
00082 //______________________________________________________________________________
00083 char *XrdProofdAux::Expand(char *p)
00084 {
00085    // Expand path 'p' relative to:
00086    //     $HOME               if begins with ~/
00087    //     <user>'s $HOME      if begins with ~<user>/
00088    //     $PWD                if does not begin with '/' or '~'
00089    //   getenv(<ENVVAR>)      if it begins with $<ENVVAR>)
00090    // The returned array of chars is the result of reallocation
00091    // of the input one.
00092    // If something is inconsistent, for example <ENVVAR> does not
00093    // exists, the original string is untouched
00094 
00095    // Make sure there soething to expand
00096    if (!p || strlen(p) <= 0 || p[0] == '/')
00097       return p;
00098 
00099    char *po = p;
00100 
00101    // Relative to the environment variable
00102    if (p[0] == '$') {
00103       // Resolve env
00104       XrdOucString env(&p[1]);
00105       int isl = env.find('/');
00106       env.erase(isl);
00107       char *p1 = (isl > 0) ? (char *)(p + isl + 2) : 0;
00108       if (getenv(env.c_str())) {
00109          int lenv = strlen(getenv(env.c_str()));
00110          int lp1 = p1 ? strlen(p1) : 0;
00111          po = (char *) malloc(lp1 + lenv + 2);
00112          if (po) {
00113             memcpy(po, getenv(env.c_str()), lenv);
00114             if (p1) {
00115                memcpy(po+lenv+1, p1, lp1);
00116                po[lenv] = '/';
00117             }
00118             po[lp1 + lenv + 1] = 0;
00119             free(p);
00120          } else
00121             po = p;
00122       }
00123       return po;
00124    }
00125 
00126    // Relative to the local location
00127    if (p[0] != '~') {
00128       if (getenv("PWD")) {
00129          int lpwd = strlen(getenv("PWD"));
00130          int lp = strlen(p);
00131          po = (char *) malloc(lp + lpwd + 2);
00132          if (po) {
00133             memcpy(po, getenv("PWD"), lpwd);
00134             memcpy(po+lpwd+1, p, lp);
00135             po[lpwd] = '/';
00136             po[lpwd+lp+1] = 0;
00137             free(p);
00138          } else
00139             po = p;
00140       }
00141       return po;
00142    }
00143 
00144    // Relative to $HOME or <user>'s $HOME
00145    if (p[0] == '~') {
00146       char *pu = p+1;
00147       char *pd = strchr(pu,'/');
00148       *pd++ = '\0';
00149       // Get the correct user structure
00150       XrdProofUI ui;
00151       int rc = 0;
00152       if (strlen(pu) > 0) {
00153          rc = XrdProofdAux::GetUserInfo(pu, ui);
00154       } else {
00155          rc = XrdProofdAux::GetUserInfo(getuid(), ui);
00156       }
00157       if (rc == 0) {
00158          int ldir = ui.fHomeDir.length();
00159          int lpd = strlen(pd);
00160          po = (char *) malloc(lpd + ldir + 2);
00161          if (po) {
00162             memcpy(po, ui.fHomeDir.c_str(), ldir);
00163             memcpy(po+ldir+1, pd, lpd);
00164             po[ldir] = '/';
00165             po[lpd + ldir + 1] = 0;
00166             free(p);
00167          } else
00168             po = p;
00169       }
00170       return po;
00171    }
00172 
00173    // We are done
00174    return po;
00175 }
00176 
00177 //______________________________________________________________________________
00178 void XrdProofdAux::Expand(XrdOucString &p)
00179 {
00180    // Expand path 'p' relative to:
00181    //     $HOME               if begins with ~/
00182    //     <user>'s $HOME      if begins with ~<user>/
00183    //     $PWD                if does not begin with '/' or '~'
00184    //   getenv(<ENVVAR>)      if it begins with $<ENVVAR>)
00185    // The input string is updated with the result.
00186    // If something is inconsistent, for example <ENVVAR> does not
00187    // exists, the original string is untouched
00188 
00189    char *po = strdup((char *)p.c_str());
00190    po = Expand(po);
00191    p = po;
00192    SafeFree(po);
00193 }
00194 
00195 //__________________________________________________________________________
00196 long int XrdProofdAux::GetLong(char *str)
00197 {
00198    // Extract first integer from string at 'str', if any
00199 
00200    // Reposition on first digit
00201    char *p = str;
00202    while ((*p < 48 || *p > 57) && (*p) != '\0')
00203       p++;
00204    if (*p == '\0')
00205       return LONG_MAX;
00206 
00207    // Find the last digit
00208    int j = 0;
00209    while (*(p+j) >= 48 && *(p+j) <= 57)
00210       j++;
00211    *(p+j) = '\0';
00212 
00213    // Convert now
00214    return strtol(p, 0, 10);
00215 }
00216 
00217 //__________________________________________________________________________
00218 int XrdProofdAux::GetGroupInfo(const char *grp, XrdProofGI &gi)
00219 {
00220    // Get information about group with 'gid' in a thread safe way.
00221    // Retur 0 on success, -errno on error
00222 
00223    // Make sure input is defined
00224    if (!grp || strlen(grp) <= 0)
00225       return -EINVAL;
00226 
00227    // Call getgrgid_r ...
00228    struct group gr;
00229    struct group *pgr = 0;
00230    char buf[2048];
00231 #if defined(__sun) && !defined(__GNUC__)
00232    pgr = getgrnam_r(grp, &gr, buf, sizeof(buf));
00233 #else
00234    getgrnam_r(grp, &gr, buf, sizeof(buf), &pgr);
00235 #endif
00236    if (pgr) {
00237       // Fill output
00238       gi.fGroup = grp;
00239       gi.fGid = (int) gr.gr_gid;
00240       // Done
00241       return 0;
00242    }
00243 
00244    // Failure
00245    if (errno != 0)
00246       return ((int) -errno);
00247    else
00248       return -ENOENT;
00249 }
00250 
00251 //__________________________________________________________________________
00252 int XrdProofdAux::GetGroupInfo(int gid, XrdProofGI &gi)
00253 {
00254    // Get information about group with 'gid' in a thread safe way.
00255    // Retur 0 on success, -errno on error
00256 
00257    // Make sure input make sense
00258    if (gid <= 0)
00259       return -EINVAL;
00260 
00261    // Call getgrgid_r ...
00262    struct group gr;
00263    struct group *pgr = 0;
00264    char buf[2048];
00265 #if defined(__sun) && !defined(__GNUC__)
00266    pgr = getgrgid_r((gid_t)gid, &gr, buf, sizeof(buf));
00267 #else
00268    getgrgid_r((gid_t)gid, &gr, buf, sizeof(buf), &pgr);
00269 #endif
00270    if (pgr) {
00271       // Fill output
00272       gi.fGroup = gr.gr_name;
00273       gi.fGid = gid;
00274       // Done
00275       return 0;
00276    }
00277 
00278    // Failure
00279    if (errno != 0)
00280       return ((int) -errno);
00281    else
00282       return -ENOENT;
00283 }
00284 
00285 //__________________________________________________________________________
00286 int XrdProofdAux::GetUserInfo(const char *usr, XrdProofUI &ui)
00287 {
00288    // Get information about user 'usr' in a thread safe way.
00289    // Return 0 on success, -errno on error
00290 
00291    // Make sure input is defined
00292    if (!usr || strlen(usr) <= 0)
00293       return -EINVAL;
00294 
00295    // Call getpwnam_r ...
00296    struct passwd pw;
00297    struct passwd *ppw = 0;
00298    char buf[2048];
00299 #if defined(__sun) && !defined(__GNUC__)
00300    ppw = getpwnam_r(usr, &pw, buf, sizeof(buf));
00301 #else
00302    getpwnam_r(usr, &pw, buf, sizeof(buf), &ppw);
00303 #endif
00304    if (ppw) {
00305       // Fill output
00306       ui.fUid = (int) pw.pw_uid;
00307       ui.fGid = (int) pw.pw_gid;
00308       ui.fHomeDir = pw.pw_dir;
00309       ui.fUser = usr;
00310       // Done
00311       return 0;
00312    }
00313 
00314    // Failure
00315    if (errno != 0)
00316       return ((int) -errno);
00317    else
00318       return -ENOENT;
00319 }
00320 
00321 //__________________________________________________________________________
00322 int XrdProofdAux::GetUserInfo(int uid, XrdProofUI &ui)
00323 {
00324    // Get information about user with 'uid' in a thread safe way.
00325    // Retur 0 on success, -errno on error
00326 
00327    // Make sure input make sense
00328    if (uid < 0)
00329       return -EINVAL;
00330 
00331    // Call getpwuid_r ...
00332    struct passwd pw;
00333    struct passwd *ppw = 0;
00334    char buf[2048];
00335 #if defined(__sun) && !defined(__GNUC__)
00336    ppw = getpwuid_r((uid_t)uid, &pw, buf, sizeof(buf));
00337 #else
00338    getpwuid_r((uid_t)uid, &pw, buf, sizeof(buf), &ppw);
00339 #endif
00340    if (ppw) {
00341       // Fill output
00342       ui.fUid = uid;
00343       ui.fGid = (int) pw.pw_gid;
00344       ui.fHomeDir = pw.pw_dir;
00345       ui.fUser = pw.pw_name;
00346       // Done
00347       return 0;
00348    }
00349 
00350    // Failure
00351    if (errno != 0)
00352       return ((int) -errno);
00353    else
00354       return -ENOENT;
00355 }
00356 
00357 //__________________________________________________________________________
00358 int XrdProofdAux::Write(int fd, const void *buf, size_t nb)
00359 {
00360    // Write nb bytes at buf to descriptor 'fd' ignoring interrupts
00361    // Return the number of bytes written or -1 in case of error
00362 
00363    if (fd < 0)
00364       return -1;
00365 
00366    const char *pw = (const char *)buf;
00367    int lw = nb;
00368    int nw = 0, written = 0;
00369    while (lw) {
00370       if ((nw = write(fd, pw + written, lw)) < 0) {
00371          if (errno == EINTR) {
00372             errno = 0;
00373             continue;
00374          } else {
00375             break;
00376          }
00377       }
00378       // Count
00379       written += nw;
00380       lw -= nw;
00381    }
00382 
00383    // Done
00384    return written;
00385 }
00386 
00387 //_____________________________________________________________________________
00388 int XrdProofdAux::AssertDir(const char *path, XrdProofUI ui, bool changeown)
00389 {
00390    // Make sure that 'path' exists and is owned by the entity
00391    // described by 'ui'.
00392    // If changeown is TRUE it tries to acquire the privileges before.
00393    // Return 0 in case of success, -1 in case of error
00394    XPDLOC(AUX, "Aux::AssertDir")
00395 
00396    TRACE(DBG, path);
00397 
00398    if (!path || strlen(path) <= 0)
00399       return -1;
00400 
00401    struct stat st;
00402    if (stat(path,&st) != 0) {
00403       if (errno == ENOENT) {
00404 
00405          {  XrdSysPrivGuard pGuard((uid_t)0, (gid_t)0);
00406             if (XpdBadPGuard(pGuard, ui.fUid) && changeown) {
00407                TRACE(XERR, "could not get privileges to create dir");
00408                return -1;
00409             }
00410 
00411             if (mkdir(path, 0755) != 0) {
00412                TRACE(XERR, "unable to create dir: "<<path<<" (errno: "<<errno<<")");
00413                return -1;
00414             }
00415          }
00416          if (stat(path,&st) != 0) {
00417             TRACE(XERR, "unable to stat dir: "<<path<<" (errno: "<<errno<<")");
00418             return -1;
00419          }
00420       } else {
00421          // Failure: stop
00422          TRACE(XERR, "unable to stat dir: "<<path<<" (errno: "<<errno<<")");
00423          return -1;
00424       }
00425    }
00426 
00427    // Make sure the ownership is right
00428    if (changeown &&
00429       ((int) st.st_uid != ui.fUid || (int) st.st_gid != ui.fGid)) {
00430 
00431       XrdSysPrivGuard pGuard((uid_t)0, (gid_t)0);
00432       if (XpdBadPGuard(pGuard, ui.fUid)) {
00433          TRACE(XERR, "could not get privileges to change ownership");
00434          return -1;
00435       }
00436 
00437       // Set ownership of the path to the client
00438       if (chown(path, ui.fUid, ui.fGid) == -1) {
00439          TRACE(XERR, "cannot set user ownership on path (errno: "<<errno<<")");
00440          return -1;
00441       }
00442    }
00443 
00444    // We are done
00445    return 0;
00446 }
00447 
00448 //_____________________________________________________________________________
00449 int XrdProofdAux::ChangeOwn(const char *path, XrdProofUI ui)
00450 {
00451    // Change the ownership of 'path' to the entity described by 'ui'.
00452    // If 'path' is a directory, go through the paths inside it recursively.
00453    // Return 0 in case of success, -1 in case of error
00454    XPDLOC(AUX, "Aux::ChangeOwn")
00455 
00456    TRACE(DBG, path);
00457 
00458    if (!path || strlen(path) <= 0)
00459       return -1;
00460 
00461    struct stat st;
00462    if (stat(path,&st) != 0) {
00463       // Failure: stop
00464       TRACE(XERR, "unable to stat path: "<<path<<" (errno: "<<errno<<")");
00465       return -1;
00466    }
00467 
00468    // If is a directory apply this on it
00469    if (S_ISDIR(st.st_mode)) {
00470       // Loop over the dir
00471       DIR *dir = opendir(path);
00472       if (!dir) {
00473          TRACE(XERR,"cannot open "<<path<< "- errno: "<< errno);
00474          return -1;
00475       }
00476       XrdOucString proot(path);
00477       if (!proot.endswith('/')) proot += "/";
00478 
00479       struct dirent *ent = 0;
00480       while ((ent = readdir(dir))) {
00481          if (ent->d_name[0] == '.' || !strcmp(ent->d_name, "..")) continue;
00482          XrdOucString fn(proot);
00483          fn += ent->d_name;
00484 
00485          struct stat xst;
00486          if (stat(fn.c_str(),&xst) == 0) {
00487             // If is a directory apply this on it
00488             if (S_ISDIR(xst.st_mode)) {
00489                if (XrdProofdAux::ChangeOwn(fn.c_str(), ui) != 0) {
00490                   TRACE(XERR, "problems changing recursively ownership of: "<<fn);
00491                   return -1;
00492                }
00493             } else {
00494                // Get the privileges, if needed
00495                XrdSysPrivGuard pGuard((uid_t)0, (gid_t)0);
00496                if (XpdBadPGuard(pGuard, ui.fUid)) {
00497                   TRACE(XERR, "could not get privileges to change ownership");
00498                   return -1;
00499                }
00500                // Set ownership of the path to the client
00501                if (chown(fn.c_str(), ui.fUid, ui.fGid) == -1) {
00502                   TRACE(XERR, "cannot set user ownership on path (errno: "<<errno<<")");
00503                   return -1;
00504                }
00505             }
00506          } else {
00507             TRACE(XERR, "unable to stat dir: "<<fn<<" (errno: "<<errno<<")");
00508          }
00509       }
00510 
00511    } else if (((int) st.st_uid != ui.fUid) || ((int) st.st_gid != ui.fGid)) {
00512       // Get the privileges, if needed
00513       XrdSysPrivGuard pGuard((uid_t)0, (gid_t)0);
00514       if (XpdBadPGuard(pGuard, ui.fUid)) {
00515          TRACE(XERR, "could not get privileges to change ownership");
00516          return -1;
00517       }
00518       // Set ownership of the path to the client
00519       if (chown(path, ui.fUid, ui.fGid) == -1) {
00520          TRACE(XERR, "cannot set user ownership on path (errno: "<<errno<<")");
00521          return -1;
00522       }
00523    }
00524 
00525    // We are done
00526    return 0;
00527 }
00528 
00529 //_____________________________________________________________________________
00530 int XrdProofdAux::ChangeMod(const char *path, unsigned int mode)
00531 {
00532    // Change the permission mode of 'path' to 'mode'.
00533    // If 'path' is a directory, go through the paths inside it recursively.
00534    // Return 0 in case of success, -1 in case of error
00535    XPDLOC(AUX, "Aux::ChangeMod")
00536 
00537    TRACE(HDBG, "path: "<<path);
00538 
00539    if (!path || strlen(path) <= 0)
00540       return -1;
00541 
00542    struct stat st;
00543    if (stat(path,&st) != 0) {
00544       // Failure: stop
00545       TRACE(XERR, "unable to stat path: "<<path<<" (errno: "<<errno<<")");
00546       return -1;
00547    }
00548 
00549    // Change the path first; then do it recursively, if needed
00550    {  // Get the privileges, if needed
00551       XrdSysPrivGuard pGuard(st.st_uid, st.st_gid);
00552       if (XpdBadPGuard(pGuard, st.st_uid)) {
00553          TRACE(XERR, "could not get privileges to change ownership");
00554          return -1;
00555       }
00556       // Set ownership of the path to the client
00557       if (chmod(path, mode) == -1) {
00558          TRACE(XERR, "cannot change permissions on path (errno: "<<errno<<")");
00559          return -1;
00560       }
00561    }
00562 
00563    // If is a directory apply this on it
00564    if (S_ISDIR(st.st_mode)) {
00565       // Loop over the dir
00566       DIR *dir = opendir(path);
00567       if (!dir) {
00568          TRACE(XERR,"cannot open "<<path<< "- errno: "<< errno);
00569          return -1;
00570       }
00571       XrdOucString proot(path);
00572       if (!proot.endswith('/')) proot += "/";
00573 
00574       struct dirent *ent = 0;
00575       while ((ent = readdir(dir))) {
00576          if (ent->d_name[0] == '.' || !strcmp(ent->d_name, "..")) continue;
00577          XrdOucString fn(proot);
00578          fn += ent->d_name;
00579 
00580          struct stat xst;
00581          if (stat(fn.c_str(),&xst) == 0) {
00582             {  // Get the privileges, if needed
00583                TRACE(HDBG,"getting {"<<xst.st_uid<<", "<< xst.st_gid<<"} identity");
00584                XrdSysPrivGuard pGuard(xst.st_uid, xst.st_gid);
00585                if (XpdBadPGuard(pGuard, xst.st_uid)) {
00586                   TRACE(XERR, "could not get privileges to change ownership");
00587                   return -1;
00588                }
00589                // Set the permission mode of the path
00590                if (chmod(fn.c_str(), mode) == -1) {
00591                   TRACE(XERR, "cannot change permissions on path (errno: "<<errno<<")");
00592                   return -1;
00593                }
00594             }
00595             // If is a directory apply this on it
00596             if (S_ISDIR(xst.st_mode)) {
00597                if (XrdProofdAux::ChangeMod(fn.c_str(), mode) != 0) {
00598                   TRACE(XERR, "problems changing recursively permissions of: "<<fn);
00599                   return -1;
00600                }
00601             }
00602          } else {
00603             TRACE(XERR, "unable to stat dir: "<<fn<<" (errno: "<<errno<<")");
00604          }
00605       }
00606    }
00607 
00608    // We are done
00609    return 0;
00610 }
00611 
00612 //_____________________________________________________________________________
00613 int XrdProofdAux::ChangeToDir(const char *dir, XrdProofUI ui, bool changeown)
00614 {
00615    // Change current directory to 'dir'.
00616    // If changeown is TRUE it tries to acquire the privileges before.
00617    // Return 0 in case of success, -1 in case of error
00618    XPDLOC(AUX, "Aux::ChangeToDir")
00619 
00620    TRACE(DBG, "changing to " << ((dir) ? dir : "**undef***"));
00621 
00622    if (!dir || strlen(dir) <= 0)
00623       return -1;
00624 
00625    if (changeown && (int) geteuid() != ui.fUid) {
00626 
00627       XrdSysPrivGuard pGuard((uid_t)0, (gid_t)0);
00628       if (XpdBadPGuard(pGuard, ui.fUid)) {
00629          TRACE(XERR, changeown << ": could not get privileges; uid req:"<< ui.fUid <<
00630                      ", euid: " << geteuid() <<", uid:"<<getuid() << "; errno: "<<errno);
00631          return -1;
00632       }
00633       if (chdir(dir) == -1) {
00634          TRACE(XERR, changeown << ": can't change directory to "<< dir << " ui.fUid: " << ui.fUid <<
00635                      ", euid: " << geteuid() <<", uid:"<<getuid()<<"; errno: "<<errno);
00636          return -1;
00637       }
00638    } else {
00639       if (chdir(dir) == -1) {
00640          TRACE(XERR, changeown << ": can't change directory to "<< dir << 
00641                      ", euid: " << geteuid() <<", uid:"<<getuid()<<"; errno: "<<errno);
00642          return -1;
00643       }
00644    }
00645 
00646    // We are done
00647    return 0;
00648 }
00649 
00650 //_____________________________________________________________________________
00651 int XrdProofdAux::SymLink(const char *path, const char *link)
00652 {
00653    // Create a symlink 'link' to 'path'
00654    // Return 0 in case of success, -1 in case of error
00655    XPDLOC(AUX, "Aux::SymLink")
00656 
00657    TRACE(DBG, path<<" -> "<<link);
00658 
00659    if (!path || strlen(path) <= 0 || !link || strlen(link) <= 0)
00660       return -1;
00661 
00662    // Remove existing link, if any
00663    if (unlink(link) != 0 && errno != ENOENT) {
00664       TRACE(XERR, "problems unlinking existing symlink "<< link<<
00665                     " (errno: "<<errno<<")");
00666       return -1;
00667    }
00668    if (symlink(path, link) != 0) {
00669       TRACE(XERR, "problems creating symlink " << link<<
00670                     " (errno: "<<errno<<")");
00671       return -1;
00672    }
00673 
00674    // We are done
00675    return 0;
00676 }
00677 
00678 //______________________________________________________________________________
00679 int XrdProofdAux::CheckIf(XrdOucStream *s, const char *host)
00680 {
00681    // Check existence and match condition of an 'if' directive
00682    // If none (valid) is found, return -1.
00683    // Else, return number of chars matching.
00684    XPDLOC(AUX, "")
00685 
00686    // There must be an 'if'
00687    char *val = s ? s->GetWord() : 0;
00688    if (!val || strncmp(val,"if",2)) {
00689       if (val)
00690          // allow the analysis of the token
00691          s->RetToken();
00692       return -1;
00693    }
00694 
00695    // check value if any
00696    val = s->GetWord();
00697    if (!val)
00698       return -1;
00699 
00700    // Deprecate
00701    TRACE(ALL,  ">>> Warning: 'if' conditions at the end of the directive are deprecated ");
00702    TRACE(ALL,  ">>> Please use standard Scalla/Xrootd 'if-else-fi' constructs");
00703    TRACE(ALL,  ">>> (see http://xrootd.slac.stanford.edu/doc/xrd_config/xrd_config.htm)");
00704 
00705    // Notify
00706    TRACE(DBG, "Aux::CheckIf: <pattern>: " <<val);
00707 
00708    // Return number of chars matching
00709    XrdOucString h(host);
00710    return h.matches((const char *)val);
00711 }
00712 
00713 //______________________________________________________________________________
00714 int XrdProofdAux::GetNumCPUs()
00715 {
00716    // Find out and return the number of CPUs in the local machine.
00717    // Return -1 in case of failure.
00718    XPDLOC(AUX, "Aux::GetNumCPUs")
00719 
00720    static int ncpu = -1;
00721 
00722    // Use cached value, if any
00723    if (ncpu > 0)
00724       return ncpu;
00725    ncpu = 0;
00726 
00727    XrdOucString emsg;
00728 
00729 #if defined(linux)
00730    // Look for in the /proc/cpuinfo file
00731    XrdOucString fcpu("/proc/cpuinfo");
00732    FILE *fc = fopen(fcpu.c_str(), "r");
00733    if (!fc) {
00734       if (errno == ENOENT) {
00735          TRACE(XERR, "/proc/cpuinfo missing!!! Something very bad going on");
00736       } else {
00737          XPDFORM(emsg, "cannot open %s; errno: %d", fcpu.c_str(), errno);
00738          TRACE(XERR, emsg);
00739       }
00740       return -1;
00741    }
00742    // Read lines and count those starting with "processor"
00743    char line[2048] = { 0 };
00744    while (fgets(line, sizeof(line), fc)) {
00745       if (!strncmp(line, "processor", strlen("processor")))
00746          ncpu++;
00747    }
00748    // Close the file
00749    fclose(fc);
00750 
00751 #elif defined(__sun)
00752 
00753    // Run "psrinfo" in popen and count lines
00754    FILE *fp = popen("psrinfo", "r");
00755    if (fp != 0) {
00756       char line[2048] = { 0 };
00757       while (fgets(line, sizeof(line), fp))
00758          ncpu++;
00759       pclose(fp);
00760    }
00761 
00762 #elif defined(__FreeBSD__) || defined(__OpenBSD__) || defined(__APPLE__)
00763 
00764    // Run "sysctl -n hw.ncpu" in popen and decode the output
00765    FILE *fp = popen("sysctl -n hw.ncpu", "r");
00766    if (fp != 0) {
00767       char line[2048] = { 0 };
00768       while (fgets(line, sizeof(line), fp))
00769          ncpu = XrdProofdAux::GetLong(&line[0]);
00770       pclose(fp);
00771    }
00772 #endif
00773 
00774    TRACE(DBG, "# of cores found: "<<ncpu);
00775 
00776    // Done
00777    return (ncpu <= 0) ? (int)(-1) : ncpu ;
00778 }
00779 
00780 #if defined(__FreeBSD__) || defined(__OpenBSD__) || defined(__APPLE__)
00781 //__________________________________________________________________________
00782 int XrdProofdAux::GetMacProcList(kinfo_proc **plist, int &nproc)
00783 {
00784    // Returns a list of all processes on the system.  This routine
00785    // allocates the list and puts it in *plist and counts the
00786    // number of entries in 'nproc'. Caller is responsible for 'freeing'
00787    // the list.
00788    // On success, the function returns 0.
00789    // On error, the function returns an errno value.
00790    //
00791    // Adapted from: reply to Technical Q&A 1123,
00792    //               http://developer.apple.com/qa/qa2001/qa1123.html
00793    //
00794    XPDLOC(AUX, "Aux::GetMacProcList")
00795 
00796    int rc = 0;
00797    kinfo_proc *res;
00798    bool done = 0;
00799    static const int name[] = {CTL_KERN, KERN_PROC, KERN_PROC_ALL, 0};
00800 
00801    TRACE(DBG, "enter");
00802 
00803    // Declaring name as const requires us to cast it when passing it to
00804    // sysctl because the prototype doesn't include the const modifier.
00805    size_t len = 0;
00806 
00807    if (!plist || (*plist))
00808       return EINVAL;
00809    nproc = 0;
00810 
00811    // We start by calling sysctl with res == 0 and len == 0.
00812    // That will succeed, and set len to the appropriate length.
00813    // We then allocate a buffer of that size and call sysctl again
00814    // with that buffer.  If that succeeds, we're done.  If that fails
00815    // with ENOMEM, we have to throw away our buffer and loop.  Note
00816    // that the loop causes use to call sysctl with 0 again; this
00817    // is necessary because the ENOMEM failure case sets length to
00818    // the amount of data returned, not the amount of data that
00819    // could have been returned.
00820 
00821    res = 0;
00822    do {
00823       // Call sysctl with a 0 buffer.
00824       len = 0;
00825       if ((rc = sysctl((int *)name, (sizeof(name)/sizeof(*name)) - 1,
00826                        0, &len, 0, 0)) == -1) {
00827          rc = errno;
00828       }
00829 
00830       // Allocate an appropriately sized buffer based on the results
00831       // from the previous call.
00832       if (rc == 0) {
00833          res = (kinfo_proc *) malloc(len);
00834          if (!res)
00835             rc = ENOMEM;
00836       }
00837 
00838       // Call sysctl again with the new buffer.  If we get an ENOMEM
00839       // error, toss away our buffer and start again.
00840       if (rc == 0) {
00841          if ((rc = sysctl((int *)name, (sizeof(name)/sizeof(*name)) - 1,
00842                           res, &len, 0, 0)) == -1) {
00843             rc = errno;
00844          }
00845          if (rc == 0) {
00846             done = 1;
00847          } else if (rc == ENOMEM) {
00848             if (res)
00849                free(res);
00850             res = 0;
00851             rc = 0;
00852          }
00853       }
00854    } while (rc == 0 && !done);
00855 
00856    // Clean up and establish post conditions.
00857    if (rc != 0 && !res) {
00858       free(res);
00859       res = 0;
00860    }
00861    *plist = res;
00862    if (rc == 0)
00863       nproc = len / sizeof(kinfo_proc);
00864 
00865    // Done
00866    return rc;
00867 }
00868 #endif
00869 
00870 //______________________________________________________________________________
00871 int XrdProofdAux::GetProcesses(const char *pn, std::map<int,XrdOucString> *pmap)
00872 {
00873    // Get from the process table list of PIDs for processes named "proofserv'
00874    // For {linux, sun, macosx} it uses the system info; for other systems it
00875    // invokes the command shell 'ps ax' via popen.
00876    // Return the number of processes found, or -1 if some error occured.
00877    XPDLOC(AUX, "Aux::GetProcesses")
00878 
00879    int np = 0;
00880 
00881    // Check input consistency
00882    if (!pn || strlen(pn) <= 0 || !pmap) {
00883       TRACE(XERR, "invalid inputs");
00884       return -1;
00885    }
00886    TRACE(DBG, "process name: "<<pn);
00887 
00888    XrdOucString emsg;
00889 
00890 #if defined(linux) || defined(__sun)
00891    // Loop over the "/proc" dir
00892    DIR *dir = opendir("/proc");
00893    if (!dir) {
00894       emsg = "cannot open /proc - errno: ";
00895       emsg += errno;
00896       TRACE(DBG, emsg.c_str());
00897       return -1;
00898    }
00899 
00900    struct dirent *ent = 0;
00901    while ((ent = readdir(dir))) {
00902       if (DIGIT(ent->d_name[0])) {
00903          XrdOucString fn("/proc/", 256);
00904          fn += ent->d_name;
00905 #if defined(linux)
00906          fn += "/status";
00907          // Open file
00908          FILE *ffn = fopen(fn.c_str(), "r");
00909          if (!ffn) {
00910             emsg = "cannot open file ";
00911             emsg += fn; emsg += " - errno: "; emsg += errno;
00912             TRACE(HDBG, emsg);
00913             continue;
00914          }
00915          // Read info
00916          bool ok = 0;
00917          int pid = -1;
00918          char line[2048] = { 0 };
00919          while (fgets(line, sizeof(line), ffn)) {
00920             // Check name
00921             if (strstr(line, "Name:")) {
00922                if (strstr(line, pn)) {
00923                   // Good one
00924                   ok = 1;
00925                }
00926                // We are done with this proc file
00927                break;
00928             }
00929          }
00930          if (ok) {
00931             fclose(ffn);
00932             fn.replace("/status", "/cmdline");
00933             // Open file
00934             if (!(ffn = fopen(fn.c_str(), "r"))) {
00935                emsg = "cannot open file ";
00936                emsg += fn; emsg += " - errno: "; emsg += errno;
00937                TRACE(HDBG, emsg);
00938                continue;
00939             }
00940             // Read the command line
00941             XrdOucString cmd;
00942             char buf[256];
00943             char *p = &buf[0];
00944             int pos = 0, ltot = 0, nr = 1;
00945             errno = 0;
00946             while (nr > 0) {
00947                while ((nr = read(fileno(ffn), p + pos, 1)) == -1 && errno == EINTR) {
00948                   errno = 0;
00949                }
00950                ltot += nr;
00951                if (ltot == 254) {
00952                   buf[255] = 0;
00953                   cmd += buf;
00954                   pos = 0;
00955                   ltot = 0;
00956                } else if (nr > 0) {
00957                   if (*p == 0) *p = ' ';
00958                   p += nr;
00959                }
00960             }
00961             // Null terminate
00962             buf[ltot] = 0;
00963             cmd += buf;
00964             // Good one: take the pid
00965             pid = strtol(ent->d_name, 0, 10);
00966             pmap->insert(std::make_pair(pid, cmd));
00967             np++;
00968          }
00969          // Close the file
00970          fclose(ffn);
00971 #elif defined(__sun)
00972          fn += "/psinfo";
00973          // Open file
00974          int ffd = open(fn.c_str(), O_RDONLY);
00975          if (ffd <= 0) {
00976             emsg = "cannot open file ";
00977             emsg += fn; emsg += " - errno: "; emsg += errno;
00978             TRACE(HDBG, emsg);
00979             continue;
00980          }
00981          // Get the information
00982          psinfo_t psi;
00983          if (read(ffd, &psi, sizeof(psinfo_t)) != sizeof(psinfo_t)) {
00984             emsg = "cannot read ";
00985             emsg += fn; emsg += ": errno: "; emsg += errno;
00986             TRACE(XERR, emsg);
00987             close(ffd);
00988             continue;
00989          }
00990          // Check name
00991          if (strstr(psi.pr_fname, pn)) {
00992             // Build command line
00993             XrdOucString cmd(psi.pr_fname);
00994             if (cmd.length() > 0) cmd += " ";
00995             cmd += psi.pr_psargs;
00996             // Good one: take the pid
00997             int pid = strtol(ent->d_name, 0, 10);
00998             pmap->insert(std::make_pair(pid, cmd));
00999             np++;
01000          }
01001          // Close the file
01002          close(ffd);
01003 #endif
01004       }
01005    }
01006    // Close the directory
01007    closedir(dir);
01008 
01009 #elif defined(__FreeBSD__) || defined(__OpenBSD__) || defined(__APPLE__)
01010 
01011    // Get the proclist
01012    kinfo_proc *pl = 0;
01013    int ern = 0;
01014    if ((ern = XrdProofdAux::GetMacProcList(&pl, np)) != 0) {
01015       emsg = "cannot get the process list: errno: ";
01016       emsg += ern;
01017       TRACE(XERR, emsg);
01018       return -1;
01019    }
01020 
01021    // Loop over the list
01022    int ii = np;
01023    while (ii--) {
01024       if (strstr(pl[ii].kp_proc.p_comm, pn)) {
01025          // Good one: take the pid
01026          pmap->insert(std::make_pair(pl[ii].kp_proc.p_pid, XrdOucString(pl[ii].kp_proc.p_comm)));
01027          np++;
01028       }
01029    }
01030    // Cleanup
01031    free(pl);
01032 #else
01033 
01034    // For the remaining cases we use 'ps' via popen to localize the processes
01035 
01036    // Build command
01037    XrdOucString cmd = "ps ax -ww | grep proofserv 2>/dev/null";
01038 
01039    // Run it ...
01040    XrdOucString pids = ":";
01041    FILE *fp = popen(cmd.c_str(), "r");
01042    if (fp != 0) {
01043       char line[2048] = { 0 };
01044       while (fgets(line, sizeof(line), fp)) {
01045          int pid = (int) XrdProofdAux::GetLong(&line[from]);
01046          pmap->insert(std::make_pair(pid, XrdOucString(line)));
01047          np++;
01048       }
01049       pclose(fp);
01050    } else {
01051       // Error executing the command
01052       return -1;
01053    }
01054 
01055 #endif
01056 
01057    // Done
01058    return np;
01059 }
01060 
01061 //_____________________________________________________________________________
01062 int XrdProofdAux::GetIDFromPath(const char *path, XrdOucString &emsg)
01063 {
01064    // Extract an integer from a file
01065 
01066    emsg = "";
01067    // Get the ID
01068    int id = -1;
01069    FILE *fid = fopen(path, "r");
01070    if (fid) {
01071       char line[64];
01072       if (fgets(line, sizeof(line), fid))
01073          sscanf(line, "%d", &id);
01074       fclose(fid);
01075    } else if (errno != ENOENT) {
01076       XPDFORM(emsg, "GetIDFromPath: error reading id from: %s (errno: %d)",
01077                 path, errno);
01078    }
01079    // Done
01080    return id;
01081 }
01082 
01083 //______________________________________________________________________________
01084 bool XrdProofdAux::HasToken(const char *s, const char *tokens)
01085 {
01086    // Returns true is 's' contains at least one of the comma-separated tokens
01087    // in 'tokens'. Else returns false.
01088 
01089    if (s && strlen(s) > 0) {
01090       XrdOucString tks(tokens), tok;
01091       int from = 0;
01092       while ((from = tks.tokenize(tok, from, ',')) != -1)
01093          if (strstr(s, tok.c_str())) return 1;
01094    }
01095    return 0;
01096 }
01097 
01098 //______________________________________________________________________________
01099 int XrdProofdAux::VerifyProcessByID(int pid, const char *pname)
01100 {
01101    // Check if a process named 'pname' and process 'pid' is still
01102    // in the process table.
01103    // For {linux, sun, macosx} it uses the system info; for other systems it
01104    // invokes the command shell 'ps ax' via popen.
01105    // Return 1 if running, 0 if not running, -1 if the check could not be run.
01106    XPDLOC(AUX, "Aux::VerifyProcessByID")
01107 
01108    int rc = 0;
01109 
01110    TRACE(DBG, "pid: "<<pid);
01111 
01112    // Check input consistency
01113    if (pid < 0) {
01114       TRACE(XERR, "invalid pid");
01115       return -1;
01116    }
01117 
01118    XrdOucString emsg;
01119 
01120    // Name
01121    const char *pn = (pname && strlen(pname) > 0) ? pname : "proofserv";
01122 
01123 #if defined(linux)
01124    // Look for the relevant /proc dir
01125    XrdOucString fn("/proc/");
01126    fn += pid;
01127    fn += "/stat";
01128    FILE *ffn = fopen(fn.c_str(), "r");
01129    if (!ffn) {
01130       if (errno == ENOENT) {
01131          TRACE(DBG, "process does not exists anymore");
01132          return 0;
01133       } else {
01134          XPDFORM(emsg, "cannot open %s; errno: %d", fn.c_str(), errno);
01135          TRACE(XERR, emsg);
01136          return -1;
01137       }
01138    }
01139    // Read status line
01140    char line[2048] = { 0 };
01141    if (fgets(line, sizeof(line), ffn)) {
01142       if (XrdProofdAux::HasToken(line, pn))
01143          // Still there
01144          rc = 1;
01145    } else {
01146       XPDFORM(emsg, "cannot read %s; errno: %d", fn.c_str(), errno);
01147       TRACE(XERR, emsg);
01148       fclose(ffn);
01149       return -1;
01150    }
01151    // Close the file
01152    fclose(ffn);
01153 
01154 #elif defined(__sun)
01155 
01156    // Look for the relevant /proc dir
01157    XrdOucString fn("/proc/");
01158    fn += pid;
01159    fn += "/psinfo";
01160    int ffd = open(fn.c_str(), O_RDONLY);
01161    if (ffd <= 0) {
01162       if (errno == ENOENT) {
01163          TRACE(DBG, "VerifyProcessByID: process does not exists anymore");
01164          return 0;
01165       } else {
01166          XPDFORM(emsg, "cannot open %s; errno: %d", fn.c_str(), errno);
01167          TRACE(XERR, emsg);
01168          return -1;
01169       }
01170    }
01171    // Get the information
01172    psinfo_t psi;
01173    if (read(ffd, &psi, sizeof(psinfo_t)) != sizeof(psinfo_t)) {
01174       XPDFORM(emsg, "cannot read %s; errno: %d", fn.c_str(), errno);
01175       TRACE(XERR, emsg);
01176       close(ffd);
01177       return -1;
01178    }
01179 
01180    // Verify now
01181    if (XrdProofdAux::HasToken(psi.pr_fname, pn))
01182       // The process is still there
01183       rc = 1;
01184 
01185    // Close the file
01186    close(ffd);
01187 
01188 #elif defined(__FreeBSD__) || defined(__OpenBSD__) || defined(__APPLE__)
01189 
01190    // Get the proclist
01191    kinfo_proc *pl = 0;
01192    int np;
01193    int ern = 0;
01194    if ((ern = XrdProofdAux::GetMacProcList(&pl, np)) != 0) {
01195       XPDFORM(emsg, "cannot get the process list: errno: %d", ern);
01196       TRACE(XERR, emsg);
01197       return -1;
01198    }
01199 
01200    // Loop over the list
01201    while (np--) {
01202       if (pl[np].kp_proc.p_pid == pid &&
01203          XrdProofdAux::HasToken(pl[np].kp_proc.p_comm, pn)) {
01204          // Process still exists
01205          rc = 1;
01206          break;
01207       }
01208    }
01209    // Cleanup
01210    free(pl);
01211 #else
01212    // Use the output of 'ps ax' as a backup solution
01213    XrdOucString cmd = "ps ax | grep proofserv 2>/dev/null";
01214    if (pname && strlen(pname))
01215       cmd.replace("proofserv", pname);
01216    FILE *fp = popen(cmd.c_str(), "r");
01217    if (fp != 0) {
01218       char line[2048] = { 0 };
01219       while (fgets(line, sizeof(line), fp)) {
01220          if (pid == XrdProofdAux::GetLong(line)) {
01221             // Process still running
01222             rc = 1;
01223             break;
01224          }
01225       }
01226       pclose(fp);
01227    } else {
01228       // Error executing the command
01229       return -1;
01230    }
01231 #endif
01232    // Done
01233    return rc;
01234 }
01235 
01236 //______________________________________________________________________________
01237 int XrdProofdAux::KillProcess(int pid, bool forcekill, XrdProofUI ui, bool changeown)
01238 {
01239    // Kill the process 'pid'.
01240    // A SIGTERM is sent, unless 'kill' is TRUE, in which case a SIGKILL is used.
01241    // If add is TRUE (default) the pid is added to the list of processes
01242    // requested to terminate.
01243    // Return 0 on success, -1 if not allowed or other errors occured.
01244    XPDLOC(AUX, "Aux::KillProcess")
01245 
01246    TRACE(DBG, "pid: "<<pid<< ", forcekill: "<< forcekill);
01247 
01248    XrdOucString msg;
01249    if (pid > 0) {
01250       // We need the right privileges to do this
01251       XrdSysPrivGuard pGuard((uid_t)0, (gid_t)0);
01252       if (XpdBadPGuard(pGuard, ui.fUid) && changeown) {
01253          TRACE(XERR, "could not get privileges");
01254          return -1;
01255       } else {
01256          bool signalled = 1;
01257          if (forcekill) {
01258             // Hard shutdown via SIGKILL
01259             if (kill(pid, SIGKILL) != 0) {
01260                if (errno != ESRCH) {
01261                   XPDFORM(msg, "kill(pid,SIGKILL) failed for process %d; errno: %d", pid, errno);
01262                   TRACE(XERR, msg);
01263                   return -1;
01264                }
01265                signalled = 0;
01266             }
01267          } else {
01268             // Softer shutdown via SIGTERM
01269             if (kill(pid, SIGTERM) != 0) {
01270                if (errno != ESRCH) {
01271                   XPDFORM(msg, "kill(pid,SIGTERM) failed for process %d; errno: %d", pid, errno);
01272                   TRACE(XERR, msg);
01273                   return -1;
01274                }
01275                signalled = 0;
01276             }
01277          }
01278          // Notify failure
01279          if (!signalled) {
01280             TRACE(DBG, "process ID "<<pid<<" not found in the process table");
01281          }
01282       }
01283    } else {
01284       return -1;
01285    }
01286 
01287    // Done
01288    return 0;
01289 }
01290 
01291 //______________________________________________________________________________
01292 int XrdProofdAux::RmDir(const char *path)
01293 {
01294    // Remove directory at path and its content.
01295    // Returns 0 on success, -errno of the last error on failure
01296    XPDLOC(AUX, "Aux::RmDir")
01297 
01298    int rc = 0;
01299 
01300    TRACE(DBG, path);
01301 
01302    // Open dir
01303    DIR *dir = opendir(path);
01304    if (!dir) {
01305       TRACE(XERR, "cannot open dir "<<path<<" ; error: "<<errno);
01306       return -errno;
01307    }
01308 
01309    // Scan the directory
01310    XrdOucString entry;
01311    struct stat st;
01312    struct dirent *ent = 0;
01313    while ((ent = (struct dirent *)readdir(dir))) {
01314       // Skip the basic entries
01315       if (!strcmp(ent->d_name, ".") || !strcmp(ent->d_name, "..")) continue;
01316       // Get info about the entry
01317       XPDFORM(entry, "%s/%s", path, ent->d_name);
01318       if (stat(entry.c_str(), &st) != 0) {
01319          TRACE(XERR, "cannot stat entry "<<entry<<" ; error: "<<errno);
01320          rc = -errno;
01321          break;
01322       }
01323       // Remove directories recursively
01324       if (S_ISDIR(st.st_mode)) {
01325          rc = XrdProofdAux::RmDir(entry.c_str());
01326          if (rc != 0) {
01327             TRACE(XERR, "problems removing"<<entry<<" ; error: "<<-rc);
01328             break;
01329          }
01330       } else {
01331          // Remove the entry
01332          if (unlink(entry.c_str()) != 0) {
01333             rc = -errno;
01334             TRACE(XERR, "problems removing"<<entry<<" ; error: "<<-rc);
01335             break;
01336          }
01337       }
01338    }
01339    // Close the directory
01340    closedir(dir);
01341 
01342    // If successful, remove the directory
01343    if (!rc && rmdir(path) != 0) {
01344       rc = -errno;
01345       TRACE(XERR, "problems removing"<<path<<" ; error: "<<-rc);
01346    }
01347 
01348    // Done
01349    return rc;
01350 }
01351 
01352 //______________________________________________________________________________
01353 int XrdProofdAux::MvDir(const char *oldpath, const char *newpath)
01354 {
01355    // Move content of directory at oldpath to newpath.
01356    // The destination path 'newpath' must exist.
01357    // Returns 0 on success, -errno of the last error on failure
01358    XPDLOC(AUX, "Aux::MvDir")
01359 
01360    int rc = 0;
01361 
01362    TRACE(DBG, "oldpath "<<oldpath<<", newpath: "<<newpath);
01363 
01364    // Open existing dir
01365    DIR *dir = opendir(oldpath);
01366    if (!dir) {
01367       TRACE(XERR, "cannot open dir "<<oldpath<<" ; error: "<<errno);
01368       return -errno;
01369    }
01370 
01371    // Assert destination dir
01372    struct stat st;
01373    if (stat(newpath, &st) != 0 || !S_ISDIR(st.st_mode)) {
01374       TRACE(XERR, "destination dir "<<newpath<<
01375                   " does not exist or is not a directory; errno: "<<errno);
01376       return -ENOENT;
01377    }
01378 
01379    // Scan the source directory
01380    XrdOucString srcentry, dstentry;
01381    struct dirent *ent = 0;
01382    while ((ent = (struct dirent *)readdir(dir))) {
01383       // Skip the basic entries
01384       if (!strcmp(ent->d_name, ".") || !strcmp(ent->d_name, "..")) continue;
01385       // Get info about the entry
01386       XPDFORM(srcentry, "%s/%s", oldpath, ent->d_name);
01387       if (stat(srcentry.c_str(), &st) != 0) {
01388          TRACE(XERR, "cannot stat entry "<<srcentry<<" ; error: "<<errno);
01389          rc = -errno;
01390          break;
01391       }
01392       // Destination entry
01393       XPDFORM(dstentry, "%s/%s", newpath, ent->d_name);
01394       // Mv directories recursively
01395       if (S_ISDIR(st.st_mode)) {
01396          mode_t srcmode = st.st_mode;
01397          // Create dest sub-dir
01398          if (stat(dstentry.c_str(), &st) == 0) {
01399             if (!S_ISDIR(st.st_mode)) {
01400                TRACE(XERR, "destination path already exists and is not a directory: "<<dstentry);
01401                rc = -ENOTDIR;
01402                break;
01403             }
01404          } else {
01405             if (mkdir(dstentry.c_str(), srcmode) != 0) {
01406                TRACE(XERR, "cannot create entry "<<dstentry<<" ; error: "<<errno);
01407                rc = -errno;
01408                break;
01409             }
01410          }
01411          if ((rc = XrdProofdAux::MvDir(srcentry.c_str(), dstentry.c_str())) != 0) {
01412             TRACE(XERR, "problems moving "<<srcentry<<" to "<<dstentry<<"; error: "<<-rc);
01413             break;
01414          }
01415          if ((rc = XrdProofdAux::RmDir(srcentry.c_str())) != 0) {
01416             TRACE(XERR, "problems removing "<<srcentry<<"; error: "<<-rc);
01417             break;
01418          }
01419       } else {
01420          // Move the entry
01421          if (rename(srcentry.c_str(), dstentry.c_str()) != 0) {
01422             rc = -errno;
01423             TRACE(XERR, "problems moving "<<srcentry<<" to "<<dstentry<<"; error: "<<-rc);
01424             break;
01425          }
01426       }
01427    }
01428    // Close the directory
01429    closedir(dir);
01430 
01431    // Done
01432    return rc;
01433 }
01434 
01435 //______________________________________________________________________________
01436 int XrdProofdAux::Touch(const char *path, int opt)
01437 {
01438    // Set access (opt == 1), modify (opt =2 ) or access&modify (opt = 0, default)
01439    // times of path to current time.
01440    // Returns 0 on success, -errno on failure
01441 
01442    if (opt == 0) {
01443       if (utime(path, 0) != 0)
01444          return -errno;
01445    } else if (opt <= 2) {
01446       struct stat st;
01447       if (stat(path, &st) != 0)
01448          return -errno;
01449       struct utimbuf ut;
01450       if (opt == 1) {
01451          ut.actime = time(0);
01452          ut.modtime = st.st_mtime;
01453       } else if (opt == 2) {
01454          ut.modtime = time(0);
01455          ut.actime = st.st_atime;
01456       }
01457       if (utime(path, &ut) != 0)
01458          return -errno;
01459    } else {
01460       // Unknown option
01461       return -1;
01462    }
01463    // Done
01464    return 0;
01465 }
01466 
01467 //___________________________________________________________________________
01468 int XrdProofdAux::ReadMsg(int fd, XrdOucString &msg)
01469 {
01470    // Receive 'msg' from pipe fd
01471    XPDLOC(AUX, "Aux::ReadMsg")
01472 
01473    msg = "";
01474    if (fd > 0) {
01475 
01476       // Read message length
01477       int len = 0;
01478       if (read(fd, &len, sizeof(len)) != sizeof(len))
01479          return -errno;
01480       TRACE(HDBG,fd<<": len: "<<len);
01481 
01482       // Read message
01483       char buf[XPD_MAXLEN];
01484       int nr = -1;
01485       do {
01486          int wanted = (len > XPD_MAXLEN-1) ? XPD_MAXLEN-1 : len;
01487          while ((nr = read(fd, buf, wanted)) < 0 &&
01488                errno == EINTR)
01489             errno = 0;
01490          if (nr < wanted) {
01491             break;
01492          } else {
01493             buf[nr] = '\0';
01494             msg += buf;
01495          }
01496          // Update counters
01497          len -= nr;
01498       } while (nr > 0 && len > 0);
01499 
01500       TRACE(HDBG,fd<<": buf: "<<buf);
01501 
01502       // Done
01503       return 0;
01504    }
01505    // Undefined socket
01506    TRACE(XERR, "pipe descriptor undefined: "<<fd);
01507    return -1;
01508 }
01509 
01510 //______________________________________________________________________________
01511 int XrdProofdAux::ParsePidPath(const char *path,
01512                                XrdOucString &before, XrdOucString &after)
01513 {
01514    // Parse a path in the form of "<before>[.<pid>][.<after>]", filling 'rest'
01515    // and returning 'pid'.
01516    // Return 0 if pid is not defined; 'before' is filled with the string preceeding
01517    // <pid>, <after> with the string following <pid>.
01518    XPDLOC(AUX, "ParsePidPath")
01519 
01520    long int pid = -1;
01521    if (path && strlen(path)) {
01522       pid = 0;
01523       int from = 0;
01524       XrdOucString spid, s(path);
01525       bool nopid = 1;
01526       while ((from = s.tokenize(spid, from, '.')) != -1) {
01527          if (spid.length() > 0) {
01528             if (spid.isdigit()) {
01529                // Get pid
01530                pid = (int) spid.atoi();
01531                if (!XPD_LONGOK(pid)) {
01532                   // Substring is not a PID
01533                   pid = 0;
01534                }
01535             }
01536             if (nopid && pid > 0) {
01537                nopid = 0;
01538             } else if (nopid) {
01539                if (before.length() > 0) before += ".";
01540                before += spid;
01541             } else {
01542                if (after.length() > 0) after += ".";
01543                after += spid;
01544             }
01545          }
01546       }
01547       if (pid == 0 && before.length() == 0) {
01548          before = after;
01549          after = "";
01550       }
01551    }
01552 
01553    TRACE(HDBG,"path: "<<path<<" --> before: '"<<before<<"', pid: "<<pid<<", after: '"<<after<<"'");
01554 
01555    // Done
01556    return pid;
01557 }
01558 
01559 //______________________________________________________________________________
01560 int XrdProofdAux::ParseUsrGrp(const char *path, XrdOucString &usr, XrdOucString &grp)
01561 {
01562    // Parse a path in the form of "<usr>[.<grp>][.<pid>]", filling 'usr' and 'grp'.
01563    // Returns -1 on failure, 0 if the pid is not defined or the pid.
01564 
01565    XrdOucString rest, after;
01566    int pid = ParsePidPath(path, rest, after);
01567 
01568    if (pid >= 0 && rest.length() > 0) {
01569       // Fill 'usr' (everything until the last dot)
01570       usr = rest;
01571       int ip = STR_NPOS;
01572       if ((ip = rest.rfind('.')) != STR_NPOS) {
01573          usr.erase(ip);
01574          // Fill 'grp'
01575          grp = rest;
01576          grp.erase(0, ip + 1);
01577       }
01578    }
01579    // Done
01580    return pid;
01581 }
01582 
01583 //
01584 // Functions to process directives for integer and strings
01585 //
01586 
01587 //______________________________________________________________________________
01588 int DoDirectiveClass(XrdProofdDirective *d, char *val, XrdOucStream *cfg, bool rcf)
01589 {
01590    // Generic class directive processor
01591 
01592    if (!d || !(d->fVal))
01593       // undefined inputs
01594       return -1;
01595 
01596    return ((XrdProofdConfig *)d->fVal)->DoDirective(d, val, cfg, rcf);
01597 }
01598 
01599 //______________________________________________________________________________
01600 int DoDirectiveInt(XrdProofdDirective *d, char *val, XrdOucStream *cfg, bool rcf)
01601 {
01602    // Process directive for an integer
01603    XPDLOC(AUX, "DoDirectiveInt")
01604 
01605    if (!d || !(d->fVal) || !val)
01606       // undefined inputs
01607       return -1;
01608 
01609    if (rcf && !d->fRcf)
01610       // Not re-configurable: do nothing
01611       return 0;
01612 
01613    // Check deprecated 'if' directive
01614    if (d->fHost && cfg)
01615       if (XrdProofdAux::CheckIf(cfg, d->fHost) == 0)
01616          return 0;
01617 
01618    long int v = strtol(val,0,10);
01619    *((int *)d->fVal) = v;
01620 
01621    TRACE(DBG, "set "<<d->fName<<" to "<<*((int *)d->fVal));
01622 
01623    return 0;
01624 }
01625 
01626 //______________________________________________________________________________
01627 int DoDirectiveString(XrdProofdDirective *d, char *val, XrdOucStream *cfg, bool rcf)
01628 {
01629    // Process directive for a string
01630    XPDLOC(AUX, "DoDirectiveString")
01631 
01632    if (!d || !(d->fVal) || !val)
01633       // undefined inputs
01634       return -1;
01635 
01636    if (rcf && !d->fRcf)
01637       // Not re-configurable: do nothing
01638       return 0;
01639 
01640    // Check deprecated 'if' directive
01641    if (d->fHost && cfg)
01642       if (XrdProofdAux::CheckIf(cfg, d->fHost) == 0)
01643          return 0;
01644 
01645    *((XrdOucString *)d->fVal) = val;
01646 
01647    TRACE(DBG, "set "<<d->fName<<" to "<<*((XrdOucString *)d->fVal));
01648    return 0;
01649 }
01650 
01651 //__________________________________________________________________________
01652 int SetHostInDirectives(const char *, XrdProofdDirective *d, void *h)
01653 {
01654    // Set host field for directive 'd' to (const char *h)
01655 
01656    const char *host = (const char *)h;
01657 
01658    if (!d || !host || strlen(host) <= 0)
01659       // Dataset root dir undefined: we cannot continue
01660       return 1;
01661 
01662    d->fHost = host;
01663 
01664    // Process next
01665    return 0;
01666 }
01667 
01668 //
01669 // XrdProofdPipe: class implementing pipe functionality
01670 //
01671 //__________________________________________________________________________
01672 XrdProofdPipe::XrdProofdPipe()
01673 {
01674    // Constructor: create the pipe
01675 
01676    // Init pipe for the poller
01677    if (pipe(fPipe) != 0) {
01678       fPipe[0] = -1;
01679       fPipe[1] = -1;
01680    }
01681 }
01682 
01683 //__________________________________________________________________________
01684 XrdProofdPipe::~XrdProofdPipe()
01685 {
01686    // Destructor
01687 
01688    // Close the pipe
01689    Close();
01690 }
01691 
01692 //__________________________________________________________________________
01693 void XrdProofdPipe::Close()
01694 {
01695    // If open, close and invalidated the pipe descriptors
01696 
01697    if (IsValid()) {
01698       close(fPipe[0]);
01699       close(fPipe[1]);
01700       fPipe[0] = -1;
01701       fPipe[1] = -1;
01702    }
01703 }
01704 
01705 //__________________________________________________________________________
01706 int XrdProofdPipe::Post(int type, const char *msg)
01707 {
01708    // Post message on the pipe 
01709    XPDLOC(AUX, "Pipe::Post")
01710 
01711 
01712    if (IsValid()) {
01713       XrdOucString buf;
01714       if (msg && strlen(msg) > 0) {
01715          XPDFORM(buf, "%d %s", type, msg);
01716       } else {
01717          buf += type;
01718       }
01719       TRACE(HDBG, fPipe[1] << ": posting: type: "<<type<<", buf: "<<buf);
01720       int len = buf.length() + 1;
01721       XrdSysMutexHelper mh(fWrMtx);
01722       if (write(fPipe[1], &len, sizeof(len)) !=  sizeof(len))
01723          return -errno;
01724       if (write(fPipe[1], buf.c_str(), len) !=  len)
01725          return -errno;
01726       // Done
01727       return 0;
01728    }
01729    // Invalid pipe
01730    TRACE(XERR, "pipe is invalid");
01731    return -1;
01732 }
01733 
01734 //__________________________________________________________________________
01735 int XrdProofdPipe::Recv(XpdMsg &msg)
01736 {
01737    // Recv message from the pipe 
01738    XPDLOC(AUX, "Pipe::Recv")
01739 
01740    if (IsValid()) {
01741       XrdOucString buf;
01742       {  XrdSysMutexHelper mh(fRdMtx);
01743          if (XrdProofdAux::ReadMsg(fPipe[0], buf) != 0)
01744             return -1;
01745       }
01746       TRACE(HDBG, fPipe[0] << ": receiving: msg: "<< buf);
01747       msg.Init(buf.c_str());
01748       // Done
01749       return 0;
01750    }
01751    // Invalid pipe
01752    TRACE(XERR, "pipe is invalid");
01753    return -1;
01754 }
01755 
01756 //__________________________________________________________________________
01757 int XrdProofdPipe::Poll(int to)
01758 {
01759    // Poll over the read pipe for to secs; return whatever poll returns
01760    XPDLOC(AUX, "Pipe::Poll")
01761 
01762    if (IsValid()) {
01763 
01764       // Read descriptor
01765       struct pollfd fds_r;
01766       fds_r.fd = fPipe[0];
01767       fds_r.events = POLLIN;
01768 
01769       // We wait for processes to communicate a session status change
01770       int pollrc = 0;
01771       int xto = (to > 0) ? to * 1000 : -1;
01772       while ((pollrc = poll(&fds_r, 1, xto)) < 0 && (errno == EINTR)) {
01773          errno = 0;
01774       }
01775       // Done
01776       return (pollrc >= 0) ? pollrc : -errno;
01777    }
01778    // Invalid pipe
01779    TRACE(XERR, "pipe is invalid");
01780    return -1;
01781 }
01782 
01783 //
01784 // XpdMsg: class to handle messages received over the pipe
01785 //
01786 //__________________________________________________________________________
01787 int XpdMsg::Init(const char *buf)
01788 {
01789    // Init from buffer
01790    XPDLOC(AUX, "Msg::Init")
01791 
01792    fType = -1;
01793    fBuf = "";
01794    fFrom = -1;
01795 
01796    TRACE(HDBG, "buf: "<< (const char *)(buf ? buf : "+++ empty +++"));
01797 
01798    if (buf && strlen(buf) > 0) {
01799       fBuf = buf;
01800       fFrom = 0;
01801       // Extract the type
01802       XrdOucString ctyp;
01803       if ((fFrom = fBuf.tokenize(ctyp, fFrom, ' ')) == -1 || ctyp.length() <= 0) {
01804          TRACE(XERR, "ctyp: "<<ctyp<<" fFrom: "<<fFrom);
01805          fBuf = "";
01806          fFrom = -1;
01807          return -1;
01808       }
01809       fType = ctyp.atoi();
01810       if (!XPD_LONGOK(fType)) {
01811          TRACE(XERR, "ctyp: "<<ctyp<<" fType: "<<fType);
01812          fBuf = "";
01813          fFrom = -1;
01814          return -1;
01815       }
01816       fBuf.erase(0,fFrom);
01817       while (fBuf.beginswith(' '))
01818          fBuf.erase(0, 1);
01819       fFrom = 0;
01820       TRACE(HDBG, fType<<", "<<fBuf);
01821    }
01822    // Done
01823    return 0;
01824 }
01825 
01826 //__________________________________________________________________________
01827 int XpdMsg::Get(int &i)
01828 {
01829    // Get next token and interpret it as an int
01830    XPDLOC(AUX, "Msg::Get")
01831 
01832    TRACE(HDBG,"int &i: "<<fFrom<<" "<<fBuf);
01833 
01834    int iold = i;
01835    XrdOucString tkn;
01836    if ((fFrom = fBuf.tokenize(tkn, fFrom, ' ')) == -1 || tkn.length() <= 0)
01837       return -1;
01838    i = tkn.atoi();
01839    if (!XPD_LONGOK(i)) {
01840       TRACE(XERR, "tkn: "<<tkn<<" i: "<<i);
01841       i = iold;
01842       return -1;
01843    }
01844    // Done
01845    return 0;
01846 }
01847 
01848 //__________________________________________________________________________
01849 int XpdMsg::Get(XrdOucString &s)
01850 {
01851    // Get next token
01852    XPDLOC(AUX, "Msg::Get")
01853 
01854    TRACE(HDBG,"XrdOucString &s: "<<fFrom<<" "<<fBuf);
01855 
01856    if ((fFrom = fBuf.tokenize(s, fFrom, ' ')) == -1 || s.length() <= 0) {
01857       TRACE(XERR, "s: "<<s<<" fFrom: "<<fFrom);
01858       return -1;
01859    }
01860 
01861    // Done
01862    return 0;
01863 }
01864 
01865 //__________________________________________________________________________
01866 int XpdMsg::Get(void **p)
01867 {
01868    // Get next token and interpret it as a pointer
01869    XPDLOC(AUX, "Msg::Get")
01870 
01871    TRACE(HDBG,"void **p: "<<fFrom<<" "<<fBuf);
01872 
01873    XrdOucString tkn;
01874    if ((fFrom = fBuf.tokenize(tkn, fFrom, ' ')) == -1 || tkn.length() <= 0) {
01875       TRACE(XERR, "tkn: "<<tkn<<" fFrom: "<<fFrom);
01876       return -1;
01877    }
01878    sscanf(tkn.c_str(), "%p", p);
01879 
01880    // Done
01881    return 0;
01882 }
01883 
01884 
01885 //
01886 // Class to handle condensed multi-string specification, e.g <head>[01-25]<tail>
01887 //
01888 
01889 //__________________________________________________________________________
01890 void XrdProofdMultiStr::Init(const char *s)
01891 {
01892    // Init the multi-string handler.
01893    // Supported formats:
01894    //    <head>[1-4]<tail>   for  <head>1<tail>, ..., <head>4<tail> (4 items)
01895    //    <head>[a,b]<tail>   for  <head>a<tail>, <head>b<tail> (2 items)
01896    //    <head>[a,1-3]<tail> for  <head>a<tail>, <head>1<tail>, <head>2<tail>,
01897    //                             <head>3<tail> (4 items)
01898    //    <head>[01-15]<tail> for  <head>01<tail>, ..., <head>15<tail> (15 items)
01899    //
01900    // A dashed is possible only between numerically treatable values, i.e.
01901    // single letters ([a-Z] will take all tokens between 'a' and 'Z') or n-field
01902    // numbers ([001-999] will take all numbers 1 to 999 always using 3 spaces).
01903    // Mixed values (e.g. [a-034]) are not allowed.
01904 
01905    fN = 0;
01906    if (s && strlen(s)) {
01907       XrdOucString kernel(s);
01908       // Find begin of kernel
01909       int ib = kernel.find('[');
01910       if (ib == STR_NPOS) return;
01911       // Find end of kernel
01912       int ie = kernel.find(']', ib + 1);
01913       if (ie == STR_NPOS) return;
01914       // Check kernel length (it must not be empty)
01915       if (ie == ib + 1) return;
01916       // Fill head and tail
01917       fHead.assign(kernel, 0, ib -1);
01918       fTail.assign(kernel, ie + 1);
01919       // The rest is the kernel
01920       XrdOucString tkns(kernel, ib + 1, ie - 1);
01921       // Tokenize the kernel filling the list
01922       int from = 0;
01923       XrdOucString tkn;
01924       while ((from = tkns.tokenize(tkn, from, ',')) != -1) {
01925          if (tkn.length() > 0) {
01926             XrdProofdMultiStrToken t(tkn.c_str());
01927             if (t.IsValid()) {
01928                fN += t.N();
01929                fTokens.push_back(t);
01930             }
01931          }
01932       }
01933       // Reset everything if nothing found
01934       if (!IsValid()) {
01935          fHead = "";
01936          fTail = "";
01937       }
01938    }
01939 }
01940 
01941 //__________________________________________________________________________
01942 bool XrdProofdMultiStr::Matches(const char *s)
01943 {
01944    // Return true if 's' is compatible with this multi-string 
01945 
01946    if (s && strlen(s)) {
01947       XrdOucString str(s);
01948       if (fHead.length() <= 0 || str.beginswith(fHead)) {
01949          if (fTail.length() <= 0 || str.endswith(fTail)) {
01950             str.replace(fHead,"");
01951             str.replace(fTail,"");
01952             std::list<XrdProofdMultiStrToken>::iterator it = fTokens.begin();
01953             for (; it != fTokens.end(); it++) {
01954                if ((*it).Matches(str.c_str()))
01955                   return 1;
01956             }
01957          }
01958       }
01959    }
01960    // Done
01961    return 0;
01962 }
01963 
01964 //__________________________________________________________________________
01965 XrdOucString XrdProofdMultiStr::Export()
01966 {
01967    // Return a string with comma-separated elements
01968 
01969    XrdOucString str(fN * (fHead.length() + fTail.length() + 4)) ;
01970    str = "";
01971    if (fN > 0) {
01972       std::list<XrdProofdMultiStrToken>::iterator it = fTokens.begin();
01973       for (; it != fTokens.end(); it++) {
01974          int n = (*it).N(), j = -1;
01975          while (n--) {
01976             str += fHead;
01977             str += (*it).Export(j);
01978             str += fTail;
01979             str += ",";
01980          }
01981       }
01982    }
01983    // Remove last ','
01984    if (str.endswith(','))
01985       str.erase(str.rfind(','));
01986    // Done
01987    return str;
01988 }
01989 
01990 //__________________________________________________________________________
01991 XrdOucString XrdProofdMultiStr::Get(int i)
01992 {
01993    // Return i-th combination (i : 0 -> fN-1)
01994 
01995    XrdOucString str;
01996 
01997    if (i >= 0) {
01998       std::list<XrdProofdMultiStrToken>::iterator it = fTokens.begin();
01999       for (; it != fTokens.end(); it++) {
02000          int n = (*it).N(), j = -1;
02001          if ((i + 1) > n) {
02002             i -= n;
02003          } else {
02004             j = i;
02005             str = fHead;
02006             str += (*it).Export(j);
02007             str += fTail;
02008             break;
02009          }
02010       }
02011    }
02012 
02013    // Done
02014    return str;
02015 }
02016 
02017 //__________________________________________________________________________
02018 void XrdProofdMultiStrToken::Init(const char *s)
02019 {
02020    // Init the multi-string token.
02021    // Supported formats:
02022    //    [1-4]   for  1, ..., 4 (4 items)
02023    //    [a,b]   for  a, b<tail> (2 items)
02024    //    [a,1-3] for  a, 1, 2, 3 (4 items)
02025    //    [01-15] for  01, ..., 15 (15 items)
02026    //
02027    // A dashed is possible only between numerically treatable values, i.e.
02028    // single letters ([a-Z] will take all tokens between 'a' and 'Z') or n-field
02029    // numbers ([001-999] will take all numbers 1 to 999 always using 3 spaces).
02030    // Mixed values (e.g. [a-034]) are not allowed.
02031    XPDLOC(AUX, "MultiStrToken::Init")
02032 
02033    fIa = LONG_MAX;
02034    fIb = LONG_MAX;
02035    fType = kUndef;
02036    fN = 0;
02037    bool bad = 0;
02038    XrdOucString emsg;
02039    if (s && strlen(s)) {
02040       fA = s;
02041       // Find the dash, if any
02042       int id = fA.find('-');
02043       if (id == STR_NPOS) {
02044          // Simple token, nothing much to do
02045          fN = 1;
02046          fType = kSimple;
02047          return;
02048       }
02049       // Define the extremes
02050       fB.assign(fA, id + 1);
02051       fA.erase(id);
02052       if (fB.length() <= 0) {
02053          if (fA.length() > 0) {
02054             // Simple token, nothing much to do
02055             fN = 1;
02056             fType = kSimple;
02057          }
02058          // Invalid
02059          return;
02060       }
02061       // Check validity
02062       char *a = (char *)fA.c_str();
02063       char *b = (char *)fB.c_str();
02064       if (fA.length() == 1 && fB.length() == 1) {
02065          LETTOIDX(*a, fIa);
02066          if (fIa != LONG_MAX) {
02067             LETTOIDX(*b, fIb);
02068             if (fIb != LONG_MAX && fIa <= fIb) {
02069                // Ordered single-letter extremes: OK
02070                fType = kLetter;
02071                fN = fIb - fIa + 1;
02072                return;
02073             }
02074          } else if (DIGIT(*a) && DIGIT(*b) &&
02075                    (fIa = *a) <= (fIb = *b)) {
02076             // Ordered single-digit extremes: OK
02077             fType = kDigit;
02078             fN = fIb - fIa + 1;
02079             return;
02080          }
02081          // Not-supported single-field extremes
02082          emsg = "not-supported single-field extremes";
02083          bad = 1;
02084       }
02085       if (!bad) {
02086          fIa = fA.atoi();
02087          if (fIa != LONG_MAX && fIa != LONG_MIN) {
02088             fIb = fB.atoi();
02089             if (fIb != LONG_MAX && fIb != LONG_MIN && fIb >= fIa) {
02090                fType = kDigits;
02091                fN = fIb - fIa + 1;
02092                return;
02093             }
02094             // Not-supported single-field extremes
02095             emsg = "non-digit or wrong-ordered extremes";
02096             bad = 1;
02097          } else {
02098             // Not-supported single-field extremes
02099             emsg = "non-digit extremes";
02100             bad = 1;
02101          }
02102       }
02103    }
02104    // Print error message, if any
02105    if (bad) {
02106       TRACE(XERR, emsg);
02107       fA = "";
02108       fB = "";
02109       fIa = LONG_MAX;
02110       fIb = LONG_MAX;
02111    }
02112    // Done
02113    return;
02114 }
02115 
02116 //__________________________________________________________________________
02117 bool XrdProofdMultiStrToken::Matches(const char *s)
02118 {
02119    // Return true if 's' is compatible with this token
02120 
02121    if (s && strlen(s)) {
02122       if (fType == kSimple)
02123          return ((fA == s) ? 1 : 0);
02124       // Multiple one: parse it
02125       XrdOucString str(s);
02126       long ls = LONG_MIN;
02127       if (fType != kDigits) {
02128          if (str.length() > 1)
02129             return 0;
02130          char *ps = (char *)s;
02131          if (fType == kDigit) {
02132             if (!DIGIT(*ps) || *ps < fIa || *ps > fIb)
02133                return 0;
02134          } else if (fType == kLetter) {
02135             LETTOIDX(*ps, ls);
02136             if (ls == LONG_MAX || ls < fIa || ls > fIb)
02137                return 0;
02138          }
02139       } else {
02140          ls = str.atoi();
02141          if (ls == LONG_MAX || ls < fIa || ls > fIb)
02142             return 0;
02143       }
02144       // OK
02145       return 1;
02146    }
02147    // Undefined
02148    return 0;
02149 }
02150 
02151 //__________________________________________________________________________
02152 XrdOucString XrdProofdMultiStrToken::Export(int &next)
02153 {
02154    // Export 'next' token; use next < 0 start from the first
02155 
02156    XrdOucString tkn(fA.length());
02157 
02158    // If simple, return the one we have
02159    if (fType == kSimple)
02160       return (tkn = fA);
02161 
02162    // Check if we still have something
02163    if (next > fIb - fIa)
02164       return tkn;
02165 
02166    // Check where we are
02167    if (next == -1)
02168       next = 0;
02169 
02170    // If letters we need to found the right letter
02171    if (fType == kLetter) {
02172       char c = 0;
02173       IDXTOLET(fIa + next, c);
02174       next++;
02175       return (tkn = c);
02176    }
02177 
02178    // If single digit, add the offset
02179    if (fType == kDigit) {
02180       tkn = (char)(fIa + next);
02181       next++;
02182       return tkn;
02183    }
02184 
02185    // If digits, check if we need to pad 0's
02186    XrdOucString tmp(fA.length());
02187    tmp.form("%ld", fIa + next);
02188    next++;
02189    int dl = fA.length() - tmp.length();
02190    if (dl <= 0) return tmp;
02191    // Add padding 0's
02192    tkn = "";
02193    while (dl--) tkn += "0";
02194    tkn += tmp;
02195    return tkn;
02196 }
02197 
02198 //______________________________________________________________________________
02199 void XrdProofdAux::Form(XrdOucString &s, const char *fmt,
02200                                          int ns, const char *ss[5],
02201                                          int ni, int ii[5],
02202                                          int np, void *pp[5])
02203 {
02204    // Recreate the string according to 'fmt', the up to 5 'const char *' and the
02205    // up to 5 'int' arguments.
02206 
02207    int len = 0;
02208    if (!fmt || (len = strlen(fmt)) <= 0) return;
02209 
02210    char si[32], sp[32];
02211 
02212    // Estimate length
02213    int i = ns;
02214    while (i-- > 0) { if (ss[i]) { len += strlen(ss[i]); } }
02215    i = ni + np;
02216    while (i-- > 0) { len += 32; }
02217 
02218    s.resize(len+1);
02219 
02220    int from = 0;
02221    s.assign(fmt, from);
02222    int nii = 0, nss = 0, npp = 0;
02223    int k = STR_NPOS;
02224    while ((k = s.find('%', from)) != STR_NPOS) {
02225       bool replaced = 0;
02226       if (s[k+1] == 's') {
02227          if (nss < ns) {
02228             s.replace("%s", ss[nss++], k, k + 1);
02229             replaced = 1;
02230          }
02231       } else if (s[k+1] == 'd') {
02232          if (nii < ni) {
02233             sprintf(si,"%d", ii[nii++]);
02234             s.replace("%d", si, k, k + 1);
02235             replaced = 1;
02236          }
02237       } else if (s[k+1] == 'p') {
02238          if (npp < np) {
02239             sprintf(sp,"%p", pp[npp++]);
02240             s.replace("%p", sp, k, k + 1);
02241             replaced = 1;
02242          }
02243       }
02244       if (!replaced) from = k + 1;
02245    }
02246 }
02247 
02248 //______________________________________________________________________________
02249 void XrdProofdAux::Form(XrdOucString &s, const char *fmt,
02250                         const char *s0, const char *s1,
02251                         const char *s2, const char *s3, const char *s4)
02252 {
02253    // Recreate the string according to 'fmt' and the 5 'const char *' arguments
02254 
02255    const char *ss[5] = {s0, s1, s2, s3, s4};
02256    int ii[5] = {0,0,0,0,0};
02257    void *pp[5] = {0,0,0,0,0};
02258 
02259    XrdProofdAux::Form(s,fmt,5,ss,0,ii,0,pp);
02260 }
02261 
02262 //______________________________________________________________________________
02263 void XrdProofdAux::Form(XrdOucString &s, const char *fmt,
02264                                          int i0, int i1, int i2, int i3, int i4)
02265 {
02266    // Recreate the string according to 'fmt' and the 5 'int' arguments
02267 
02268    const char *ss[5] = {0, 0, 0, 0, 0};
02269    int ii[5] = {i0,i1,i2,i3,i4};
02270    void *pp[5] = {0,0,0,0,0};
02271 
02272    XrdProofdAux::Form(s,fmt,0,ss,5,ii,5,pp);
02273 }
02274 
02275 //______________________________________________________________________________
02276 void XrdProofdAux::Form(XrdOucString &s, const char *fmt,
02277                                          void *p0, void *p1, void *p2, void *p3, void *p4)
02278 {
02279    // Recreate the string according to 'fmt' and the 5 'void *' arguments
02280 
02281    const char *ss[5] = {0, 0, 0, 0, 0};
02282    int ii[5] = {0,0,0,0,0};
02283    void *pp[5] = {p0,p1,p2,p3,p4};
02284 
02285    XrdProofdAux::Form(s,fmt,0,ss,0,ii,5,pp);
02286 }
02287 
02288 
02289 //______________________________________________________________________________
02290 void XrdProofdAux::Form(XrdOucString &s, const char *fmt, int i0, const char *s0,
02291                                      const char *s1, const char *s2, const char *s3)
02292 {
02293    // Recreate the string according to 'fmt' and the 5 'void *' arguments
02294 
02295    const char *ss[5] = {s0, s1, s2, s3, 0};
02296    int ii[5] = {i0,0,0,0,0};
02297    void *pp[5] = {0,0,0,0,0};
02298 
02299    XrdProofdAux::Form(s,fmt,4,ss,1,ii,0,pp);
02300 }
02301 
02302 //______________________________________________________________________________
02303 void XrdProofdAux::Form(XrdOucString &s, const char *fmt, const char *s0,
02304                                      int i0, int i1, int i2, int i3)
02305 {
02306    // Recreate the string according to 'fmt' and the 5 'void *' arguments
02307 
02308    const char *ss[5] = {s0,0,0,0,0};
02309    int ii[5] = {i0,i1,i2,i3,0};
02310    void *pp[5] = {0,0,0,0,0};
02311 
02312    XrdProofdAux::Form(s,fmt,1,ss,4,ii,0,pp);
02313 }
02314 
02315 //______________________________________________________________________________
02316 void XrdProofdAux::Form(XrdOucString &s, const char *fmt, const char *s0, const char *s1,
02317                                      int i0, int i1, int i2)
02318 {
02319    // Recreate the string according to 'fmt' and the 5 'void *' arguments
02320 
02321    const char *ss[5] = {s0,s1,0,0,0};
02322    int ii[5] = {i0,i1,i2,0,0};
02323    void *pp[5] = {0,0,0,0,0};
02324 
02325    XrdProofdAux::Form(s,fmt,2,ss,3,ii,0,pp);
02326 }
02327 
02328 //______________________________________________________________________________
02329 void XrdProofdAux::Form(XrdOucString &s, const char *fmt, int i0, int i1,
02330                                      const char *s0, const char *s1, const char *s2)
02331 {
02332    // Recreate the string according to 'fmt' and the 5 'void *' arguments
02333 
02334    const char *ss[5] = {s0,s1,s2,0,0};
02335    int ii[5] = {i0,i1,0,0,0};
02336    void *pp[5] = {0,0,0,0,0};
02337 
02338    XrdProofdAux::Form(s,fmt,3,ss,2,ii,0,pp);
02339 }
02340 
02341 
02342 //______________________________________________________________________________
02343 void XrdProofdAux::Form(XrdOucString &s, const char *fmt, const char *s0,
02344                                          const char *s1, const char *s2,
02345                                          int i0, int i1)
02346 {
02347    // Recreate the string according to 'fmt' and the 5 'void *' arguments
02348 
02349    const char *ss[5] = {s0,s1,s2,0,0};
02350    int ii[5] = {i0,i1,0,0,0};
02351    void *pp[5] = {0,0,0,0,0};
02352 
02353    XrdProofdAux::Form(s,fmt,3,ss,2,ii,0,pp);
02354 }
02355 
02356 //______________________________________________________________________________
02357 void XrdProofdAux::Form(XrdOucString &s, const char *fmt, int i0, int i1, int i2,
02358                                          const char *s0, const char *s1)
02359 {
02360    // Recreate the string according to 'fmt' and the 5 'void *' arguments
02361 
02362    const char *ss[5] = {s0,s1,0,0,0};
02363    int ii[5] = {i0,i1,i2,0,0};
02364    void *pp[5] = {0,0,0,0,0};
02365 
02366    XrdProofdAux::Form(s,fmt,2,ss,3,ii,0,pp);
02367 }
02368 
02369 
02370 //______________________________________________________________________________
02371 void XrdProofdAux::Form(XrdOucString &s, const char *fmt, const char *s0,
02372                           const char *s1, const char *s2, const char *s3, int i0)
02373 {
02374    // Recreate the string according to 'fmt' and the 5 'void *' arguments
02375 
02376    const char *ss[5] = {s0,s1,s2,s3,0};
02377    int ii[5] = {i0,0,0,0,0};
02378    void *pp[5] = {0,0,0,0,0};
02379 
02380    XrdProofdAux::Form(s,fmt,4,ss,1,ii,0,pp);
02381 }
02382 
02383 //______________________________________________________________________________
02384 void XrdProofdAux::Form(XrdOucString &s, const char *fmt, int i0, int i1, int i2,
02385                                          int i3, const char *s0)
02386 {
02387    // Recreate the string according to 'fmt' and the 5 'void *' arguments
02388 
02389    const char *ss[5] = {s0,0,0,0,0};
02390    int ii[5] = {i0,i1,i2,i3,0};
02391    void *pp[5] = {0,0,0,0,0};
02392 
02393    XrdProofdAux::Form(s,fmt,1,ss,4,ii,0,pp);
02394 }
02395 
02396 //______________________________________________________________________________
02397 void XrdProofdAux::Form(XrdOucString &s, const char *fmt, int i0, int i1, void *p0)
02398 {
02399    // Recreate the string according to 'fmt' and the 5 'void *' arguments
02400 
02401    const char *ss[5] = {0,0,0,0,0};
02402    int ii[5] = {i0,i1,0,0,0};
02403    void *pp[5] = {p0,0,0,0,0};
02404 
02405    XrdProofdAux::Form(s,fmt,0,ss,2,ii,1,pp);
02406 }
02407 
02408 //______________________________________________________________________________
02409 void XrdProofdAux::Form(XrdOucString &s, const char *fmt,
02410                                          int i0, int i1, int i2, void *p0)
02411 {
02412    // Recreate the string according to 'fmt' and the 5 'void *' arguments
02413 
02414    const char *ss[5] = {0,0,0,0,0};
02415    int ii[5] = {i0,i1,i2,0,0};
02416    void *pp[5] = {p0,0,0,0,0};
02417 
02418    XrdProofdAux::Form(s,fmt,0,ss,3,ii,1,pp);
02419 }
02420 
02421 //______________________________________________________________________________
02422 void XrdProofdAux::Form(XrdOucString &s, const char *fmt,
02423                                          int i0, int i1, int i2, int i3, void *p0)
02424 {
02425    // Recreate the string according to 'fmt' and the 5 'void *' arguments
02426 
02427    const char *ss[5] = {0,0,0,0,0};
02428    int ii[5] = {i0,i1,i2,i3,0};
02429    void *pp[5] = {p0,0,0,0,0};
02430 
02431    XrdProofdAux::Form(s,fmt,0,ss,4,ii,1,pp);
02432 }
02433 
02434 //______________________________________________________________________________
02435 void XrdProofdAux::Form(XrdOucString &s, const char *fmt, int i0, int i1,
02436                                                           void *p0, int i2, int i3)
02437 {
02438    // Recreate the string according to 'fmt' and the 5 'void *' arguments
02439 
02440    const char *ss[5] = {0,0,0,0,0};
02441    int ii[5] = {i0,i1,i2,i3,0};
02442    void *pp[5] = {p0,0,0,0,0};
02443 
02444    XrdProofdAux::Form(s,fmt,0,ss,4,ii,1,pp);
02445 }
02446 
02447 //______________________________________________________________________________
02448 void XrdProofdAux::Form(XrdOucString &s, const char *fmt, void *p0, int i0, int i1)
02449 {
02450    // Recreate the string according to 'fmt' and the 5 'void *' arguments
02451 
02452    const char *ss[5] = {0,0,0,0,0};
02453    int ii[5] = {i0,i1,0,0,0};
02454    void *pp[5] = {p0,0,0,0,0};
02455 
02456    XrdProofdAux::Form(s,fmt,0,ss,2,ii,1,pp);
02457 }
02458 
02459 //______________________________________________________________________________
02460 void XrdProofdAux::Form(XrdOucString &s, const char *fmt,
02461                                          const char *s0, void *p0, int i0, int i1)
02462 {
02463    // Recreate the string according to 'fmt' and the 5 'void *' arguments
02464 
02465    const char *ss[5] = {s0,0,0,0,0};
02466    int ii[5] = {i0,i1,0,0,0};
02467    void *pp[5] = {p0,0,0,0,0};
02468 
02469    XrdProofdAux::Form(s,fmt,1,ss,2,ii,1,pp);
02470 }
02471 
02472 //______________________________________________________________________________
02473 void XrdProofdAux::Form(XrdOucString &s, const char *fmt,
02474                                          void *p0, const char *s0, int i0)
02475 {
02476    // Recreate the string according to 'fmt' and the 5 'void *' arguments
02477 
02478    const char *ss[5] = {s0,0,0,0,0};
02479    int ii[5] = {i0,0,0,0,0};
02480    void *pp[5] = {p0,0,0,0,0};
02481 
02482    XrdProofdAux::Form(s,fmt,1,ss,1,ii,1,pp);
02483 }
02484 
02485 //______________________________________________________________________________
02486 void XrdProofdAux::Form(XrdOucString &s, const char *fmt,
02487                                          const char *s0, const char *s1, void *p0)
02488 {
02489    // Recreate the string according to 'fmt' and the 5 'void *' arguments
02490 
02491    const char *ss[5] = {s0,s1,0,0,0};
02492    int ii[5] = {0,0,0,0,0};
02493    void *pp[5] = {p0,0,0,0,0};
02494 
02495    XrdProofdAux::Form(s,fmt,2,ss,0,ii,1,pp);
02496 }
02497 
02498 //______________________________________________________________________________
02499 void XrdProofdAux::Form(XrdOucString &s, const char *fmt, int i0,
02500                                          const char *s0, const char *s1, int i1, int i2)
02501 {
02502    // Recreate the string according to 'fmt' and the 5 'void *' arguments
02503 
02504    const char *ss[5] = {s0,s1,0,0,0};
02505    int ii[5] = {i0,i1,i2,0,0};
02506    void *pp[5] = {0,0,0,0,0};
02507 
02508    XrdProofdAux::Form(s,fmt,2,ss,3,ii,0,pp);
02509 }
02510 
02511 //______________________________________________________________________________
02512 void XrdProofdAux::Form(XrdOucString &s, const char *fmt, int i0,
02513                                          const char *s0, int i1, int i2)
02514 {
02515    // Recreate the string according to 'fmt' and the 5 'void *' arguments
02516 
02517    const char *ss[5] = {s0,0,0,0,0};
02518    int ii[5] = {i0,i1,i2,0,0};
02519    void *pp[5] = {0,0,0,0,0};
02520 
02521    XrdProofdAux::Form(s,fmt,1,ss,3,ii,0,pp);
02522 }
02523 

Generated on Tue Jul 5 14:51:51 2011 for ROOT_528-00b_version by  doxygen 1.5.1