rootd.cxx

Go to the documentation of this file.
00001 // @(#)root/rootd:$Id: rootd.cxx 36177 2010-10-08 09:22:57Z ganis $
00002 // Author: Fons Rademakers   11/08/97
00003 
00004 /*************************************************************************
00005  * Copyright (C) 1995-2000, 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 // Rootd                                                                //
00015 //                                                                      //
00016 // Root remote file server daemon.                                      //
00017 // This small server is started either by inetd when a client requests  //
00018 // a connection to a rootd server or by hand (i.e. from the command     //
00019 // line). The rootd server works with the ROOT TNetFile class. It       //
00020 // allows remote access to ROOT database files in either read or        //
00021 // write mode. By default TNetFile uses port 1094 (allocated by IANA,   //
00022 // www.iana.org, to rootd). To run rootd via inetd add the              //
00023 // following line to /etc/services:                                     //
00024 //                                                                      //
00025 // rootd     1094/tcp                                                   //
00026 //                                                                      //
00027 // and to /etc/inetd.conf:                                              //
00028 //                                                                      //
00029 // rootd stream tcp nowait root /usr/local/root/bin/rootd rootd -i      //
00030 //                                                                      //
00031 // Force inetd to reread its conf file with "kill -HUP <pid inetd>".    //
00032 //                                                                      //
00033 // If xinetd is used instead, a file named 'rootd' should be created    //
00034 // under /etc/xinetd.d with content:                                    //
00035 //                                                                      //
00036 // # default: off                                                       //
00037 // # description: The root daemon                                       //
00038 // #                                                                    //
00039 // service rootd                                                        //
00040 // {                                                                    //
00041 //      disable         = no                                            //
00042 //      flags           = REUSE                                         //
00043 //      socket_type     = stream                                        //
00044 //      wait            = no                                            //
00045 //      user            = root                                          //
00046 //      server          = /usr/local/root/bin/rootd                     //
00047 //      server_args     = -i -d 0                                       //
00048 // }                                                                    //
00049 //                                                                      //
00050 // and xinetd restarted (/sbin/service xinetd restart).                 //
00051 //                                                                      //
00052 // You can also start rootd by hand running directly under your private //
00053 // account (no root system priviliges needed). For example to start     //
00054 // rootd listening on port 5151 just type:                              //
00055 //                                                                      //
00056 // rootd -p 5151                                                        //
00057 //                                                                      //
00058 // Notice: no & is needed. Rootd will go in background by itself.       //
00059 // In this case, the port number and process id will be printed, e.g.   //
00060 //                                                                      //
00061 // ROOTD_PORT=5151                                                      //
00062 // ROOTD_PID=14433                                                      //
00063 //                                                                      //
00064 // Rootd arguments:                                                     //
00065 //   -b tcpwindowsize  specifies the tcp window size in bytes (e.g. see //
00066 //                     http://www.psc.edu/networking/perf_tune.html)    //
00067 //                     Default is 65535. Only change default for pipes  //
00068 //                     with a high bandwidth*delay product.             //
00069 //   -C hostcertfile   defines a file where to find information for the //
00070 //                     local host Globus information (see GLOBUS.README //
00071 //                     for details)                                     //
00072 //   -d level          level of debug info written to syslog            //
00073 //                     0 = no debug (default)                           //
00074 //                     1 = minimum                                      //
00075 //                     2 = medium                                       //
00076 //                     3 = maximum                                      //
00077 //   -D rootdaemonrc   read access rules from file <rootdaemonrc>.      //
00078 //                     By default <root_etc_dir>/system.rootdaemonrc is //
00079 //                     used for access rules; for privately started     //
00080 //                     daemons $HOME/.rootdaemonrc (if present) takes   //
00081 //                     highest priority.                                //
00082 //   -E                obsolete; up to v4.00.08 this option was used to //
00083 //                     force exclusivity of the authentication tokens;  //
00084 //                     with the new approach for authentication tab     //
00085 //                     files this option is dummy.                      //
00086 //   -f                do not run as daemon, run in the foreground      //
00087 //   -F filename       Specify that rootd is in CASTOR mode and should  //
00088 //                     serve this file.                                 //
00089 //   -G gridmapfile    defines the gridmap file to be used for globus   //
00090 //                     authentication if different from globus default  //
00091 //                     (/etc/grid-security/gridmap); (re)defines the    //
00092 //                     GRIDMAP environment variable.                    //
00093 //   -h                print usage message                              //
00094 //   -H reqid          In CASTOR mode, specify the ID of the request    //
00095 //                     that should be accepted                          //
00096 //   -i                says we were started by inetd                    //
00097 //   -noauth           do not require client authentication             //
00098 //   -p port#          specifies a different port to listen on.         //
00099 //                     Use port1-port2 to find first available port in  //
00100 //                     range. Use 0-N for range relative to service     //
00101 //                     port.                                            //
00102 //   -P file           use this password file, instead of .srootdpass   //
00103 //   -r                files can only be opened in read-only mode       //
00104 //   -R bitmask        bit mask specifies which methods will allow      //
00105 //                     authentication to be re-used                     //
00106 //   -s <sshd_port>    specifies the port number for the sshd daemon    //
00107 //                     (default is 22)                                  //
00108 //   -S keytabfile     use this keytab file, instead of the default     //
00109 //                     (option only supported when compiled with        //
00110 //                     Kerberos5 support)                               //
00111 //   -T <tmpdir>       specifies the directory path to be used to place //
00112 //                     temporary files; default is /usr/tmp.            //
00113 //                     Useful if not running as root.                   //
00114 //   -w                do not check /etc/hosts.equiv, $HOME/.rhosts     //
00115 //                     for UsrPwd authentications; by default these     //
00116 //                     files are checked first by calling ruserok(...); //
00117 //                     if this option is specified a password is always //
00118 //                     required.
00119 //   rootsys_dir       directory containing the ROOT etc and bin        //
00120 //                     directories. Superseeds ROOTSYS or built-in      //
00121 //                     (as specified to ./configure).                   //
00122 //                                                                      //
00123 // Rootd can also be configured for anonymous usage (like anonymous     //
00124 // ftp). To setup rootd to accept anonymous logins do the following     //
00125 // (while being logged in as root):                                     //
00126 //                                                                      //
00127 // - Add the following line to /etc/passwd:                             //
00128 //                                                                      //
00129 //   rootd:*:71:72:Anonymous rootd:/var/spool/rootd:/bin/false          //
00130 //                                                                      //
00131 //   where you may modify the uid, gid (71, 72) and the home directory  //
00132 //   to suite your system.                                              //
00133 //                                                                      //
00134 // - Add the following line to /etc/group:                              //
00135 //                                                                      //
00136 //   rootd:*:72:rootd                                                   //
00137 //                                                                      //
00138 //   where the gid must match the gid in /etc/passwd.                   //
00139 //                                                                      //
00140 // - Create the directories:                                            //
00141 //                                                                      //
00142 //   mkdir /var/spool/rootd                                             //
00143 //   mkdir /var/spool/rootd/tmp                                         //
00144 //   chmod 777 /var/spool/rootd/tmp                                     //
00145 //                                                                      //
00146 //   Where /var/spool/rootd must match the rootd home directory as      //
00147 //   specified in the rootd /etc/passwd entry.                          //
00148 //                                                                      //
00149 // - To make writeable directories for anonymous do, for example:       //
00150 //                                                                      //
00151 //   mkdir /var/spool/rootd/pub                                         //
00152 //   chown rootd:rootd /var/spool/rootd/pub                             //
00153 //                                                                      //
00154 // That's all.                                                          //
00155 //                                                                      //
00156 // Several remarks:                                                     //
00157 //  - you can login to an anonymous server either with the names        //
00158 //    "anonymous" or "rootd".                                           //
00159 //  - the passwd should be of type user@host.do.main. Only the @ is     //
00160 //    enforced for the time being.                                      //
00161 //  - in anonymous mode the top of the file tree is set to the rootd    //
00162 //    home directory, therefore only files below the home directory     //
00163 //    can be accessed.                                                  //
00164 //  - anonymous mode only works when the server is started via inetd.   //
00165 //                                                                      //
00166 //  When your system uses shadow passwords you have to compile rootd    //
00167 //  with -DR__SHADOWPW. Since shadow passwords can only be accessed     //
00168 //  while being superuser (root) this works only when the server is     //
00169 //  started via inetd. Another solution is to create a file             //
00170 //  ~/.rootdpass containing an encrypted password. If this file exists  //
00171 //  its password is used for authentication. This method overrides      //
00172 //  all other authentication methods. To create an encrypted password   //
00173 //  do something like:                                                  //
00174 //     perl -e '$pw = crypt("<secretpasswd>","salt"); print "$pw\n"'    //
00175 //  and store this string in ~/.rootdpass.                              //
00176 //                                                                      //
00177 //  To use AFS for authentication compile rootd with the -DR__AFS flag. //
00178 //  In that case you also need to link with the AFS libraries. See      //
00179 //  the Makefiles for more details.                                     //
00180 //                                                                      //
00181 //  To use Secure Remote Passwords (SRP) for authentication compile     //
00182 //  rootd with the -DR__SRP flag. In that case you also need to link    //
00183 //  with the SRP and gmp libraries. See the Makefile for more details.  //
00184 //  SRP is described at: http://srp.stanford.edu/.                      //
00185 //                                                                      //
00186 //  See README.AUTH for more details on the authentication features.    //
00187 //                                                                      //
00188 //////////////////////////////////////////////////////////////////////////
00189 
00190 // Protocol changes (see gProtocol):
00191 // 2 -> 3: added handling of kROOTD_FSTAT message.
00192 // 3 -> 4: added support for TFTP (i.e. kROOTD_PUTFILE, kROOTD_GETFILE, etc.)
00193 // 4 -> 5: added support for "+read" to allow readers when file is opened for writing
00194 // 5 -> 6: added support for kerberos5 authentication
00195 // 6 -> 7: added support for kROOTD_BYE and kROOTD_PROTOCOL2
00196 // 7 -> 8: added support for Globus, SSH and Rfio authentication and negotiation
00197 // 8 -> 9: change in Kerberos authentication protocol
00198 // 9 -> 10: Receives client protocol with kROOTD_PROTOCOL + change cleaning protocol
00199 // 10 -> 11: modified SSH protocol + support for server 'no authentication' mode
00200 // 11 -> 12: added support for stat functionality (access,opendir,...) (cfr.TNetSystem)
00201 //           and support for OpenSSL keys for encryption
00202 // 12 -> 13: changed return message of RootdFstat()
00203 // 13 -> 14: support for TNetFile setup via TXNetFile
00204 // 14 -> 15: support for SSH authentication via SSH tunnel
00205 // 15 -> 16: cope with the bug fix in TUrl::GetFile
00206 // 16 -> 17: Addition of "Gets" (multiple buffers in a single request)
00207 // 17 -> 18: fix problems with '//' in admin paths; partial logging in castor mode
00208 
00209 #include "RConfigure.h"
00210 #include "RConfig.h"
00211 
00212 #include <ctype.h>
00213 #include <fcntl.h>
00214 #include <pwd.h>
00215 #include <stdio.h>
00216 #include <string.h>
00217 #include <string>
00218 #include <stdlib.h>
00219 #include <unistd.h>
00220 #include <time.h>
00221 #include <sys/time.h>
00222 #include <sys/stat.h>
00223 #include <netinet/in.h>
00224 #include <errno.h>
00225 #include <netdb.h>
00226 #include "snprintf.h"
00227 
00228 #include <sys/types.h>
00229 #include <dirent.h>
00230 
00231 #if defined(__CYGWIN__) && defined(__GNUC__)
00232 #   define cygwingcc
00233 #endif
00234 #if defined(__alpha) && !defined(linux)
00235 #   ifdef _XOPEN_SOURCE
00236 #      if _XOPEN_SOURCE+0 > 0
00237 #         define R__TRUE64
00238 #      endif
00239 #   endif
00240 #include <sys/mount.h>
00241 #ifndef R__TRUE64
00242 extern "C" int fstatfs(int file_descriptor, struct statfs *buffer);
00243 #endif
00244 #elif defined(__APPLE__)
00245 #include <sys/mount.h>
00246 extern "C" int fstatfs(int file_descriptor, struct statfs *buffer);
00247 #elif defined(linux) || defined(__hpux) || defined(cygwingcc)
00248 #include <sys/vfs.h>
00249 #elif defined(__FreeBSD__) || defined(__OpenBSD__)
00250 #include <sys/param.h>
00251 #include <sys/mount.h>
00252 #else
00253 #include <sys/statfs.h>
00254 #endif
00255 
00256 #if defined(linux) || defined(__hpux) || defined(_AIX) || defined(__alpha) || \
00257     defined(__sun) || defined(__sgi) || defined(__FreeBSD__) || \
00258     defined(__APPLE__) || defined(cygwingcc) || defined(__OpenBSD__)
00259 #define HAVE_MMAP
00260 #endif
00261 
00262 #ifdef HAVE_MMAP
00263 #   include <sys/mman.h>
00264 #ifndef MAP_FILE
00265 #define MAP_FILE 0           /* compatability flag */
00266 #endif
00267 #endif
00268 
00269 #if (defined(__FreeBSD__) && (__FreeBSD__ < 4)) || defined(__OpenBSD__) || \
00270     (defined(__APPLE__) && (!defined(MAC_OS_X_VERSION_10_3) || \
00271      (MAC_OS_X_VERSION_MAX_ALLOWED < MAC_OS_X_VERSION_10_3)))
00272 #include <sys/file.h>
00273 #define lockf(fd, op, sz)   flock((fd), (op))
00274 #ifndef F_LOCK
00275 #define F_LOCK             (LOCK_EX | LOCK_NB)
00276 #endif
00277 #ifndef F_ULOCK
00278 #define F_ULOCK             LOCK_UN
00279 #endif
00280 #endif
00281 
00282 #if defined(cygwingcc)
00283 #define F_LOCK F_WRLCK
00284 #define F_ULOCK F_UNLCK
00285 static int fcntl_lockf(int fd, int op, off_t off)
00286 {
00287    flock fl;
00288    fl.l_whence = SEEK_SET;
00289    fl.l_start  = off;
00290    fl.l_len    = 0;       // whole file
00291    fl.l_pid    = getpid();
00292    fl.l_type   = op;
00293    return fcntl(fd, F_SETLK, &fl);
00294 }
00295 #define lockf fcntl_lockf
00296 #endif
00297 
00298 #if defined(linux) || defined(__sun) || defined(__sgi) || \
00299     defined(_AIX) || defined(__FreeBSD__) || defined(__APPLE__) || \
00300     defined(__MACH__) || defined(cygwingcc) || defined(__OpenBSD__)
00301 #include <grp.h>
00302 #include <sys/types.h>
00303 #include <signal.h>
00304 #define ROOT_SIGNAL_INCLUDED
00305 #endif
00306 
00307 #if defined(__alpha) && !defined(linux) && !defined(__FreeBSD__) && \
00308     !defined(__OpenBSD__)
00309 extern "C" int initgroups(const char *name, int basegid);
00310 #ifndef ROOT_SIGNAL_INCLUDED
00311 #include <signal.h>
00312 #endif
00313 #endif
00314 
00315 #if defined(__sgi) && !defined(__GNUG__) && (SGI_REL<62)
00316 extern "C" {
00317    int seteuid(int euid);
00318    int setegid(int egid);
00319 }
00320 #endif
00321 
00322 #if defined(_AIX)
00323 extern "C" {
00324    //int initgroups(const char *name, int basegid);
00325    int seteuid(uid_t euid);
00326    int setegid(gid_t egid);
00327 }
00328 #endif
00329 
00330 #include "rootdp.h"
00331 
00332 extern "C" {
00333 #include "rsadef.h"
00334 #include "rsalib.h"
00335 }
00336 
00337 // Debug flag
00338 int gDebug  = 0;
00339 
00340 //--- Local Globals -----------------------------------------------------------
00341 
00342 enum EFileMode{ kBinary, kAscii };
00343 
00344 static std::string gRootdTab;     // keeps track of open files
00345 static std::string gRpdAuthTab;   // keeps track of authentication info
00346 static EService gService         = kROOTD;
00347 static int gProtocol             = 18;      // increase when protocol changes
00348 static int gClientProtocol       = -1;      // Determined by RpdInitSession
00349 static int gAnon                 = 0;       // anonymous user flag
00350 static double gBytesRead         = 0;
00351 static double gBytesWritten      = 0;
00352 static DIR *gRDDirectory         = 0;
00353 static int gDownloaded           = 0;
00354 static int gFd                   = -1;
00355 static int gFtp                  = 0;
00356 static int gInetdFlag            = 0;
00357 static char gOption[32]          = { 0 };
00358 static char gFile[kMAXPATHLEN]   = { 0 };
00359 static int gUploaded             = 0;
00360 static int gWritable             = 0;
00361 static int gReadOnly             = 0;
00362 static std::string gUser;
00363 static std::string gPasswd;
00364 
00365 // CASTOR specific
00366 static int gCastorFlag           = 0;
00367 static std::string gCastorFile;
00368 static std::string gCastorReqId;
00369 
00370 using namespace ROOT;
00371 
00372 //--- Error handlers -----------------------------------------------------------
00373 
00374 //______________________________________________________________________________
00375 void Err(int level,const char *msg, int size)
00376 {
00377    Perror((char *)msg,size);
00378    if (level > -1) NetSendError((ERootdErrors)level);
00379 }
00380 //______________________________________________________________________________
00381 void ErrFatal(int level,const char *msg, int size)
00382 {
00383    Perror((char *)msg,size);
00384    if (level > -1) NetSendError((ERootdErrors)level);
00385    RootdClose();
00386    exit(1);
00387 }
00388 //______________________________________________________________________________
00389 void ErrSys(int level,const char *msg, int size)
00390 {
00391    Perror((char *)msg,size);
00392    ErrFatal(level,msg,size);
00393 }
00394 
00395 //--- Rootd routines -----------------------------------------------------------
00396 
00397 const char *shellMeta   = "~*[]{}?$";
00398 const char *shellStuff  = "(){}<>\"'";
00399 const char  shellEscape = '\\';
00400 
00401 //______________________________________________________________________________
00402 static int EscChar(const char *src, char *dst, int dstlen, const char *specchars, char escchar)
00403 {
00404    // Escape specchars in src with escchar and copy to dst.
00405 
00406    const char *p;
00407    char *q, *end = dst+dstlen-1;
00408 
00409    for (p = src, q = dst; *p && q < end; ) {
00410       if (strchr(specchars, *p)) {
00411          *q++ = escchar;
00412          if (q < end)
00413             *q++ = *p++;
00414       } else
00415          *q++ = *p++;
00416    }
00417    *q = '\0';
00418 
00419    if (*p != 0)
00420       return -1;
00421    return q-dst;
00422 }
00423 
00424 //______________________________________________________________________________
00425 void SigPipe(int)
00426 {
00427    // After SO_KEEPALIVE times out we probably get a SIGPIPE.
00428 
00429    ErrorInfo("SigPipe: rootd.cxx: got a SIGPIPE");
00430 
00431    // Terminate properly
00432    RpdAuthCleanup(0, 0);
00433    RootdClose();
00434    exit(1);
00435 }
00436 
00437 //______________________________________________________________________________
00438 static const char *HomeDirectory(const char *name)
00439 {
00440    // Returns the user's home directory.
00441 
00442    static char path[kMAXPATHLEN], mydir[kMAXPATHLEN];
00443    struct passwd *pw;
00444 
00445    if (name) {
00446       pw = getpwnam(name);
00447       if (pw) {
00448          strncpy(path, pw->pw_dir, kMAXPATHLEN-1);
00449          path[sizeof(path)-1] = '\0';
00450          return path;
00451       }
00452    } else {
00453       if (mydir[0])
00454          return mydir;
00455       pw = getpwuid(getuid());
00456       if (pw) {
00457          strncpy(mydir, pw->pw_dir, kMAXPATHLEN-1);
00458          mydir[sizeof(mydir)-1] = '\0';
00459          return mydir;
00460       }
00461    }
00462    return 0;
00463 }
00464 
00465 //______________________________________________________________________________
00466 char *RootdExpandPathName(const char *name)
00467 {
00468    // Expand a pathname getting rid of special shell characters like ~.$, etc.
00469    // Returned string must be freed by caller.
00470 
00471    const char *patbuf = name;
00472 
00473    // skip leading blanks
00474    while (*patbuf == ' ')
00475       patbuf++;
00476 
00477    // any shell meta characters?
00478    for (const char *p = patbuf; *p; p++)
00479       if (strchr(shellMeta, *p))
00480          goto needshell;
00481 
00482    return strdup(name);
00483 
00484 needshell:
00485    // escape shell quote characters
00486    char escPatbuf[kMAXPATHLEN];
00487    EscChar(patbuf, escPatbuf, sizeof(escPatbuf), shellStuff, shellEscape);
00488 
00489    char cmd[kMAXPATHLEN];
00490 #ifdef __hpux
00491    strlcpy(cmd, "/bin/echo ", sizeof(cmd));
00492 #else
00493    strlcpy(cmd, "echo ", sizeof(cmd));
00494 #endif
00495 
00496    // emulate csh -> popen executes sh
00497    if (escPatbuf[0] == '~') {
00498       const char *hd;
00499       if (escPatbuf[1] != '\0' && escPatbuf[1] != '/') {
00500          // extract user name
00501          char uname[70], *p, *q;
00502          for (p = &escPatbuf[1], q = uname; *p && *p !='/';)
00503             *q++ = *p++;
00504          *q = '\0';
00505          hd = HomeDirectory(uname);
00506          if (hd == 0)
00507             strcat(cmd, escPatbuf);
00508          else {
00509             strcat(cmd, hd);
00510             strcat(cmd, p);
00511          }
00512 
00513       } else {
00514          hd = HomeDirectory(0);
00515          if (hd == 0) {
00516             Error(ErrSys, kErrFatal, "RootdExpandPathName: no home directory");
00517             return 0;
00518          }
00519          strcat(cmd, hd);
00520          strcat(cmd, &escPatbuf[1]);
00521       }
00522    } else
00523       strcat(cmd, escPatbuf);
00524 
00525    FILE *pf;
00526    if ((pf = ::popen(&cmd[0], "r")) == 0) {
00527       Error(ErrSys, kErrFatal, "RootdExpandPathName: error in popen(%s)", cmd);
00528       return 0;
00529    }
00530 
00531    // read first argument
00532    char expPatbuf[kMAXPATHLEN];
00533    int  ch, i, cnt = 0;
00534 again:
00535    for (i = 0, ch = fgetc(pf); ch != EOF && ch != ' ' && ch != '\n'; i++, ch = fgetc(pf)) {
00536       expPatbuf[i] = ch;
00537       cnt++;
00538    }
00539    // this will be true if forked process was not yet ready to be read
00540    if (cnt == 0 && ch == EOF) goto again;
00541    expPatbuf[cnt] = '\0';
00542 
00543    // skip rest of pipe
00544    while (ch != EOF) {
00545       ch = fgetc(pf);
00546       if (ch == ' ' || ch == '\t') {
00547          ::pclose(pf);
00548          Error(ErrFatal, kErrFatal, "RootdExpandPathName: expression ambigous");
00549          return 0;
00550       }
00551    }
00552 
00553    ::pclose(pf);
00554 
00555    return strdup(expPatbuf);
00556 }
00557 
00558 //______________________________________________________________________________
00559 int RootdCheckTab(int mode)
00560 {
00561    // Checks gRootdTab file to see if file can be opened. If mode = 1 then
00562    // check if file can safely be opened in write mode, i.e. see if file
00563    // is not already opened in either read or write mode. If mode = 0 then
00564    // check if file can safely be opened in read mode, i.e. see if file
00565    // is not already opened in write mode. If mode = -1 check write mode
00566    // like 1 but do not update rootdtab file. Returns 1 if file can be
00567    // opened safely, otherwise 0.
00568    //
00569    // The format of the file is:
00570    // filename device inode mode username pid
00571    // where device is the unique file system id, inode is the unique file
00572    // ref number, mode is either "read" or "write", username the user
00573    // who has the file open and pid is the pid of the rootd having the
00574    // file open.
00575 
00576    // Open rootdtab file. Try first /usr/tmp and then /tmp.
00577    // The lockf() call can fail if the directory is NFS mounted
00578    // and the lockd daemon is not running.
00579 
00580    const char *sfile = gRootdTab.c_str();
00581    int fid, create = 0;
00582 
00583    int noupdate = 0;
00584    if (mode < 0) {
00585       mode = 1;
00586       noupdate = 1;
00587    }
00588 
00589 again:
00590    if (access(sfile, F_OK) == -1) {
00591       fid = open(sfile, O_CREAT|O_RDWR, 0644);
00592       if (fid != -1) fchmod(fid, 0666);    // override umask setting
00593       create = 1;
00594    } else
00595       fid = open(sfile, O_RDWR);
00596 
00597    if (fid == -1) {
00598       if (sfile[1] == 'u') {
00599          sfile = gRootdTab.c_str()+4;
00600          goto again;
00601       }
00602       Error(ErrSys, kErrFatal, "RootdCheckTab: error opening %s", sfile);
00603    }
00604 
00605    // lock the file
00606    if (lockf(fid, F_LOCK, (off_t)1) == -1) {
00607       if (sfile[1] == 'u' && create) {
00608          close(fid);
00609          remove(sfile);
00610          sfile = gRootdTab.c_str()+4;
00611          goto again;
00612       }
00613       Error(ErrSys, kErrFatal, "RootdCheckTab: error locking %s", sfile);
00614    }
00615    if (gDebug > 2)
00616       ErrorInfo("RootdCheckTab: file %s locked", sfile);
00617 
00618    struct stat sbuf;
00619    fstat(fid, &sbuf);
00620    size_t siz = sbuf.st_size;
00621 
00622    dev_t device;
00623    ino_t inode;
00624    if (stat(gFile, &sbuf) == -1) {
00625       device = 0;
00626       inode  = 0;
00627    } else {
00628       device = sbuf.st_dev;
00629       inode  = sbuf.st_ino;
00630    }
00631 
00632    char msg[kMAXPATHLEN];
00633    const char *smode = (mode == 1) ? "write" : "read";
00634    int result = 1;
00635 
00636    if (siz > 0) {
00637       int changed = 0;
00638       char *fbuf = new char[siz+1];
00639       char *flast = fbuf + siz;
00640 
00641       while (read(fid, fbuf, siz) < 0 && GetErrno() == EINTR)
00642          ResetErrno();
00643       fbuf[siz] = 0;
00644 
00645       char *n, *s = fbuf;
00646       while ((n = strchr(s, '\n')) && siz > 0) {
00647          n++;
00648          char user[64], gmode[32];
00649          int  pid;
00650          unsigned long dev, ino;
00651          sscanf(s, "%s %lu %lu %s %s %d", msg, &dev, &ino, gmode, user, &pid);
00652          if (kill(pid, 0) == -1 && GetErrno() == ESRCH) {
00653             ErrorInfo("RootdCheckTab: remove stale lock (%s %lu %lu %s %s %d)\n",
00654                 msg, dev, ino, gmode, user, pid);
00655             if (n >= flast) {
00656                siz = int(s - fbuf);
00657                changed = 1;
00658                break;
00659             } else {
00660                int l = int(flast - n) + 1;
00661                memmove(s, n, l);
00662                siz -= int(n - s);
00663                n = s;
00664             }
00665             flast = fbuf + siz;
00666             changed = 1;
00667          } else if ((dev_t)dev == device && (ino_t)ino == inode) {
00668             if (mode == 1)
00669                result = 0;
00670             else if (!strcmp(gmode, "write"))
00671                result = 0;
00672          }
00673          s = n;
00674       }
00675       if (changed) {
00676          if (ftruncate(fid, 0) == -1)
00677             ErrorInfo("RootdCheckTab: ftruncate failed");
00678          lseek(fid, 0, SEEK_SET);
00679          if (siz > 0) {
00680             while (write(fid, fbuf, siz) < 0 && GetErrno() == EINTR)
00681                ResetErrno();
00682          }
00683       }
00684       delete [] fbuf;
00685    }
00686 
00687    if (result && !noupdate) {
00688       unsigned long dev = device;
00689       unsigned long ino = inode;
00690       char *tmsg = msg;
00691       int lmsg = strlen(gFile) + gUser.length() + strlen(smode) + 40;
00692       if (lmsg > kMAXPATHLEN)
00693          tmsg = new char[lmsg];
00694       sprintf(tmsg, "%s %lu %lu %s %s %d\n",
00695                    gFile, dev, ino, smode, gUser.c_str(), (int) getpid());
00696       if (write(fid, tmsg, strlen(tmsg)) == -1)
00697          Error(ErrSys, kErrFatal, "RootdCheckTab: error writing %s", sfile);
00698       if (tmsg != msg)
00699          delete[] tmsg;
00700    }
00701 
00702    // unlock the file
00703    lseek(fid, 0, SEEK_SET);
00704    if (lockf(fid, F_ULOCK, (off_t)1) == -1)
00705       Error(ErrSys, kErrFatal, "RootdCheckTab: error unlocking %s", sfile);
00706    if (gDebug > 2)
00707       ErrorInfo("RootdCheckTab: file %s unlocked", sfile);
00708 
00709    close(fid);
00710 
00711    return result;
00712 }
00713 
00714 //______________________________________________________________________________
00715 void RootdCloseTab(int force = 0)
00716 {
00717    // Removes from the gRootdTab file the reference to gFile for the
00718    // current rootd. If force = 1, then remove all references for gFile
00719    // from the gRootdTab file. This might be necessary in case something
00720    // funny happened and the original reference was not correctly removed.
00721    // Stale locks are detected by checking each pid and then removed.
00722 
00723    const char *sfile = gRootdTab.c_str();
00724    int fid;
00725 
00726 again:
00727    if (access(sfile, F_OK) == -1) {
00728       if (sfile[1] == 'u') {
00729          sfile = gRootdTab.c_str()+4;
00730          goto again;
00731       }
00732       ErrorInfo("RootdCloseTab: file %s does not exist", sfile);
00733       return;
00734    }
00735 
00736    fid = open(sfile, O_RDWR);
00737 
00738    if (fid == -1) {
00739       ErrorInfo("RootdCloseTab: error opening %s", sfile);
00740       return;
00741    }
00742 
00743    // lock the file
00744    if (lockf(fid, F_LOCK, (off_t)1) == -1) {
00745       ErrorInfo("RootdCloseTab: error locking %s", sfile);
00746       return;
00747    }
00748    if (gDebug > 2)
00749       ErrorInfo("RootdCloseTab: file %s locked", sfile);
00750 
00751    struct stat sbuf;
00752    fstat(fid, &sbuf);
00753    size_t siz = sbuf.st_size;
00754 
00755    stat(gFile, &sbuf);
00756    dev_t device = sbuf.st_dev;
00757    ino_t inode  = sbuf.st_ino;
00758 
00759    if (siz > 0) {
00760       int changed = 0;
00761       int mypid   = getpid();
00762       char *fbuf  = new char[siz+1];
00763       char *flast = fbuf + siz;
00764 
00765       while (read(fid, fbuf, siz) < 0 && GetErrno() == EINTR)
00766          ResetErrno();
00767       fbuf[siz] = 0;
00768 
00769       char *n, *s = fbuf;
00770       while ((n = strchr(s, '\n')) && siz > 0) {
00771          n++;
00772          char msg[kMAXPATHLEN], user[64], gmode[32];
00773          int  pid, stale = 0;
00774          unsigned long dev, ino;
00775          sscanf(s, "%s %lu %lu %s %s %d", msg, &dev, &ino, gmode, user, &pid);
00776          if (kill(pid, 0) == -1 && GetErrno() == ESRCH) {
00777             stale = 1;
00778             ErrorInfo("Remove Stale Lock (%s %lu %lu %s %s %d)\n",
00779                        msg, dev, ino, gmode, user, pid);
00780          }
00781          if (stale || (!force && mypid == pid) ||
00782             (force && device == (dev_t)dev && inode == (ino_t)ino &&
00783              !strcmp(gUser.c_str(), user))) {
00784             if (n >= flast) {
00785                siz = int(s - fbuf);
00786                changed = 1;
00787                break;
00788             } else {
00789                int l = int(flast - n) + 1;
00790                memmove(s, n, l);
00791                siz -= int(n - s);
00792                n = s;
00793             }
00794             flast = fbuf + siz;
00795             changed = 1;
00796          }
00797          s = n;
00798       }
00799       if (changed) {
00800          if (ftruncate(fid, 0) == -1)
00801             ErrorInfo("RootdCheckTab: ftruncate failed");
00802          lseek(fid, 0, SEEK_SET);
00803          if (siz > 0) {
00804             while (write(fid, fbuf, siz) < 0 && GetErrno() == EINTR)
00805                ResetErrno();
00806          }
00807       }
00808       delete [] fbuf;
00809    }
00810 
00811    // unlock the file
00812    lseek(fid, 0, SEEK_SET);
00813    if (lockf(fid, F_ULOCK, (off_t)1) == -1) {
00814       ErrorInfo("RootdCloseTab: error unlocking %s", sfile);
00815       return;
00816    }
00817    if (gDebug > 2)
00818       ErrorInfo("RootdCloseTab: file %s unlocked", sfile);
00819 
00820    close(fid);
00821 }
00822 
00823 //______________________________________________________________________________
00824 int RootdIsOpen()
00825 {
00826    if (gFd == -1) return 0;
00827    return 1;
00828 }
00829 
00830 //______________________________________________________________________________
00831 void RootdCloseFtp()
00832 {
00833    if (gDebug > 0)
00834       ErrorInfo("RootdCloseFtp: %d files uploaded, %d files downloaded,"
00835                 " rd=%g, wr=%g, rx=%g, tx=%g",
00836                 gUploaded, gDownloaded, gBytesRead, gBytesWritten,
00837                 NetGetBytesRecv(), NetGetBytesSent());
00838    else
00839       ErrorInfo("Rootd: %d files uploaded, %d files downloaded, rd=%g,"
00840                 " wr=%g, rx=%g, tx=%g",
00841                 gUploaded, gDownloaded, gBytesRead, gBytesWritten,
00842                 NetGetBytesRecv(), NetGetBytesSent());
00843 }
00844 
00845 //______________________________________________________________________________
00846 void RootdClose()
00847 {
00848    if (gFtp) {
00849       RootdCloseFtp();
00850       return;
00851    }
00852 
00853    if (RootdIsOpen()) {
00854       close(gFd);
00855       gFd = -1;
00856    }
00857 
00858    RootdCloseTab();
00859 
00860    if (gDebug > 0)
00861       ErrorInfo("RootdClose: file %s closed, rd=%g, wr=%g, rx=%g, tx=%g",
00862                 gFile, gBytesRead, gBytesWritten,
00863                 NetGetBytesRecv(), NetGetBytesSent());
00864    else
00865       ErrorInfo("Rootd: file %s closed, rd=%g, wr=%g, rx=%g, tx=%g", gFile,
00866                 gBytesRead, gBytesWritten,
00867                 NetGetBytesRecv(), NetGetBytesSent());
00868 }
00869 
00870 //______________________________________________________________________________
00871 void RootdFlush()
00872 {
00873    if (RootdIsOpen() && gWritable) {
00874 #ifndef WIN32
00875       if (fsync(gFd) < 0)
00876          Error(ErrSys, kErrFatal, "RootdFlush: error flushing file %s", gFile);
00877 #endif
00878    }
00879 
00880    if (gDebug > 0)
00881       ErrorInfo("RootdFlush: file %s flushed", gFile);
00882 }
00883 
00884 //______________________________________________________________________________
00885 void RootdStat()
00886 {
00887 
00888 }
00889 
00890 //______________________________________________________________________________
00891 void RootdFstat(const char *buf)
00892 {
00893    // Return file stat information in same format as TSystem::GetPathInfo().
00894 
00895    char     msg[256];
00896    int      islink = 0;
00897 
00898 #if defined(R__SEEK64)
00899    struct stat64 statbuf;
00900 #elif defined(WIN32)
00901    struct _stati64 statbuf;
00902 #else
00903    struct stat statbuf;
00904 #endif
00905 
00906    int rc = -1;
00907    if (!buf || !strlen(buf)) {
00908 
00909       if (RootdIsOpen()) {
00910 #if defined(R__SEEK64)
00911          rc = fstat64(gFd, &statbuf);
00912 #elif defined(WIN32)
00913          rc = _fstati64(gFd, &statbuf);
00914 #else
00915          rc = fstat(gFd, &statbuf);
00916 #endif
00917       }
00918    } else {
00919 
00920       char *epath = (char *)buf;
00921       if (buf[0] == '/' && buf[1] == '/')
00922          epath++;
00923 #if defined(R__SEEK64)
00924       rc = lstat64(epath, &statbuf);
00925 #elif defined(WIN32)
00926       rc = _stati64(epath, &statbuf);
00927 #else
00928       rc = lstat(epath, &statbuf);
00929 #endif
00930       if (rc >= 0) {
00931          islink = S_ISLNK(statbuf.st_mode);
00932          if (islink) {
00933 #if defined(R__SEEK64)
00934             rc = stat64(epath, &statbuf);
00935 #elif defined(WIN32)
00936             rc = _stati64(epath, &statbuf);
00937 #else
00938             rc = stat(epath, &statbuf);
00939 #endif
00940          }
00941       }
00942    }
00943 
00944    // New format for recent clients
00945    if (gClientProtocol > 11) {
00946       if (rc >= 0)
00947          sprintf(msg, "%ld %ld %d %d %d %lld %ld %d", (long)statbuf.st_dev,
00948                  (long)statbuf.st_ino, statbuf.st_mode, (int)(statbuf.st_uid),
00949                  (int)(statbuf.st_gid), (Long64_t)statbuf.st_size, statbuf.st_mtime,
00950                  islink);
00951       else
00952          sprintf(msg, "-1 -1 -1 -1 -1 -1 -1 -1");
00953    } else {
00954       // Old client: use previous incomplete format
00955       if (rc >= 0) {
00956          long id = (statbuf.st_dev << 24) + statbuf.st_ino;
00957          Long64_t size = statbuf.st_size;
00958          long modtime = statbuf.st_mtime;
00959          long flags = 0;
00960          if (statbuf.st_mode & ((S_IEXEC)|(S_IEXEC>>3)|(S_IEXEC>>6)))
00961             flags |= 1;
00962          if ((statbuf.st_mode & S_IFMT) == S_IFDIR)
00963             flags |= 2;
00964          if ((statbuf.st_mode & S_IFMT) != S_IFREG &&
00965              (statbuf.st_mode & S_IFMT) != S_IFDIR)
00966             flags |= 4;
00967          sprintf(msg, "%ld %lld %ld %ld", id, size, flags, modtime);
00968       } else
00969          sprintf(msg, "-1 -1 -1 -1");
00970    }
00971 
00972    NetSend(msg, kROOTD_FSTAT);
00973 }
00974 
00975 //______________________________________________________________________________
00976 void RootdParallel()
00977 {
00978    // Handle initialization message from remote host. If size > 1 then
00979    // so many parallel sockets will be opened to the remote host.
00980 
00981    int buf[3];
00982    if (NetRecvRaw(buf, sizeof(buf)) < 0)
00983       Error(ErrFatal, kErrFatal, "RootdParallel: error receiving message");
00984 
00985    int size = ntohl(buf[1]);
00986    int port = ntohl(buf[2]);
00987 
00988    if (gDebug > 0)
00989       ErrorInfo("RootdParallel: port = %d, size = %d", port, size);
00990 
00991    if (size > 1)
00992       NetParOpen(port, size);
00993 }
00994 
00995 //______________________________________________________________________________
00996 static int SysOpen(const char *pathname, int flags, unsigned int mode)
00997 {
00998    // System independent open().
00999 
01000 #if defined(R__WINGCC)
01001    // ALWAYS use binary mode - even cygwin text should be in unix format
01002    // although this is posix default it has to be set explicitly
01003    return ::open(pathname, flags | O_BINARY, mode);
01004 #elif defined(R__SEEK64)
01005    return ::open64(pathname, flags, mode);
01006 #else
01007    return ::open(pathname, flags, mode);
01008 #endif
01009 }
01010 
01011 //______________________________________________________________________________
01012 void RootdOpen(const char *msg)
01013 {
01014    // Open file in mode depending on specified option. If file is already
01015    // opened by another rootd in write mode, do not open the file.
01016 
01017    char file[kMAXPATHLEN], option[32];
01018 
01019    gBytesRead = gBytesWritten = 0;
01020    NetResetByteCount();
01021 
01022    sscanf(msg, "%s %s", file, option);
01023 
01024    if (gCastorFlag) {
01025 
01026       // Checking the CASTOR Request ID
01027       if (gCastorReqId.length() > 0) {
01028          if (strstr(file, gCastorReqId.c_str()) == 0) {
01029             Error(ErrFatal, kErrNoAccess,
01030                   "RootdOpen: Bad CASTOR Request ID: %s rather than %s",
01031                   file, gCastorReqId.c_str());
01032          }
01033       }
01034 
01035       ErrorInfo("RootdOpen: CASTOR Flag on, file: %s", gCastorFile.c_str());
01036       strncpy(gFile, gCastorFile.c_str(), kMAXPATHLEN-1);
01037       gFile[kMAXPATHLEN-1] = '\0';
01038 
01039    } else {
01040 
01041       if (gClientProtocol > 14) {
01042          strlcpy(gFile, file, sizeof(gFile));
01043       } else {
01044          // Old clients send an additional slash at the beginning
01045          if (file[0] == '/')
01046             strlcpy(gFile, &file[1], sizeof(gFile));
01047          else
01048             strlcpy(gFile, file, sizeof(gFile));
01049       }
01050 
01051       gFile[strlen(file)] = '\0';
01052    }
01053 
01054    strlcpy(gOption, option, sizeof(gOption));
01055 
01056    int forceOpen = 0;
01057    if (option[0] == 'f') {
01058       forceOpen = 1;
01059       strlcpy(gOption, &option[1], sizeof(gOption));
01060    }
01061 
01062    int forceRead = 0;
01063    if (!strcmp(option, "+read")) {
01064       forceRead = 1;
01065       strlcpy(gOption, &option[1], sizeof(gOption));
01066    }
01067 
01068    int create = 0;
01069    if (!strcmp(gOption, "new") || !strcmp(gOption, "create"))
01070       create = 1;
01071    int recreate = strcmp(gOption, "recreate") ? 0 : 1;
01072    int update   = strcmp(gOption, "update")   ? 0 : 1;
01073    int read     = strcmp(gOption, "read")     ? 0 : 1;
01074    if (!create && !recreate && !update && !read) {
01075       read = 1;
01076       strlcpy(gOption, "read", sizeof(gOption));
01077    }
01078 
01079    if (!read && gReadOnly)
01080       Error(ErrFatal, kErrNoAccess,
01081             "RootdOpen: file %s can only be opened in \"READ\" mode", gFile);
01082 
01083    if (!gAnon) {
01084       char *fname;
01085       if ((fname = RootdExpandPathName(gFile))) {
01086          strlcpy(gFile, fname, sizeof(gFile));
01087          free(fname);
01088       } else
01089          Error(ErrFatal, kErrBadFile, "RootdOpen: bad file name %s", gFile);
01090    }
01091 
01092    if (forceOpen)
01093       RootdCloseTab(1);
01094 
01095    int trunc = 0;
01096    if (recreate) {
01097       if (!RootdCheckTab(-1))
01098          Error(ErrFatal, kErrFileWriteOpen,
01099                "RootdOpen: file %s already opened in read or write mode", gFile);
01100       if (!access(gFile, F_OK))
01101          trunc = O_TRUNC;
01102       else {
01103          recreate = 0;
01104          create   = 1;
01105          strlcpy(gOption, "create", sizeof(gOption));
01106       }
01107    }
01108 
01109    if (create && !access(gFile, F_OK))
01110       Error(ErrFatal, kErrFileExists, "RootdOpen: file %s already exists", gFile);
01111 
01112    int wasupdt = 0;
01113    if (update) {
01114       if (access(gFile, F_OK)) {
01115          update = 0;
01116          create = 1;
01117          wasupdt = 1;
01118          strlcpy(gOption, "create", sizeof(gOption));
01119       }
01120       if (update && access(gFile, W_OK))
01121          Error(ErrFatal, kErrNoAccess,
01122                "RootdOpen: no write permission for file %s", gFile);
01123    }
01124 
01125    if (read) {
01126       if (access(gFile, F_OK))
01127          Error(ErrFatal, kErrNoFile,
01128                "RootdOpen: file %s does not exist (errno: 0x%x)", gFile, errno);
01129       if (access(gFile, R_OK))
01130          Error(ErrFatal, kErrNoAccess,
01131                "RootdOpen: no read permission for file %s (errno: 0x%x)", gFile, errno);
01132    }
01133 
01134    if (create || recreate || update) {
01135       if (create || recreate) {
01136          // make sure file exists so RootdCheckTab works correctly
01137 #ifndef WIN32
01138          gFd = SysOpen(gFile, O_RDWR | O_CREAT | trunc, 0644);
01139 #else
01140          gFd = SysOpen(gFile, O_RDWR | O_CREAT | O_BINARY | trunc, S_IREAD | S_IWRITE);
01141 #endif
01142          if (gFd != -1)
01143             close(gFd);
01144          gFd = -1;
01145       }
01146 #ifndef WIN32
01147       gFd = SysOpen(gFile, O_RDWR, 0644);
01148 #else
01149       gFd = SysOpen(gFile, O_RDWR | O_BINARY, S_IREAD | S_IWRITE);
01150 #endif
01151       if (gFd == -1)
01152          Error(ErrSys, kErrFileOpen, "RootdOpen: error opening file %s in write mode", gFile);
01153 
01154       if (!RootdCheckTab(1)) {
01155          close(gFd);
01156          Error(ErrFatal, kErrFileWriteOpen, "RootdOpen: file %s already opened in read or write mode", gFile);
01157       }
01158 
01159       gWritable = wasupdt ? 2 : 1;
01160 
01161    } else {
01162 #ifndef WIN32
01163       gFd = SysOpen(gFile, O_RDONLY, 0644);
01164 #else
01165       gFd = SysOpen(gFile, O_RDONLY | O_BINARY, S_IREAD | S_IWRITE);
01166 #endif
01167       if (gFd == -1)
01168          Error(ErrSys, kErrFileOpen, "RootdOpen: error opening file %s in read mode", gFile);
01169 
01170       if (!RootdCheckTab(0)) {
01171          if (!forceRead) {
01172             close(gFd);
01173             Error(ErrFatal, kErrFileReadOpen, "RootdOpen: file %s already opened in write mode", gFile);
01174          }
01175       }
01176 
01177       gWritable = 0;
01178 
01179    }
01180 
01181    NetSend(gWritable, kROOTD_OPEN);
01182 
01183    struct stat sbuf;
01184    fstat(gFd, &sbuf);
01185    unsigned long dev = sbuf.st_dev;
01186    unsigned long ino = sbuf.st_ino;
01187 
01188    if (gDebug > 0)
01189       ErrorInfo("RootdOpen: file %s opened in mode %s", gFile, gOption);
01190    else {
01191       if (gAnon)
01192          ErrorInfo("RootdOpen: file %s (dev=%lu,inode=%lu,%s) opened by %s/%s",
01193                    gFile, dev, ino, gOption, gUser.c_str(), gPasswd.c_str());
01194       else
01195          ErrorInfo("RootdOpen: file %s (dev=%lu,inode=%lu,%s) opened by %s",
01196                    gFile, dev, ino, gOption, gUser.c_str());
01197    }
01198 }
01199 
01200 //______________________________________________________________________________
01201 void RootdPut(const char *msg)
01202 {
01203    // Receive a buffer and write it at the specified offset in the currently
01204    // open file.
01205 
01206    Long64_t offset;
01207    int      len;
01208 
01209    sscanf(msg, "%lld %d", &offset, &len);
01210 
01211    char *buf = new char[len];
01212    NetRecvRaw(buf, len);
01213 
01214    if (!RootdIsOpen() || !gWritable)
01215       Error(ErrFatal, kErrNoAccess, "RootdPut: file %s not opened in write mode", gFile);
01216 
01217 #if defined (R__SEEK64)
01218    if (lseek64(gFd, offset, SEEK_SET) < 0)
01219 #elif defined(WIN32)
01220    if (_lseeki64(gFd, offset, SEEK_SET) < 0)
01221 #else
01222    if (lseek(gFd, offset, SEEK_SET) < 0)
01223 #endif
01224       Error(ErrSys, kErrFilePut, "RootdPut: cannot seek to position %lld in file %s", offset, gFile);
01225 
01226    ssize_t siz;
01227    while ((siz = write(gFd, buf, len)) < 0 && GetErrno() == EINTR)
01228       ResetErrno();
01229 
01230    if (siz < 0)
01231       Error(ErrSys, kErrFilePut, "RootdPut: error writing to file %s", gFile);
01232 
01233    if (siz != len)
01234       Error(ErrFatal, kErrFilePut, "RootdPut: error writing all requested bytes to file %s, wrote %d of %d",
01235             gFile, siz, len);
01236 
01237    NetSend(0, kROOTD_PUT);
01238 
01239    delete [] buf;
01240 
01241    gBytesWritten += len;
01242 
01243    if (gDebug > 0)
01244       ErrorInfo("RootdPut: written %d bytes starting at %lld to file %s",
01245                 len, offset, gFile);
01246 }
01247 
01248 //______________________________________________________________________________
01249 void RootdGet(const char *msg)
01250 {
01251    // Get a buffer from the specified offset from the currently open file
01252    // and send it to the client.
01253 
01254    Long64_t offset;
01255    int      len;
01256 
01257    sscanf(msg, "%lld %d", &offset, &len);
01258 
01259    char *buf = new char[len];
01260 
01261    if (!RootdIsOpen())
01262       Error(ErrFatal, kErrNoAccess, "RootdGet: file %s not open", gFile);
01263 
01264 #if defined (R__SEEK64)
01265    if (lseek64(gFd, offset, SEEK_SET) < 0)
01266 #elif defined(WIN32)
01267    if (_lseeki64(gFd, offset, SEEK_SET) < 0)
01268 #else
01269    if (lseek(gFd, offset, SEEK_SET) < 0)
01270 #endif
01271       Error(ErrSys, kErrFileGet, "RootdGet: cannot seek to position %lld in"
01272             " file %s", offset, gFile);
01273 
01274    ssize_t siz;
01275    while ((siz = read(gFd, buf, len)) < 0 && GetErrno() == EINTR)
01276       ResetErrno();
01277 
01278    if (siz < 0)
01279       Error(ErrSys, kErrFileGet, "RootdGet: error reading from file %s", gFile);
01280 
01281    if (siz != len)
01282       Error(ErrFatal, kErrFileGet, "RootdGet: error reading all requested bytes"
01283             " from file %s, got %d of %d",gFile, siz, len);
01284 
01285    NetSend(0, kROOTD_GET);
01286 
01287    NetSendRaw(buf, len);
01288 
01289    delete [] buf;
01290 
01291    gBytesRead += len;
01292 
01293    if (gDebug > 0)
01294       ErrorInfo("RootdGet: read %d bytes starting at %lld from file %s",
01295                 len, offset, gFile);
01296 }
01297 
01298 //______________________________________________________________________________
01299 void RootdGets(const char *msg)
01300 {
01301    // Gets multiple buffers from the specified list of offsets and lengths from
01302    // the currently open file and send it to the client in a single buffer.
01303    // (BUt rem it gets the buffer with the info in the same way it would get
01304    // new data)
01305 
01306    if (!RootdIsOpen())
01307       Error(ErrFatal, kErrNoAccess, "RootdGets: file %s not open", gFile);
01308 
01309    Int_t nbuf;      // Number of buffers
01310    Int_t len;       // len of the data buffer with the list of buffers
01311    Int_t npar;      // compatibility issues
01312    Int_t size;      // size of the readv block (all the small reads)
01313    Int_t maxTransz; // blocksize for the transfer
01314 
01315    npar = sscanf(msg, "%d %d %d", &nbuf, &len, &maxTransz);
01316 
01317    Long64_t *offsets = new Long64_t[nbuf];  // list to be filled
01318    Int_t    *lens    = new Int_t[nbuf];     // list to be filled
01319    char     *buf_in  = new char[len+1];     // buff coming from the server
01320 
01321    NetRecvRaw(buf_in, len);
01322    buf_in[len] = '\0';
01323 
01324    char *ptr = buf_in;
01325    size = 0;
01326    for(Int_t i = 0 ; i < nbuf ; i++) {
01327       sscanf(ptr, "%llu-%d/", &offsets[i], &lens[i]);
01328       ptr = strchr(ptr, '/') + 1;
01329       size += lens[i];
01330    }
01331 
01332    // If the blocksize is not specified the try to send
01333    // just a big block
01334    if( npar == 2  )
01335       maxTransz = size;
01336 
01337    // We are Ready to begin the transference
01338    NetSend(0, kROOTD_GETS);
01339 
01340    char *buf_out  = new char[maxTransz];
01341    char *buf_send = new char[maxTransz];
01342    Int_t actual_pos = 0; // position for the whole size
01343    Int_t buf_pos    = 0; // position in the buffer
01344    ssize_t siz = 0;
01345 
01346    for (Int_t i = 0; i < nbuf; i++) {
01347       Long64_t left = size - actual_pos;
01348       if (left > maxTransz)
01349          left = maxTransz;
01350 
01351       Int_t pos = 0; // Position for the disk read
01352       while ( pos < lens[i] ) {
01353 #if defined (R__SEEK64)
01354          if (lseek64(gFd, offsets[i] + pos, SEEK_SET) < 0)
01355 #elif defined(WIN32)
01356          if (_lseeki64(gFd, offsets[i] + pos, SEEK_SET) < 0)
01357 #else
01358          if (lseek(gFd, offsets[i] + pos, SEEK_SET) < 0)
01359 #endif
01360          Error(ErrSys, kErrFileGet, "RootdGets: cannot seek to position %lld in"
01361             " file %s", offsets[i], gFile);
01362 
01363          Int_t readsz = lens[i] - pos;
01364          if( readsz > ( left - buf_pos) )
01365             readsz = left - buf_pos;
01366 
01367          while ((siz = read(gFd, buf_out + buf_pos, readsz)) < 0 && GetErrno() == EINTR)
01368             ResetErrno();
01369 
01370          if (siz != readsz)
01371             goto end;
01372 
01373          pos += readsz;
01374          buf_pos += readsz;
01375          if ( buf_pos == left ) {
01376             if (gDebug > 0 )
01377                ErrorInfo("RootdGets: Sending %d bytes", left);
01378 
01379             // Swap buffers
01380             char *buf_tmp = buf_out;
01381             buf_out = buf_send;
01382             buf_send = buf_tmp;
01383 
01384             NetSendRaw(buf_send, left);
01385             actual_pos += left;
01386             buf_pos = 0;
01387 
01388             if ( left > (size - actual_pos) )
01389                left = size - actual_pos;
01390          }
01391       }
01392    }
01393 
01394 end:
01395    if (siz < 0)
01396       Error(ErrSys, kErrFileGet, "RootdGets: error reading from file %s", gFile);
01397 
01398    if (actual_pos != size)
01399       Error(ErrFatal, kErrFileGet, "RootdGets: error reading all requested bytes"
01400             " from file %s, got %d of %d",gFile, actual_pos, size);
01401 
01402    delete [] buf_in;
01403    delete [] buf_out;
01404    delete [] buf_send;
01405    delete [] lens;
01406    delete [] offsets;
01407 
01408    gBytesRead += actual_pos;
01409 
01410    if (gDebug > 0)
01411       ErrorInfo("RootdGets: read %d bytes from file %s",
01412                 actual_pos, gFile);
01413 }
01414 
01415 //______________________________________________________________________________
01416 void RootdPutFile(const char *msg)
01417 {
01418    // Receive a file from the remote client (upload).
01419 
01420    char     file[kMAXPATHLEN];
01421    Long64_t size, restartat;
01422    int      blocksize, mode, forceopen = 0;
01423 
01424    gFtp = 1;   // rootd is used for ftp instead of file serving
01425 
01426    sscanf(msg, "%s %d %d %lld %lld", file, &blocksize, &mode, &size, &restartat);
01427 
01428    if (file[0] == '-') {
01429       forceopen = 1;
01430       strlcpy(gFile, file+1, sizeof(gFile));
01431    } else
01432       strlcpy(gFile, file, sizeof(gFile));
01433 
01434    // anon user may not overwrite existing files...
01435    struct stat st;
01436    if (!stat(gFile, &st)) {
01437       if (gAnon) {
01438          Error(Err, kErrFileExists, "RootdPutFile: anonymous users may not overwrite existing file %s", gFile);
01439          return;
01440       }
01441    } else if (GetErrno() != ENOENT) {
01442       Error(Err, kErrFatal, "RootdPutFile: can't check for file presence");
01443       return;
01444    }
01445 
01446    // remove lock from file
01447    if (restartat || forceopen)
01448       RootdCloseTab(1);
01449 
01450    // open local file
01451    int fd;
01452    if (!restartat) {
01453 
01454       // make sure file exists so RootdCheckTab works correctly
01455 #ifndef WIN32
01456       fd = SysOpen(gFile, O_RDWR | O_CREAT, 0600);
01457 #else
01458       fd = SysOpen(gFile, O_RDWR | O_CREAT | O_BINARY, S_IREAD | S_IWRITE);
01459 #endif
01460       if (fd < 0) {
01461          Error(Err, kErrFileOpen, "RootdPutFile: cannot open file %s", gFile);
01462          return;
01463       }
01464 
01465       close(fd);
01466 
01467       // check if file is not in use by somebody and prevent from somebody
01468       // using it before upload is completed
01469       if (!RootdCheckTab(1)) {
01470          Error(Err, kErrFileWriteOpen, "RootdPutFile: file %s already opened in read or write mode", gFile);
01471          return;
01472       }
01473 
01474 #ifndef WIN32
01475       fd = SysOpen(gFile, O_CREAT | O_TRUNC | O_WRONLY, 0600);
01476 #else
01477       if (mode == kBinary)
01478          fd = SysOpen(gFile, O_CREAT | O_TRUNC | O_WRONLY | O_BINARY,
01479                       S_IREAD | S_IWRITE);
01480       else
01481          fd = SysOpen(gFile, O_CREAT | O_TRUNC | O_WRONLY,
01482                       S_IREAD | S_IWRITE);
01483 #endif
01484    } else {
01485 #ifndef WIN32
01486       fd = SysOpen(gFile, O_WRONLY, 0600);
01487 #else
01488       if (mode == kBinary)
01489          fd = SysOpen(gFile, O_WRONLY | O_BINARY, S_IREAD | S_IWRITE);
01490       else
01491          fd = SysOpen(gFile, O_WRONLY, S_IREAD | S_IWRITE);
01492 #endif
01493       if (fd < 0) {
01494          Error(Err, kErrFileOpen, "RootdPutFile: cannot open file %s", gFile);
01495          return;
01496       }
01497       if (!RootdCheckTab(1)) {
01498          close(fd);
01499          Error(Err, kErrFileWriteOpen, "RootdPutFile: file %s already opened in read or write mode", gFile);
01500          return;
01501       }
01502    }
01503 
01504    // check file system space
01505    if (strcmp(gFile, "/dev/null")) {
01506       struct statfs statfsbuf;
01507 #if defined(__sgi) || (defined(__sun) && !defined(linux))
01508       if (fstatfs(fd, &statfsbuf, sizeof(struct statfs), 0) == 0) {
01509          Long64_t space = (Long64_t)statfsbuf.f_bsize * (Long64_t)statfsbuf.f_bfree;
01510 #else
01511       if (fstatfs(fd, &statfsbuf) == 0) {
01512          Long64_t space = (Long64_t)statfsbuf.f_bsize * (Long64_t)statfsbuf.f_bavail;
01513 #endif
01514          if (space < size - restartat) {
01515             Error(Err, kErrNoSpace, "RootdPutFile: not enough space to store file %s", gFile);
01516             close(fd);
01517             return;
01518          }
01519       }
01520    }
01521 
01522    // seek to restartat position
01523    if (restartat) {
01524 #if defined(R__SEEK64)
01525       if (lseek64(fd, restartat, SEEK_SET) < 0) {
01526 #elif defined(WIN32)
01527       if (_lseeki64(fd, restartat, SEEK_SET) < 0) {
01528 #else
01529       if (lseek(fd, restartat, SEEK_SET) < 0) {
01530 #endif
01531          Error(Err, kErrRestartSeek, "RootdPutFile: cannot seek to position %lld in file %s",
01532                restartat, gFile);
01533          close(fd);
01534          return;
01535       }
01536    }
01537 
01538    // setup ok
01539    NetSend(0, kROOTD_PUTFILE);
01540 
01541    struct timeval started, ended;
01542    gettimeofday(&started, 0);
01543 
01544    char *buf = new char[blocksize];
01545    char *buf2 = 0;
01546    if (mode == 1)
01547       buf2 = new char[blocksize];
01548 
01549    Long64_t pos = restartat & ~(blocksize-1);
01550    int skip = restartat - pos;
01551 
01552    while (pos < size) {
01553       Long64_t left = Long64_t(size - pos);
01554       if (left > blocksize)
01555          left = blocksize;
01556 
01557       NetRecvRaw(buf, int(left-skip));
01558 
01559       int n = int(left-skip);
01560 
01561       // in case of ascii file, loop here over buffer and remove \r's
01562       ssize_t siz;
01563       if (mode == kAscii) {
01564          int i = 0, j = 0;
01565          while (i < n) {
01566             if (buf[i] == '\r')
01567                i++;
01568             else
01569                buf2[j++] = buf[i++];
01570          }
01571          n = j;
01572          while ((siz = write(fd, buf2, n)) < 0 && GetErrno() == EINTR)
01573             ResetErrno();
01574       } else {
01575          while ((siz = write(fd, buf, n)) < 0 && GetErrno() == EINTR)
01576             ResetErrno();
01577       }
01578 
01579       if (siz < 0)
01580          Error(ErrSys, kErrFilePut, "RootdPutFile: error writing to file %s", gFile);
01581 
01582       if (siz != n)
01583          Error(ErrFatal, kErrFilePut, "RootdPutFile: error writing all requested bytes to file %s, wrote %d of %d",
01584                gFile, siz, int(left-skip));
01585 
01586       gBytesWritten += n;
01587 
01588       pos += left;
01589       skip = 0;
01590    }
01591 
01592    gettimeofday(&ended, 0);
01593 
01594    // file stored ok
01595    NetSend(0, kROOTD_PUTFILE);
01596 
01597    delete [] buf; delete [] buf2;
01598 
01599    fchmod(fd, 0644);
01600 
01601    close(fd);
01602 
01603    RootdCloseTab();
01604 
01605    gUploaded++;
01606 
01607    double speed, t;
01608    t = (ended.tv_sec + ended.tv_usec / 1000000.0) -
01609        (started.tv_sec + started.tv_usec / 1000000.0);
01610    if (t > 0)
01611       speed = double(size - restartat) / t;
01612    else
01613       speed = 0.0;
01614    if (speed > 524288)
01615       ErrorInfo("RootdPutFile: uploaded file %s (%lld bytes, %.3f seconds, "
01616                 "%.2f Mbytes/s)", gFile, size, t, speed / 1048576);
01617    else if (speed > 512)
01618       ErrorInfo("RootdPutFile: uploaded file %s (%lld bytes, %.3f seconds, "
01619                 "%.2f Kbytes/s)", gFile, size, t, speed / 1024);
01620    else
01621       ErrorInfo("RootdPutFile: uploaded file %s (%lld bytes, %.3f seconds, "
01622                 "%.2f bytes/s)", gFile, size, t, speed);
01623 }
01624 
01625 //______________________________________________________________________________
01626 void RootdGetFile(const char *msg)
01627 {
01628    // Send a file to a remote client (download).
01629 
01630    char     file[kMAXPATHLEN];
01631    Long64_t restartat;
01632    int      blocksize, mode, forceopen = 0;
01633 
01634    gFtp = 1;   // rootd is used for ftp instead of file serving
01635 
01636    sscanf(msg, "%s %d %d %lld", file, &blocksize, &mode, &restartat);
01637 
01638    if (file[0] == '-') {
01639       forceopen = 1;
01640       strlcpy(gFile, file+1, sizeof(gFile));
01641    } else
01642       strlcpy(gFile, file, sizeof(gFile));
01643 
01644    // remove lock from file
01645    if (forceopen)
01646       RootdCloseTab(1);
01647 
01648    // open file for reading
01649 #if defined(WIN32) || defined(R__WINGCC)
01650    int fd = SysOpen(gFile, O_RDONLY | O_BINARY, S_IREAD | S_IWRITE);
01651 #else
01652    int fd = SysOpen(gFile, O_RDONLY, 0600);
01653 #endif
01654    if (fd < 0) {
01655       Error(Err, kErrFileOpen, "RootdGetFile: cannot open file %s", gFile);
01656       return;
01657    }
01658 
01659    // check if file is not in use by somebody and prevent from somebody
01660    // using it before download is completed
01661    if (!RootdCheckTab(0)) {
01662       close(fd);
01663       Error(Err, kErrFileOpen, "RootdGetFile: file %s is already open in write mode", gFile);
01664       return;
01665    }
01666 
01667 #if defined(R__SEEK64)
01668    struct stat64 st;
01669    if (fstat64(fd, &st)) {
01670 #elif defined(WIN32)
01671    struct _stati64 st;
01672    if (_fstati64(fd, &st)) {
01673 #else
01674    struct stat st;
01675    if (fstat(fd, &st)) {
01676 #endif
01677       Error(Err, kErrFatal, "RootdGetFile: cannot get size of file %s", gFile);
01678       close(fd);
01679       return;
01680    }
01681    Long64_t size = st.st_size;
01682 
01683    if (!S_ISREG(st.st_mode)) {
01684       Error(Err, kErrBadFile, "RoodGetFile: not a regular file %s", gFile);
01685       close(fd);
01686       return;
01687    }
01688 
01689    // check if restartat value makes sense
01690    if (restartat && (restartat >= size))
01691       restartat = 0;
01692 
01693    // setup ok
01694    NetSend(0, kROOTD_GETFILE);
01695 
01696    char mess[128];
01697    SPrintf(mess, 128, "%lld", size);
01698    NetSend(mess, kROOTD_GETFILE);
01699 
01700    struct timeval started, ended;
01701    gettimeofday(&started, 0);
01702 
01703    Long64_t pos  = restartat & ~(blocksize-1);
01704    int  skip = int(restartat - pos);
01705 
01706 #ifndef HAVE_MMAP
01707    char *buf = new char[blocksize];
01708 #if defined(R__SEEK64)
01709    lseek64(fd, pos, SEEK_SET);
01710 #elif defined(WIN32)
01711    _lseeki64(fd, pos, SEEK_SET);
01712 #else
01713    lseek(fd, pos, SEEK_SET);
01714 #endif
01715 #endif
01716 
01717    while (pos < size) {
01718       Long64_t left = size - pos;
01719       if (left > blocksize)
01720          left = blocksize;
01721 #ifdef HAVE_MMAP
01722 #if defined(R__SEEK64)
01723       char *buf = (char*) mmap64(0, left, PROT_READ, MAP_FILE | MAP_SHARED, fd, pos);
01724 #else
01725       char *buf = (char*) mmap(0, left, PROT_READ, MAP_FILE | MAP_SHARED, fd, pos);
01726 #endif
01727       if (buf == (char *) -1)
01728          Error(ErrFatal, kErrFileGet, "RootdGetFile: mmap of file %s failed", gFile);
01729 #else
01730       int siz;
01731       while ((siz = read(fd, buf, (int)left)) < 0 && GetErrno() == EINTR)
01732          ResetErrno();
01733       if (siz < 0 || siz != left)
01734          Error(ErrFatal, kErrFileGet, "RootdGetFile: error reading from file %s", gFile);
01735 #endif
01736 
01737       NetSendRaw(buf+skip, int(left-skip));
01738 
01739       gBytesRead += left-skip;
01740 
01741       pos += left;
01742       skip = 0;
01743 
01744 #ifdef HAVE_MMAP
01745       munmap(buf, left);
01746 #endif
01747    }
01748 
01749    gettimeofday(&ended, 0);
01750 
01751 #ifndef HAVE_MMAP
01752    delete [] buf;
01753 #endif
01754 
01755    close(fd);
01756 
01757    RootdCloseTab();
01758 
01759    gDownloaded++;
01760 
01761    double speed, t;
01762    t = (ended.tv_sec + ended.tv_usec / 1000000.0) -
01763        (started.tv_sec + started.tv_usec / 1000000.0);
01764    if (t > 0)
01765       speed = double(size - restartat) / t;
01766    else
01767       speed = 0.0;
01768    if (speed > 524288)
01769       ErrorInfo("RootdGetFile: downloaded file %s (%lld bytes, %.3f seconds, "
01770                 "%.2f Mbytes/s)", gFile, size, t, speed / 1048576);
01771    else if (speed > 512)
01772       ErrorInfo("RootdGetFile: downloaded file %s (%lld bytes, %.3f seconds, "
01773                 "%.2f Kbytes/s)", gFile, size, t, speed / 1024);
01774    else
01775       ErrorInfo("RootdGetFile: downloaded file %s (%lld bytes, %.3f seconds, "
01776                 "%.2f bytes/s)", gFile, size, t, speed);
01777 }
01778 
01779 //______________________________________________________________________________
01780 void RootdChdir(const char *dir)
01781 {
01782    // Change directory.
01783 
01784    const int kMAXBUFLEN = kMAXPATHLEN + 256;
01785    char buffer[kMAXBUFLEN];
01786 
01787    if (dir && *dir == '~') {
01788       struct passwd *pw;
01789       int i = 0;
01790       const char *p = dir;
01791 
01792       p++;
01793       while (*p && *p != '/')
01794          buffer[i++] = *p++;
01795       buffer[i] = 0;
01796 
01797       if ((pw = getpwnam(i ? buffer : gUser.c_str())))
01798          SPrintf(buffer, kMAXBUFLEN, "%s%s", pw->pw_dir, p);
01799       else
01800          *buffer = 0;
01801    } else
01802       *buffer = 0;
01803 
01804    if (chdir(*buffer ? buffer : (dir && *dir ? dir : "/")) == -1) {
01805       SPrintf(buffer,kMAXBUFLEN,"cannot change directory to %s",dir);
01806       Perror(buffer,kMAXBUFLEN);
01807       NetSend(buffer, kROOTD_CHDIR);
01808       return;
01809    } else {
01810       FILE *msg;
01811 
01812       if ((msg = fopen(".message", "r"))) {
01813          int len = fread(buffer, 1, kMAXPATHLEN, msg);
01814          fclose(msg);
01815          if (len > 0 && len < 1024) {
01816             buffer[len] = 0;
01817             NetSend(buffer, kMESS_STRING);
01818          }
01819       }
01820 
01821       if (!getcwd(buffer, kMAXPATHLEN)) {
01822          if (dir && *dir == '/')
01823             SPrintf(buffer, kMAXBUFLEN, "%s", dir);
01824       }
01825       NetSend(buffer, kROOTD_CHDIR);
01826    }
01827 }
01828 
01829 //______________________________________________________________________________
01830 void RootdAccess(const char *buf)
01831 {
01832    // Test access permission on path
01833 
01834    char buffer[kMAXPATHLEN];
01835    char path[kMAXPATHLEN];
01836    int mode;
01837 
01838    int nw = 0;
01839    if (buf)
01840       nw = sscanf(buf,"%s %d",path,&mode);
01841 
01842    if (nw >= 2) {
01843 
01844       char *epath = &path[0];
01845       if (path[0] == '/' && path[1] == '/')
01846          epath = &path[1];
01847 
01848       if (access(epath, mode) == -1) {
01849          SPrintf(buffer,kMAXPATHLEN,"cannot stat %s",epath);
01850          Perror(buffer);
01851          ErrorInfo("RootdAccess: %s", buffer);
01852       } else
01853          SPrintf(buffer,kMAXPATHLEN,"OK");
01854 
01855    } else {
01856       SPrintf(buffer,kMAXPATHLEN,"bad input format %s",buf);
01857       ErrorInfo("RootdAccess: %s", buffer);
01858    }
01859 
01860    NetSend(buffer, kROOTD_ACCESS);
01861 }
01862 
01863 
01864 //______________________________________________________________________________
01865 void RootdFreeDir()
01866 {
01867    // Free open directory.
01868 
01869    char buffer[kMAXPATHLEN];
01870 
01871    if (!gRDDirectory) {
01872       SPrintf(buffer,kMAXPATHLEN,"no directory open");
01873       ErrorInfo("RootdFreeDir: %s", buffer);
01874    } else if (closedir(gRDDirectory) == -1) {
01875       SPrintf(buffer,kMAXPATHLEN,"cannot free open directory");
01876       Perror(buffer);
01877       ErrorInfo("RootdFreeDir: %s", buffer);
01878    } else
01879       SPrintf(buffer,kMAXPATHLEN,"open directory freed");
01880 
01881    NetSend(buffer, kROOTD_FREEDIR);
01882 }
01883 
01884 //______________________________________________________________________________
01885 void RootdGetDirEntry()
01886 {
01887    // Get directory entry.
01888 
01889    char buffer[kMAXPATHLEN];
01890    struct dirent *dp = 0;
01891 
01892    if (!gRDDirectory) {
01893       SPrintf(buffer,kMAXPATHLEN,"no directory open");
01894       ErrorInfo("RootdGetDirEntry: %s", buffer);
01895    } else if ((dp = readdir(gRDDirectory)) == 0) {
01896       if (GetErrno() == EBADF) {
01897          SPrintf(buffer,kMAXPATHLEN,"cannot read open directory");
01898          Perror(buffer);
01899          ErrorInfo("RootdGetDirEntry: %s", buffer);
01900       } else
01901          SPrintf(buffer,kMAXPATHLEN,"no more entries");
01902    } else {
01903       SPrintf(buffer,kMAXPATHLEN,"OK:%s",dp->d_name);
01904    }
01905 
01906    NetSend(buffer, kROOTD_DIRENTRY);
01907 }
01908 
01909 //______________________________________________________________________________
01910 void RootdOpenDir(const char *dir)
01911 {
01912    // Open directory.
01913 
01914    char buffer[kMAXPATHLEN];
01915 
01916    char *edir = (char *)dir;
01917    if (dir[0] == '/' && dir[1] == '/')
01918       edir++;
01919 
01920    if ((gRDDirectory = opendir(edir)) == 0) {
01921       SPrintf(buffer,kMAXPATHLEN,"cannot open directory %s",edir);
01922       Perror(buffer);
01923       ErrorInfo("RootdOpenDir: %s", buffer);
01924    } else
01925       SPrintf(buffer,kMAXPATHLEN,"OK: directory %s open",edir);
01926 
01927    NetSend(buffer, kROOTD_OPENDIR);
01928 }
01929 
01930 //______________________________________________________________________________
01931 void RootdMkdir(const char *fdir)
01932 {
01933    // Make directory.
01934 
01935    char buffer[kMAXPATHLEN];
01936 
01937    char *dir = (char *)fdir;
01938    if (fdir[0] == '/' && fdir[1] == '/')
01939       dir++;
01940 
01941    if (gAnon) {
01942       SPrintf(buffer,kMAXPATHLEN,
01943               "anonymous users may not create directories");
01944       ErrorInfo("RootdMkdir: %s", buffer);
01945    } else if (mkdir(dir, 0755) < 0) {
01946       SPrintf(buffer,kMAXPATHLEN,"cannot create directory %s",dir);
01947       Perror(buffer);
01948       ErrorInfo("RootdMkdir: %s", buffer);
01949    } else
01950       SPrintf(buffer,kMAXPATHLEN,"OK: created directory %s",dir);
01951 
01952    NetSend(buffer, kROOTD_MKDIR);
01953 }
01954 
01955 //______________________________________________________________________________
01956 void RootdRmdir(const char *fdir)
01957 {
01958    // Delete directory.
01959 
01960    char buffer[kMAXPATHLEN];
01961 
01962    char *dir = (char *)fdir;
01963    if (fdir[0] == '/' && fdir[1] == '/')
01964       dir++;
01965 
01966    if (gAnon) {
01967       SPrintf(buffer,kMAXPATHLEN,
01968               "anonymous users may not delete directories");
01969       ErrorInfo("RootdRmdir: %s", buffer);
01970    } else if (rmdir(dir) < 0) {
01971       SPrintf(buffer, kMAXPATHLEN, "cannot delete directory %s", dir);
01972       Perror(buffer);
01973       ErrorInfo("RootdRmdir: %s", buffer);
01974    } else
01975       SPrintf(buffer, kMAXPATHLEN, "deleted directory %s", dir);
01976 
01977    NetSend(buffer, kROOTD_RMDIR);
01978 }
01979 
01980 //______________________________________________________________________________
01981 void RootdLsdir(const char *cmd)
01982 {
01983    // List directory.
01984 
01985    char buffer[kMAXPATHLEN];
01986 
01987    // make sure all commands start with ls (should use snprintf)
01988    if (gAnon) {
01989       if (strlen(cmd) < 2 || strncmp(cmd, "ls", 2))
01990          SPrintf(buffer, kMAXPATHLEN, "ls %s", cmd);
01991       else
01992          SPrintf(buffer, kMAXPATHLEN, "%s", cmd);
01993    } else {
01994       if (strlen(cmd) < 2 || strncmp(cmd, "ls", 2))
01995          SPrintf(buffer, kMAXPATHLEN, "ls %s 2>/dev/null", cmd);
01996       else
01997          SPrintf(buffer, kMAXPATHLEN, "%s 2>/dev/null", cmd);
01998    }
01999 
02000    FILE *pf;
02001    if ((pf = popen(buffer, "r")) == 0) {
02002       SPrintf(buffer,kMAXPATHLEN, "error in popen");
02003       Perror(buffer);
02004       NetSend(buffer, kROOTD_LSDIR);
02005       ErrorInfo("RootdLsdir: %s", buffer);
02006       return;
02007    }
02008 
02009    // read output of ls
02010    int  ch, i = 0, cnt = 0;
02011 //again:
02012    for (ch = fgetc(pf); ch != EOF; ch = fgetc(pf)) {
02013       buffer[i++] = ch;
02014       cnt++;
02015       if (i == kMAXPATHLEN-1) {
02016          buffer[i] = 0;
02017          NetSend(buffer, kMESS_STRING);
02018          i = 0;
02019       }
02020    }
02021    // this will be true if forked process was not yet ready to be read
02022 //   if (cnt == 0 && ch == EOF) goto again;
02023 
02024    pclose(pf);
02025 
02026    buffer[i] = 0;
02027    NetSend(buffer, kROOTD_LSDIR);
02028 }
02029 
02030 //______________________________________________________________________________
02031 void RootdPwd()
02032 {
02033    // Print path of working directory.
02034 
02035    char buffer[kMAXPATHLEN];
02036 
02037    if (!getcwd(buffer, kMAXPATHLEN)) {
02038       SPrintf(buffer, kMAXPATHLEN, "current directory not readable");
02039       Perror(buffer);
02040       ErrorInfo("RootdPwd: %s", buffer);
02041    }
02042 
02043    NetSend(buffer, kROOTD_PWD);
02044 }
02045 
02046 //______________________________________________________________________________
02047 void RootdMv(const char *msg)
02048 {
02049    // Rename a file.
02050 
02051    char file1[kMAXPATHLEN], file2[kMAXPATHLEN], buffer[kMAXPATHLEN];
02052    sscanf(msg, "%s %s", file1, file2);
02053 
02054    if (gAnon) {
02055       SPrintf(buffer, kMAXPATHLEN, "anonymous users may not rename files");
02056       ErrorInfo("RootdMv: %s", buffer);
02057    } else if (rename(file1, file2) < 0) {
02058       SPrintf(buffer, kMAXPATHLEN, "cannot rename file %s to %s",
02059               file1, file2);
02060       Perror(buffer);
02061       ErrorInfo("RootdMv: %s", buffer);
02062    } else
02063       SPrintf(buffer, kMAXPATHLEN, "renamed file %s to %s",
02064               file1, file2);
02065 
02066    NetSend(buffer, kROOTD_MV);
02067 }
02068 
02069 //______________________________________________________________________________
02070 void RootdRm(const char *file)
02071 {
02072    // Delete a file.
02073 
02074    char buffer[kMAXPATHLEN];
02075 
02076    if (gAnon) {
02077       SPrintf(buffer, kMAXPATHLEN, "anonymous users may not delete files");
02078       ErrorInfo("RootdRm: %s", buffer);
02079    } else if (unlink(file) < 0) {
02080       SPrintf(buffer, kMAXPATHLEN, "cannot unlink file %s", file);
02081       Perror(buffer);
02082       ErrorInfo("RootdRm: %s", buffer);
02083    } else
02084       SPrintf(buffer, kMAXPATHLEN, "removed file %s", file);
02085 
02086    NetSend(buffer, kROOTD_RM);
02087 }
02088 
02089 //______________________________________________________________________________
02090 void RootdChmod(const char *msg)
02091 {
02092    // Delete a file.
02093 
02094    char file[kMAXPATHLEN], buffer[kMAXPATHLEN];
02095    int  mode;
02096 
02097    sscanf(msg, "%s %d", file, &mode);
02098 
02099    if (gAnon) {
02100       SPrintf(buffer, kMAXPATHLEN,
02101               "anonymous users may not change file permissions");
02102       ErrorInfo("RootdChmod: %s", buffer);
02103    } else if (chmod(file, mode) < 0) {
02104       SPrintf(buffer, kMAXPATHLEN, "cannot chmod file %s to 0%o", file, mode);
02105       Perror(buffer);
02106       ErrorInfo("RootdChmod: %s", buffer);
02107    } else
02108       SPrintf(buffer, kMAXPATHLEN, "changed permission of file %s to 0%o",
02109               file, mode);
02110 
02111    NetSend(buffer, kROOTD_CHMOD);
02112 }
02113 
02114 //______________________________________________________________________________
02115 static void RootdTerm(int)
02116 {
02117    // Termination upon receipt of a SIGTERM or SIGINT.
02118 
02119    ErrorInfo("RootdTerm: rootd.cxx: got a SIGTERM/SIGINT");
02120    // Terminate properly
02121    RpdAuthCleanup(0,0);
02122    // Close network connection
02123    NetClose();
02124    // exit
02125    exit(0);
02126 }
02127 
02128 //______________________________________________________________________________
02129 void RootdLoop()
02130 {
02131    // Handle all rootd commands. Returns after file close command.
02132 
02133    char recvbuf[kMAXRECVBUF];
02134    EMessageTypes kind;
02135 
02136 //#define R__ROOTDDBG
02137 #ifdef R__ROOTDDBG
02138    int debug = 1;
02139    while (debug)
02140       ;
02141 #endif
02142 
02143    // Check if we will go for parallel sockets
02144    // (in early days was done before entering main loop)
02145    if (gClientProtocol > 9)
02146       RootdParallel();
02147 
02148    // Main loop
02149    while (1) {
02150 
02151       if (NetRecv(recvbuf, kMAXRECVBUF, kind) < 0)
02152          Error(ErrFatal, kErrFatal, "RootdLoop: error receiving message");
02153 
02154       if (gDebug > 2 && kind != kROOTD_PASS)
02155          ErrorInfo("RootdLoop: kind:%d -- buf:'%s' (len:%d)",
02156                    kind, recvbuf, strlen(recvbuf));
02157 
02158       switch (kind) {
02159          case kROOTD_OPEN:
02160             RootdOpen(recvbuf);
02161             break;
02162          case kROOTD_PUT:
02163             RootdPut(recvbuf);
02164             break;
02165          case kROOTD_GET:
02166             RootdGet(recvbuf);
02167             break;
02168          case kROOTD_GETS:
02169             RootdGets(recvbuf);
02170             break;
02171          case kROOTD_FLUSH:
02172             RootdFlush();
02173             break;
02174          case kROOTD_CLOSE:
02175             RootdClose();
02176             if (gClientProtocol < 7)
02177                return;
02178             break;
02179          case kROOTD_FSTAT:
02180             RootdFstat(recvbuf);
02181             break;
02182          case kROOTD_STAT:
02183             RootdStat();
02184             break;
02185          case kROOTD_PUTFILE:
02186             RootdPutFile(recvbuf);
02187             break;
02188          case kROOTD_GETFILE:
02189             RootdGetFile(recvbuf);
02190             break;
02191          case kROOTD_CHDIR:
02192             RootdChdir(recvbuf);
02193             break;
02194          case kROOTD_MKDIR:
02195             RootdMkdir(recvbuf);
02196             break;
02197          case kROOTD_RMDIR:
02198             RootdRmdir(recvbuf);
02199             break;
02200          case kROOTD_LSDIR:
02201             RootdLsdir(recvbuf);
02202             break;
02203          case kROOTD_PWD:
02204             RootdPwd();
02205             break;
02206          case kROOTD_MV:
02207             RootdMv(recvbuf);
02208             break;
02209          case kROOTD_RM:
02210             RootdRm(recvbuf);
02211             break;
02212          case kROOTD_CHMOD:
02213             RootdChmod(recvbuf);
02214             break;
02215          case kROOTD_OPENDIR:
02216             RootdOpenDir(recvbuf);
02217             break;
02218          case kROOTD_FREEDIR:
02219             RootdFreeDir();
02220             break;
02221          case kROOTD_DIRENTRY:
02222             RootdGetDirEntry();
02223             break;
02224          case kROOTD_ACCESS:
02225             RootdAccess(recvbuf);
02226             break;
02227          case kROOTD_BYE:
02228             return;
02229          default:
02230             Error(ErrFatal, kErrBadOp, "RootdLoop: received bad opcode %d", kind);
02231       }
02232       continue;
02233    }
02234 }
02235 
02236 //______________________________________________________________________________
02237 void Usage(const char* name, int rc)
02238 {
02239    fprintf(stderr, "\nUsage: %s [options] [rootsys-dir]\n", name);
02240    fprintf(stderr, "\nOptions:\n");
02241    fprintf(stderr, "\t-b tcpwindowsize  Specify the tcp window size in bytes\n");
02242 #ifdef R__GLBS
02243    fprintf(stderr, "\t-C hostcertfile   Specify the location of the Globus host certificate\n");
02244 #endif
02245    fprintf(stderr, "\t-d level          set debug level [0..3]\n");
02246    fprintf(stderr, "\t-D rootdaemonrc   Use alternate rootdaemonrc file\n");
02247    fprintf(stderr, "\t                  (see documentation)\n");
02248    fprintf(stderr, "\t-E                Ignored for backward compatibility\n");
02249    fprintf(stderr, "\t-f                Run in foreground\n");
02250 #ifdef R__GLBS
02251    fprintf(stderr, "\t-G gridmapfile    Specify the location of th Globus gridmap\n");
02252 #endif
02253    fprintf(stderr, "\t-i                Running from inetd\n");
02254    fprintf(stderr, "\t-noauth           Do not require client authentication\n");
02255    fprintf(stderr, "\t-p port#          Specify a different port to listen on\n");
02256    fprintf(stderr, "\t-P pwfile         Use pwfile instead of .srootdpass\n");
02257    fprintf(stderr, "\t-r                Files can only be opened in read-only mode\n");
02258    fprintf(stderr, "\t-R bitmask        Bitmask specifies which methods allow authentication re-use\n");
02259    fprintf(stderr, "\t-s sshd_port#     Specify the port for the sshd daemon\n");
02260 #ifdef R__KRB5
02261    fprintf(stderr, "\t-S keytabfile     Use an alternate keytab file\n");
02262 #endif
02263    fprintf(stderr, "\t-T <tmpdir>       Use an alternate temp dir\n");
02264    fprintf(stderr, "\t-w                Do not check /etc/hosts.equiv and $HOME/.rhosts\n");
02265 
02266    exit(rc);
02267 }
02268 
02269 //______________________________________________________________________________
02270 int main(int argc, char **argv)
02271 {
02272    char *s;
02273    int checkhostsequiv= 1;
02274    int requireauth    = 1;
02275    int tcpwindowsize  = 65535;
02276    int sshdport       = 22;
02277    int port1          = 0;
02278    int port2          = 0;
02279    int reuseallow     = 0x1F;
02280    int login          = 2; // form rootd we fully login users, by default
02281    int foregroundflag = 0;
02282    std::string tmpdir = "";
02283    std::string confdir = "";
02284    std::string rootbindir = "";
02285    std::string altSRPpass = "";
02286    std::string daemonrc = "";
02287    std::string rootetcdir = "";
02288 #ifdef R__GLBS
02289    std::string gridmap = "";
02290    std::string hostcertconf = "";
02291 #endif
02292    char *progname = argv[0];
02293 
02294    // Init error handlers
02295    RpdSetErrorHandler(Err, ErrSys, ErrFatal);
02296 
02297    // function for dealing with SIGPIPE signals
02298    // (used by NetSetOptions() in rpdutils/net.cxx)
02299    NetSetSigPipeHook(SigPipe);
02300 
02301    // Init syslog
02302    ErrorInit(argv[0]);
02303 
02304    // Output to syslog ...
02305    RpdSetSysLogFlag(1);
02306 
02307    // ... unless we are running in the foreground and we are
02308    // attached to terminal; make also sure that "-i" and "-f"
02309    // are not simultaneously specified
02310    int i = 1;
02311    for (i = 1; i < argc; i++) {
02312       if (!strncmp(argv[i],"-f",2))
02313          foregroundflag = 1;
02314       if (!strncmp(argv[i],"-i",2))
02315          gInetdFlag = 1;
02316    }
02317    if (foregroundflag) {
02318       if (isatty(0) && isatty(1)) {
02319          RpdSetSysLogFlag(0);
02320          ErrorInfo("main: running in foreground mode:"
02321                    " sending output to stderr");
02322       }
02323       if (gInetdFlag)
02324          Error(ErrFatal,-1,"-i and -f options are incompatible");
02325    }
02326 
02327    // To terminate correctly ... maybe not needed
02328    signal(SIGTERM, RootdTerm);
02329    signal(SIGINT, RootdTerm);
02330 
02331    char *tmp = RootdExpandPathName(argv[0]);
02332    if (tmp) {
02333       int p = strlen(tmp)-1;
02334       while ((p+1) && tmp[p] != '/')
02335          p--;
02336       if (p+1) {
02337          tmp[p] = '\0';
02338          rootbindir = std::string(tmp);
02339          while ((p+1) && tmp[p] != '/')
02340             p--;
02341          if (p+1) {
02342             tmp[p] = '\0';
02343             confdir = std::string(tmp);
02344          }
02345       }
02346       free(tmp);
02347    }
02348 
02349    while (--argc > 0 && (*++argv)[0] == '-')
02350       for (s = argv[0]+1; *s != 0; s++)
02351          switch (*s) {
02352 
02353             case 'b':
02354                if (--argc <= 0) {
02355                   Error(ErrFatal,kErrFatal,"-b requires a buffersize in bytes"
02356                                     " as argument");
02357                }
02358                tcpwindowsize = atoi(*++argv);
02359                break;
02360 #ifdef R__GLBS
02361             case 'C':
02362                if (--argc <= 0) {
02363                   Error(ErrFatal, kErrFatal,"-C requires a file name for"
02364                                     " the host certificates file location");
02365                }
02366                hostcertconf = std::string(*++argv);
02367                break;
02368 #endif
02369             case 'd':
02370                if (--argc <= 0) {
02371                   Error(ErrFatal,kErrFatal,"-d requires a debug level as"
02372                                     " argument");
02373                }
02374                gDebug = atoi(*++argv);
02375                break;
02376 
02377             case 'D':
02378                if (--argc <= 0) {
02379                   Error(ErrFatal, kErrFatal,"-D requires a file path name"
02380                                     "  for the file defining access rules");
02381                }
02382                daemonrc = std::string(*++argv);
02383                break;
02384 
02385             case 'E':
02386                Error(ErrFatal, kErrFatal,"Option '-E' is now dummy "
02387                           "- ignored (see proofd/src/proofd.cxx for"
02388                           " additional details)");
02389                break;
02390 
02391             case 'f':
02392                if (gInetdFlag) {
02393                   Error(ErrFatal,-1,"-i and -f options are incompatible");
02394                }
02395                foregroundflag = 1;
02396                break;
02397 
02398             case 'F':
02399                gCastorFlag = 1;
02400                gInetdFlag  = 1;
02401                reuseallow = 0x0; // No auth reuse for castor
02402                login = 1; // No full logins for castor (user $HOMEs may not exist on servers)
02403                if (--argc <= 0) {
02404                   if (!gInetdFlag)
02405                      fprintf(stderr,"-F requires a file path name for the"
02406                              " CASTOR disk file to be accessed\n");
02407                   Error(ErrFatal, kErrFatal,"-F requires a file path name"
02408                         " for the CASTOR disk file to be accessed");
02409                }
02410                gCastorFile = std::string(*++argv);
02411                break;
02412 
02413 #ifdef R__GLBS
02414             case 'G':
02415                if (--argc <= 0) {
02416                   Error(ErrFatal,kErrFatal,"-G requires a file name for"
02417                                     " the gridmap file");
02418                }
02419                gridmap = std::string(*++argv);
02420                break;
02421 #endif
02422             case 'h':
02423                Usage(progname, 0);
02424                break;
02425 
02426             case 'H':
02427                if (--argc <= 0) {
02428                   if (!gInetdFlag && !gCastorFlag)
02429                      fprintf(stderr,"-H requires the CASTOR request ID");
02430                   Error(ErrFatal, kErrFatal,"-H requires the CASTOR request ID");
02431                }
02432                gCastorReqId = std::string(*++argv);
02433                break;
02434 
02435             case 'i':
02436                if (foregroundflag) {
02437                   Error(ErrFatal,-1,"-i and -f options are incompatible");
02438                }
02439                gInetdFlag = 1;
02440                break;
02441 
02442             case 'n':
02443                if (!strncmp(argv[0]+1,"noauth",6)) {
02444                   requireauth = 0;
02445                   s += 5;
02446                }
02447                break;
02448 
02449             case 'p':
02450                if (--argc <= 0) {
02451                   Error(ErrFatal,kErrFatal,"-p requires a port number as"
02452                                     " argument");
02453                }
02454                char *p;
02455                port1 = strtol(*++argv, &p, 10);
02456                if (*p == '-') {
02457                   p++;
02458                   port2 = strtol(p, &p, 10);
02459                } else if (*p == '\0')
02460                   port2 = port1;
02461                if (*p != '\0' || port2 < port1 || port2 < 0) {
02462                   Error(ErrFatal,kErrFatal,"invalid port number or range: %s",
02463                                      *argv);
02464                }
02465                break;
02466 
02467             case 'P':
02468                if (--argc <= 0) {
02469                   Error(ErrFatal,kErrFatal,"-P requires a file name for SRP"
02470                                     " password file");
02471                }
02472                altSRPpass = std::string(*++argv);
02473                break;
02474 
02475             case 'r':
02476                gReadOnly = 1;
02477                break;
02478 
02479             case 'R':
02480                if (--argc <= 0) {
02481                   Error(ErrFatal,kErrFatal,"-R requires a hex but mask as"
02482                                     " argument");
02483                }
02484                reuseallow = strtol(*++argv, (char **)0, 16);
02485                break;
02486 
02487             case 's':
02488                if (--argc <= 0) {
02489                   Error(ErrFatal,kErrFatal,"-s requires as argument a port"
02490                                     " number for the sshd daemon");
02491                }
02492                sshdport = atoi(*++argv);
02493                break;
02494 #ifdef R__KRB5
02495             case 'S':
02496                if (--argc <= 0) {
02497                   Error(ErrFatal,kErrFatal,"-S requires a path to your"
02498                                     " keytab\n");
02499                }
02500                RpdSetKeytabFile((const char *)(*++argv));
02501                break;
02502 #endif
02503             case 'T':
02504                if (--argc <= 0) {
02505                   Error(ErrFatal, kErrFatal,"-T requires a dir path for"
02506                                     " temporary files [/usr/tmp]");
02507                }
02508                tmpdir = std::string(*++argv);
02509                break;
02510 
02511             case 'w':
02512                checkhostsequiv = 0;
02513                break;
02514 
02515             default:
02516                if (!foregroundflag) fprintf(stderr, "\nUnknown command line option: %c\n", *s);
02517                Error(0, -1, "unknown command line option: %c", *s);
02518                Usage(progname, 1);
02519          }
02520 
02521    // dir for temporary files
02522    if (!tmpdir.length())
02523       tmpdir = std::string("/usr/tmp");
02524    if (access(tmpdir.c_str(), W_OK) == -1)
02525       tmpdir = std::string("/tmp");
02526 
02527    // root tab file
02528    gRootdTab = std::string(tmpdir).append("/rootdtab");
02529 
02530    if (argc > 0) {
02531       confdir = std::string(*argv);
02532    } else {
02533       // try to guess the config directory...
02534 #ifndef ROOTPREFIX
02535       if (!confdir.length()) {
02536          if (getenv("ROOTSYS")) {
02537             confdir = getenv("ROOTSYS");
02538             if (gDebug > 0)
02539                ErrorInfo("main: no config directory specified using"
02540                          " ROOTSYS (%s)", confdir.c_str());
02541          } else {
02542             if (gDebug > 0)
02543                ErrorInfo("main: no config directory specified");
02544          }
02545       }
02546 #else
02547       confdir = ROOTPREFIX;
02548 #endif
02549    }
02550 #ifdef ROOTBINDIR
02551    rootbindir= ROOTBINDIR;
02552 #endif
02553 #ifdef ROOTETCDIR
02554    rootetcdir= ROOTETCDIR;
02555 #endif
02556 
02557    // Define rootbindir if not done already
02558    if (!rootbindir.length())
02559       rootbindir = std::string(confdir).append("/bin");
02560    // Make it available to all the session via env
02561    if (rootbindir.length()) {
02562       char *tmp1 = new char[15 + rootbindir.length()];
02563       sprintf(tmp1, "ROOTBINDIR=%s", rootbindir.c_str());
02564       putenv(tmp1);
02565    }
02566 
02567    // Define rootetcdir if not done already
02568    if (!rootetcdir.length())
02569       rootetcdir = std::string(confdir).append("/etc");
02570    // Make it available to all the session via env
02571    if (rootetcdir.length()) {
02572       char *tmp1 = new char[15 + rootetcdir.length()];
02573       sprintf(tmp1, "ROOTETCDIR=%s", rootetcdir.c_str());
02574       putenv(tmp1);
02575    }
02576 
02577    // If specified, set the special daemonrc file to be used
02578    if (daemonrc.length()) {
02579       char *tmp1 = new char[15+daemonrc.length()];
02580       sprintf(tmp1, "ROOTDAEMONRC=%s", daemonrc.c_str());
02581       putenv(tmp1);
02582    }
02583 #ifdef R__GLBS
02584    // If specified, set the special gridmap file to be used
02585    if (gridmap.length()) {
02586       char *tmp1 = new char[15+gridmap.length()];
02587       sprintf(tmp1, "GRIDMAP=%s", gridmap.c_str());
02588       putenv(tmp1);
02589    }
02590    // If specified, set the special hostcert.conf file to be used
02591    if (hostcertconf.length()) {
02592       char *tmp1 = new char[15+hostcertconf.length()];
02593       sprintf(tmp1, "ROOTHOSTCERT=%s", hostcertconf.c_str());
02594       putenv(tmp1);
02595    }
02596 #endif
02597 
02598    // Parent ID
02599    int rootdparentid = -1;      // Parent process ID
02600    if (!gInetdFlag)
02601       rootdparentid = getpid(); // Identifies this family
02602    else
02603       rootdparentid = getppid(); // Identifies this family
02604 
02605    // default job options
02606    unsigned int options = kDMN_RQAUTH | kDMN_HOSTEQ | kDMN_SYSLOG;
02607    // modify them if required
02608    if (!requireauth)
02609       options &= ~kDMN_RQAUTH;
02610    if (!checkhostsequiv)
02611       options &= ~kDMN_HOSTEQ;
02612    if (foregroundflag)
02613       options &= ~kDMN_SYSLOG;
02614    RpdInit(gService, rootdparentid, gProtocol, options,
02615            reuseallow, sshdport,
02616            tmpdir.c_str(),altSRPpass.c_str(),login);
02617 
02618    // Generate Local RSA keys for the session
02619    if (RpdGenRSAKeys(0)) {
02620       Error(Err, -1, "rootd: unable to generate local RSA keys");
02621    }
02622 
02623    if (!gInetdFlag) {
02624 
02625       // Start rootd up as a daemon process (in the background).
02626       // Also initialize the network connection - create the socket
02627       // and bind our well-know address to it.
02628 
02629       int fdkeep = NetInit(gService, port1, port2, tcpwindowsize);
02630       if (!foregroundflag)
02631          DaemonStart(1, fdkeep, gService);
02632    }
02633 
02634    if (gDebug > 0)
02635       ErrorInfo("main: pid = %d, ppid = %d, gInetdFlag = %d, gProtocol = %d",
02636                 getpid(), getppid(), gInetdFlag, gProtocol);
02637 
02638    // Concurrent server loop.
02639    // The child created by NetOpen() handles the client's request.
02640    // The parent waits for another request. In the inetd case,
02641    // the parent from NetOpen() never returns.
02642 
02643    while (1) {
02644 
02645       if (NetOpen(gInetdFlag, gService) == 0) {
02646 
02647          // Init Session (get protocol, run authentication, login, ...)
02648          int rci = RpdInitSession(gService, gUser,
02649                                   gClientProtocol, gAnon, gPasswd);
02650          if (rci == -1)
02651             Error(ErrFatal, -1, "rootd: failure initializing session");
02652          else if (rci == -2)
02653             // Special session (eg. cleanup): just exit
02654             exit(0);
02655 
02656          ErrorInfo("main: rootdparentid = %d (%d)", rootdparentid, getppid());
02657 
02658          // RootdParallel is called after authentication in RootdLogin
02659          RootdLoop();      // child processes client's requests
02660          NetClose();       // till we are done
02661          exit(0);
02662       }
02663 
02664       // parent waits for another client to connect
02665       // (except in CASTOR mode)
02666       if (gCastorFlag) break;
02667 
02668    }
02669 
02670 }

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