CMS 3D CMS Logo

/data/refman/pasoursint/CMSSW_5_3_10_patch1/src/Utilities/StorageFactory/src/RemoteFile.cc

Go to the documentation of this file.
00001 #include "Utilities/StorageFactory/interface/RemoteFile.h"
00002 #include "Utilities/StorageFactory/src/Throw.h"
00003 #include "FWCore/Utilities/interface/Exception.h"
00004 #include <sys/wait.h>
00005 #include <sys/types.h>
00006 #include <cerrno>
00007 #include <cassert>
00008 #include <spawn.h>
00009 #include <unistd.h>
00010 #include <ostream>
00011 #include <cstring>
00012 #if __APPLE__
00013 # include <crt_externs.h>
00014 # define environ (*_NSGetEnviron())
00015 #endif
00016 
00017 static std::string
00018 join (char **cmd)
00019 {
00020   size_t size = 0;
00021   for (char **p = cmd; p && p[0]; ++p)
00022     size += 1 + strlen(*p);
00023 
00024   std::string result;
00025   result.reserve (size);
00026 
00027   for (char **p = cmd; p && p[0]; ++p)
00028   {
00029     if (p != cmd)
00030       result += ' ';
00031     result += *p;
00032   }
00033 
00034   return result;
00035 }
00036 
00037 RemoteFile::RemoteFile (IOFD fd, const std::string &name)
00038   : File (fd),
00039     name_ (name)
00040 {}
00041 
00042 void
00043 RemoteFile::remove (void)
00044 { unlink (name_.c_str()); }
00045 
00046 void
00047 RemoteFile::close (void)
00048 { remove(); File::close (); }
00049 
00050 void
00051 RemoteFile::abort (void)
00052 { remove(); File::abort (); }
00053 
00054 int
00055 RemoteFile::local (const std::string &tmpdir, std::string &temp)
00056 {
00057   // Download temporary files to the current directory by default.
00058   // This is better for grid jobs as the current directory is
00059   // likely to have more space, and is more optimised for
00060   // large files, and is cleaned up after the job.
00061   if (tmpdir.empty () || tmpdir == ".")
00062   {
00063     size_t len = pathconf (".", _PC_PATH_MAX);
00064     char   *buf = (char *) malloc (len);
00065     getcwd (buf, len);
00066 
00067     temp.reserve (len + 32);
00068     temp = buf;
00069     free (buf);
00070   }
00071   else
00072   {
00073     temp.reserve (tmpdir.size() + 32);
00074     temp = tmpdir;
00075   }
00076   if (temp[temp.size()-1] != '/')
00077     temp += '/';
00078 
00079   temp += "storage-factory-local-XXXXXX";
00080   temp.c_str(); // null terminate for mkstemp
00081 
00082   int fd = mkstemp (&temp[0]);
00083   if (fd == -1)
00084     throwStorageError("RemoteFile", "Calling RemoteFile::local()", "mkstemp()", errno);
00085 
00086   return fd;
00087 }
00088 
00089 Storage *
00090 RemoteFile::get (int localfd, const std::string &name, char **cmd, int mode)
00091 {
00092   // FIXME: On write, create a temporary local file open for write;
00093   // on close, trigger transfer to destination.  If opening existing
00094   // file for write, may need to first download.
00095   assert (! (mode & (IOFlags::OpenWrite | IOFlags::OpenCreate)));
00096 
00097   pid_t  pid = -1;
00098   int    rc = posix_spawnp (&pid, cmd[0], 0, 0, cmd, environ);
00099 
00100   if (rc == -1)
00101   {
00102     int errsave = errno;
00103     ::close (localfd);
00104     unlink (name.c_str());
00105     throwStorageError ("RemoteFile", "Calling RemoteFile::get()", "posix_spawnp()", errsave);
00106   }
00107 
00108   pid_t rcpid;
00109   do
00110     rcpid = waitpid(pid, &rc, 0);
00111   while (rcpid == (pid_t) -1 && errno == EINTR);
00112 
00113   if (rcpid == (pid_t) -1)
00114   {
00115     int errsave = errno;
00116     ::close (localfd);
00117     unlink (name.c_str());
00118     throwStorageError ("RemoteFile", "Calling RemoteFile::get()", "waitpid()", errsave);
00119   }
00120 
00121   if (WIFEXITED(rc) && WEXITSTATUS(rc) == 0)
00122     return new RemoteFile (localfd, name);
00123   else
00124   {
00125     ::close (localfd);
00126     unlink (name.c_str());
00127     cms::Exception ex("RemoteFile");
00128     ex << "'" << join(cmd) << "'"
00129        << (WIFEXITED(rc) ? " exited with exit code "
00130            : WIFSIGNALED(rc) ? " died from signal "
00131            : " died for an obscure unknown reason with exit status ")
00132        << (WIFEXITED(rc) ? WEXITSTATUS(rc)
00133            : WIFSIGNALED(rc) ? WTERMSIG(rc)
00134            : rc);
00135     ex.addContext("Calling RemoteFile::get()");
00136     throw ex;
00137   }
00138 }