Back to home page

Project CMSSW displayed by LXR

 
 

    


File indexing completed on 2024-07-12 02:42:04

0001 #include "Utilities/StorageFactory/interface/RemoteFile.h"
0002 #include "Utilities/StorageFactory/src/Throw.h"
0003 #include "FWCore/Utilities/interface/Exception.h"
0004 #include <sys/wait.h>
0005 #include <sys/types.h>
0006 #include <cerrno>
0007 #include <cassert>
0008 #include <spawn.h>
0009 #include <unistd.h>
0010 #include <ostream>
0011 #include <cstring>
0012 #include <filesystem>
0013 #include <vector>
0014 #if __APPLE__
0015 #include <crt_externs.h>
0016 #define environ (*_NSGetEnviron())
0017 #endif
0018 
0019 using namespace edm::storage;
0020 
0021 static std::string join(char **cmd) {
0022   size_t size = 0;
0023   for (char **p = cmd; p && p[0]; ++p)
0024     size += 1 + strlen(*p);
0025 
0026   std::string result;
0027   result.reserve(size);
0028 
0029   for (char **p = cmd; p && p[0]; ++p) {
0030     if (p != cmd)
0031       result += ' ';
0032     result += *p;
0033   }
0034 
0035   return result;
0036 }
0037 
0038 RemoteFile::RemoteFile(IOFD fd, const std::string &name) : File(fd), name_(name) {}
0039 
0040 void RemoteFile::remove(void) { unlink(name_.c_str()); }
0041 
0042 void RemoteFile::close(void) {
0043   remove();
0044   File::close();
0045 }
0046 
0047 void RemoteFile::abort(void) {
0048   remove();
0049   File::abort();
0050 }
0051 
0052 int RemoteFile::local(const std::string &tmpdir, std::string &temp) {
0053   // Download temporary files to the current directory by default.
0054   // This is better for grid jobs as the current directory is
0055   // likely to have more space, and is more optimised for
0056   // large files, and is cleaned up after the job.
0057   std::vector<char> temp_chars;
0058 
0059   if (tmpdir.empty() || tmpdir == ".") {
0060     std::filesystem::path current_path = std::filesystem::current_path();
0061     auto spath = current_path.string();
0062     temp_chars.reserve(spath.size() + 30);
0063     temp_chars.assign(spath.begin(), spath.end());
0064   } else {
0065     temp_chars.reserve(tmpdir.size() + 30);
0066     temp_chars.assign(tmpdir.begin(), tmpdir.end());
0067   }
0068 
0069   if (temp_chars.back() != '/')
0070     temp_chars.push_back('/');
0071 
0072   std::string suffix = "storage-factory-local-XXXXXX";
0073   temp_chars.insert(temp_chars.end(), suffix.begin(), suffix.end());
0074 
0075   // Ensure the vector is null-terminated
0076   temp_chars.push_back('\0');
0077 
0078   int fd = mkstemp(temp_chars.data());
0079   if (fd == -1)
0080     throwStorageError("RemoteFile", "Calling RemoteFile::local()", "mkstemp()", errno);
0081   // Copy temp_chars to temp
0082   temp.assign(temp_chars.begin(), temp_chars.end() - 1);  // Exclude the null terminator
0083 
0084   return fd;
0085 }
0086 
0087 std::unique_ptr<Storage> RemoteFile::get(int localfd, const std::string &name, char **cmd, int mode) {
0088   // FIXME: On write, create a temporary local file open for write;
0089   // on close, trigger transfer to destination.  If opening existing
0090   // file for write, may need to first download.
0091   assert(!(mode & (IOFlags::OpenWrite | IOFlags::OpenCreate)));
0092 
0093   pid_t pid = -1;
0094   int rc = posix_spawnp(&pid, cmd[0], nullptr, nullptr, cmd, environ);
0095 
0096   if (rc == -1) {
0097     int errsave = errno;
0098     ::close(localfd);
0099     unlink(name.c_str());
0100     throwStorageError("RemoteFile", "Calling RemoteFile::get()", "posix_spawnp()", errsave);
0101   }
0102 
0103   pid_t rcpid;
0104   do
0105     rcpid = waitpid(pid, &rc, 0);
0106   while (rcpid == (pid_t)-1 && errno == EINTR);
0107 
0108   if (rcpid == (pid_t)-1) {
0109     int errsave = errno;
0110     ::close(localfd);
0111     unlink(name.c_str());
0112     throwStorageError("RemoteFile", "Calling RemoteFile::get()", "waitpid()", errsave);
0113   }
0114 
0115   if (WIFEXITED(rc) && WEXITSTATUS(rc) == 0)
0116     return std::unique_ptr<Storage>(static_cast<Storage *>(new RemoteFile(localfd, name)));
0117   else {
0118     ::close(localfd);
0119     unlink(name.c_str());
0120     cms::Exception ex("RemoteFile");
0121     ex << "'" << join(cmd) << "'"
0122        << (WIFEXITED(rc)     ? " exited with exit code "
0123            : WIFSIGNALED(rc) ? " died from signal "
0124                              : " died for an obscure unknown reason with exit status ")
0125        << (WIFEXITED(rc)     ? WEXITSTATUS(rc)
0126            : WIFSIGNALED(rc) ? WTERMSIG(rc)
0127                              : rc);
0128     ex.addContext("Calling RemoteFile::get()");
0129     throw ex;
0130   }
0131 }