1 #include "config.h" 2 3 #include "download_manager.hpp" 4 5 #include "xyz/openbmc_project/Common/error.hpp" 6 7 #include <sys/wait.h> 8 #include <unistd.h> 9 10 #include <phosphor-logging/elog-errors.hpp> 11 #include <phosphor-logging/elog.hpp> 12 #include <phosphor-logging/log.hpp> 13 14 #include <algorithm> 15 #include <filesystem> 16 #include <iostream> 17 #include <string> 18 19 namespace phosphor 20 { 21 namespace software 22 { 23 namespace manager 24 { 25 26 using namespace sdbusplus::xyz::openbmc_project::Common::Error; 27 using namespace phosphor::logging; 28 namespace fs = std::filesystem; 29 30 void Download::downloadViaTFTP(std::string fileName, std::string serverAddress) 31 { 32 using Argument = xyz::openbmc_project::Common::InvalidArgument; 33 34 // Sanitize the fileName string 35 if (!fileName.empty()) 36 { 37 fileName.erase(std::remove(fileName.begin(), fileName.end(), '/'), 38 fileName.end()); 39 fileName = fileName.substr(fileName.find_first_not_of('.')); 40 } 41 42 if (fileName.empty()) 43 { 44 log<level::ERR>("Error FileName is empty"); 45 elog<InvalidArgument>(Argument::ARGUMENT_NAME("FileName"), 46 Argument::ARGUMENT_VALUE(fileName.c_str())); 47 return; 48 } 49 50 if (serverAddress.empty()) 51 { 52 log<level::ERR>("Error ServerAddress is empty"); 53 elog<InvalidArgument>(Argument::ARGUMENT_NAME("ServerAddress"), 54 Argument::ARGUMENT_VALUE(serverAddress.c_str())); 55 return; 56 } 57 58 log<level::INFO>("Downloading via TFTP", 59 entry("FILENAME=%s", fileName.c_str()), 60 entry("SERVERADDRESS=%s", serverAddress.c_str())); 61 62 // Check if IMAGE DIR exists 63 fs::path imgDirPath(IMG_UPLOAD_DIR); 64 if (!fs::is_directory(imgDirPath)) 65 { 66 log<level::ERR>("Error Image Dir does not exist"); 67 elog<InternalFailure>(); 68 return; 69 } 70 71 pid_t pid = fork(); 72 73 if (pid == 0) 74 { 75 pid_t nextPid = fork(); 76 if (nextPid == 0) 77 { 78 // child process 79 execl("/usr/bin/tftp", "tftp", "-g", "-r", fileName.c_str(), 80 serverAddress.c_str(), "-l", 81 (std::string{IMG_UPLOAD_DIR} + '/' + fileName).c_str(), 82 (char*)0); 83 // execl only returns on fail 84 log<level::ERR>("Error occurred during the TFTP call"); 85 elog<InternalFailure>(); 86 } 87 else if (nextPid < 0) 88 { 89 log<level::ERR>("Error occurred during fork"); 90 elog<InternalFailure>(); 91 } 92 // do nothing as parent if all is going well 93 // when parent exits, child will be reparented under init 94 // and then be reaped properly 95 exit(0); 96 } 97 else if (pid < 0) 98 { 99 log<level::ERR>("Error occurred during fork"); 100 elog<InternalFailure>(); 101 } 102 else 103 { 104 int status; 105 if (waitpid(pid, &status, 0) < 0) 106 { 107 log<level::ERR>("waitpid error"); 108 } 109 else if (WEXITSTATUS(status) != 0) 110 { 111 log<level::ERR>("failed to launch tftp"); 112 } 113 } 114 115 return; 116 } 117 118 } // namespace manager 119 } // namespace software 120 } // namespace phosphor 121