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/lg2.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 PHOSPHOR_LOG2_USING; 28 using namespace phosphor::logging; 29 namespace fs = std::filesystem; 30 31 void Download::downloadViaTFTP(std::string fileName, std::string serverAddress) 32 { 33 using Argument = xyz::openbmc_project::Common::InvalidArgument; 34 35 // Sanitize the fileName string 36 if (!fileName.empty()) 37 { 38 fileName.erase(std::remove(fileName.begin(), fileName.end(), '/'), 39 fileName.end()); 40 fileName = fileName.substr(fileName.find_first_not_of('.')); 41 } 42 43 if (fileName.empty()) 44 { 45 error("Filename is empty"); 46 elog<InvalidArgument>(Argument::ARGUMENT_NAME("FileName"), 47 Argument::ARGUMENT_VALUE(fileName.c_str())); 48 return; 49 } 50 51 if (serverAddress.empty()) 52 { 53 error("ServerAddress is empty"); 54 elog<InvalidArgument>(Argument::ARGUMENT_NAME("ServerAddress"), 55 Argument::ARGUMENT_VALUE(serverAddress.c_str())); 56 return; 57 } 58 59 info("Downloading {PATH} via TFTP: {SERVERADDRESS}", "PATH", fileName, 60 "SERVERADDRESS", serverAddress); 61 62 // Check if IMAGE DIR exists 63 fs::path imgDirPath(IMG_UPLOAD_DIR); 64 if (!fs::is_directory(imgDirPath)) 65 { 66 error("Image Dir {PATH} does not exist", "PATH", imgDirPath); 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 error("Error ({ERRNO}) occurred during the TFTP call", "ERRNO", 85 errno); 86 elog<InternalFailure>(); 87 } 88 else if (nextPid < 0) 89 { 90 error("Error ({ERRNO}) occurred during fork", "ERRNO", errno); 91 elog<InternalFailure>(); 92 } 93 // do nothing as parent if all is going well 94 // when parent exits, child will be reparented under init 95 // and then be reaped properly 96 exit(0); 97 } 98 else if (pid < 0) 99 { 100 error("Error ({ERRNO}) occurred during fork", "ERRNO", errno); 101 elog<InternalFailure>(); 102 } 103 else 104 { 105 int status; 106 if (waitpid(pid, &status, 0) < 0) 107 { 108 error("Error ({ERRNO}) occurred during waitpid", "ERRNO", errno); 109 } 110 else if (WEXITSTATUS(status) != 0) 111 { 112 113 error("Failed ({STATUS}) to launch tftp", "STATUS", status); 114 } 115 } 116 117 return; 118 } 119 120 } // namespace manager 121 } // namespace software 122 } // namespace phosphor 123