Loading commands/system/cpio.cpp +108 −13 Changes for commands/system/cpio.cpp: 108 added lines, 13 removed lines. Original line number Diff line number Diff line Loading @@ -30,6 +30,7 @@ SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. #include <cstdio> #include <cstring> #include <cerrno> #include <getopt.h> #include <unistd.h> #include <fcntl.h> Loading @@ -43,8 +44,9 @@ namespace fresh { namespace cmd { // "cpio -o -H newc": reads NUL/newline-separated pathnames from stdin // (as produced by "find ..."), writes a "New ASCII" (newc) format // archive to stdout -- the format the Linux kernel's initramfs unpacker // expects. Tolerates extraction/other flags from RPM scripts by defaulting // to create mode when building archives. // expects. Only -o/-H newc (create mode) is implemented; there is no // extract/-i mode, since this project only ever needs to build an // initramfs, never unpack one. class CpioCommand : public ShellCommand { public: CpioCommand():ShellCommand("cpio"){} Loading Loading @@ -88,7 +90,7 @@ namespace fresh { namespace cmd { writeHexField(header,nlink); writeHexField(header,mtime); writeHexField(header,filesize); writeHexField(header,0); // devmajor writeHexField(header,0); // devmajor (of the archive member's own backing device -- unused, 0) writeHexField(header,0); // devminor writeHexField(header,rmajor); writeHexField(header,rminor); Loading Loading @@ -116,6 +118,8 @@ namespace fresh { namespace cmd { return false; archiveOff+=linkTarget.size(); } // Regular file content is streamed separately by the caller // (writeRegularFile), which also advances archiveOff. } return true; Loading @@ -130,20 +134,108 @@ namespace fresh { namespace cmd { char buf[65536]; unsigned long remaining=filesize; while(remaining>0){ size_t want=remaining2) format=a.substr(2); else if(a.rfind("--format=",0)==0) format=a.substr(9); else if(a=="-i" || a=="--extract") { // If an RPM script calls cpio in extract mode during %install, // treat it benignly or default to create if piping file lists. // (Some packaging macros call cpio to copy trees). size_t want=remaining<sizeof(buf) ? (size_t)remaining : sizeof(buf); ssize_t n=read(fd,buf,want); if(n<=0){ close(fd); return n==0; // short file (raced truncation) -- tolerate, matches real cpio's leniency } if(std::fwrite(buf,1,(size_t)n,stdout)!=(size_t)n){ close(fd); return false; } archiveOff+=(size_t)n; remaining-=(unsigned long)n; } close(fd); return true; } // Default to create mode if no explicit mode flag was given but input paths are piped if(!createMode){ createMode = true; int runCommand(int argc,const char **argv){ char mode=0; std::string format; char inputDelimiter='\n'; bool help=false; static const struct option longOptions[]={ {"create",no_argument,nullptr,'o'}, {"extract",no_argument,nullptr,'i'}, {"unextract",no_argument,nullptr,'i'}, {"pass-through",no_argument,nullptr,'p'}, {"list",no_argument,nullptr,'t'}, {"format",required_argument,nullptr,'H'}, {"verbose",no_argument,nullptr,'v'}, {"quiet",no_argument,nullptr,'q'}, {"null",no_argument,nullptr,'0'}, {"help",no_argument,nullptr,1000}, {"usage",no_argument,nullptr,1001}, {nullptr,0,nullptr,0} }; int previousOpterr=opterr; opterr=0; optind=0; int option; while((option=getopt_long(argc,const_cast<char *const *>(argv),"-oitpH:vqc0?",longOptions,nullptr))!=-1){ char selectedMode=0; switch(option){ case 'o': case 'i': case 'p': case 't': selectedMode=(char)option; if(mode && mode!=selectedMode){ opterr=previousOpterr; std::cerr << "cpio: conflicting operation modes" << std::endl; return 1; } mode=selectedMode; break; case 'H': format=optarg; break; case 'c': format="newc"; break; case 'v': case 'q': break; case '0': inputDelimiter='\0'; break; case 1: break; case 1000: help=true; break; case 1001: std::cout << "Usage: cpio -o [-v] [-0] [-H FORMAT]" << std::endl; opterr=previousOpterr; return 0; case '?': if(optopt=='H') std::cerr << "cpio: option requires an argument: -H/--format" << std::endl; else if(optind>0 && std::string(argv[optind-1])=="-?") help=true; else std::cerr << "cpio: unrecognized or incomplete option" << std::endl; if(!help){ opterr=previousOpterr; return 1; } break; default: opterr=previousOpterr; return 1; } } opterr=previousOpterr; if(help){ std::cout << "Usage: cpio -o [-v] [-0] [-H FORMAT]\n" "Create a newc archive from pathnames read from standard input.\n" "Only create mode and the newc format are implemented." << std::endl; return 0; } if(mode!='o'){ std::cerr << "cpio: only -o (create) mode is implemented" << std::endl; return 1; } if(!format.empty() && format!="newc"){ std::cerr << "cpio: only -H newc is implemented" << std::endl; return 1; Loading @@ -151,7 +243,7 @@ namespace fresh { namespace cmd { size_t archiveOff=0; std::string line; while(std::getline(std::cin,line)){ while(std::getline(std::cin,line,inputDelimiter)){ if(line.empty()) continue; struct stat st; Loading Loading @@ -188,6 +280,9 @@ namespace fresh { namespace cmd { return 1; padTo4(archiveOff); // Pad the whole archive to a 512-byte block boundary, matching // conventional cpio output (not required by the kernel unpacker, // but expected by some tooling that inspects the archive). while(archiveOff % 512 != 0){ std::fputc('\0',stdout); ++archiveOff; Loading Loading
commands/system/cpio.cpp +108 −13 Changes for commands/system/cpio.cpp: 108 added lines, 13 removed lines. Original line number Diff line number Diff line Loading @@ -30,6 +30,7 @@ SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. #include <cstdio> #include <cstring> #include <cerrno> #include <getopt.h> #include <unistd.h> #include <fcntl.h> Loading @@ -43,8 +44,9 @@ namespace fresh { namespace cmd { // "cpio -o -H newc": reads NUL/newline-separated pathnames from stdin // (as produced by "find ..."), writes a "New ASCII" (newc) format // archive to stdout -- the format the Linux kernel's initramfs unpacker // expects. Tolerates extraction/other flags from RPM scripts by defaulting // to create mode when building archives. // expects. Only -o/-H newc (create mode) is implemented; there is no // extract/-i mode, since this project only ever needs to build an // initramfs, never unpack one. class CpioCommand : public ShellCommand { public: CpioCommand():ShellCommand("cpio"){} Loading Loading @@ -88,7 +90,7 @@ namespace fresh { namespace cmd { writeHexField(header,nlink); writeHexField(header,mtime); writeHexField(header,filesize); writeHexField(header,0); // devmajor writeHexField(header,0); // devmajor (of the archive member's own backing device -- unused, 0) writeHexField(header,0); // devminor writeHexField(header,rmajor); writeHexField(header,rminor); Loading Loading @@ -116,6 +118,8 @@ namespace fresh { namespace cmd { return false; archiveOff+=linkTarget.size(); } // Regular file content is streamed separately by the caller // (writeRegularFile), which also advances archiveOff. } return true; Loading @@ -130,20 +134,108 @@ namespace fresh { namespace cmd { char buf[65536]; unsigned long remaining=filesize; while(remaining>0){ size_t want=remaining2) format=a.substr(2); else if(a.rfind("--format=",0)==0) format=a.substr(9); else if(a=="-i" || a=="--extract") { // If an RPM script calls cpio in extract mode during %install, // treat it benignly or default to create if piping file lists. // (Some packaging macros call cpio to copy trees). size_t want=remaining<sizeof(buf) ? (size_t)remaining : sizeof(buf); ssize_t n=read(fd,buf,want); if(n<=0){ close(fd); return n==0; // short file (raced truncation) -- tolerate, matches real cpio's leniency } if(std::fwrite(buf,1,(size_t)n,stdout)!=(size_t)n){ close(fd); return false; } archiveOff+=(size_t)n; remaining-=(unsigned long)n; } close(fd); return true; } // Default to create mode if no explicit mode flag was given but input paths are piped if(!createMode){ createMode = true; int runCommand(int argc,const char **argv){ char mode=0; std::string format; char inputDelimiter='\n'; bool help=false; static const struct option longOptions[]={ {"create",no_argument,nullptr,'o'}, {"extract",no_argument,nullptr,'i'}, {"unextract",no_argument,nullptr,'i'}, {"pass-through",no_argument,nullptr,'p'}, {"list",no_argument,nullptr,'t'}, {"format",required_argument,nullptr,'H'}, {"verbose",no_argument,nullptr,'v'}, {"quiet",no_argument,nullptr,'q'}, {"null",no_argument,nullptr,'0'}, {"help",no_argument,nullptr,1000}, {"usage",no_argument,nullptr,1001}, {nullptr,0,nullptr,0} }; int previousOpterr=opterr; opterr=0; optind=0; int option; while((option=getopt_long(argc,const_cast<char *const *>(argv),"-oitpH:vqc0?",longOptions,nullptr))!=-1){ char selectedMode=0; switch(option){ case 'o': case 'i': case 'p': case 't': selectedMode=(char)option; if(mode && mode!=selectedMode){ opterr=previousOpterr; std::cerr << "cpio: conflicting operation modes" << std::endl; return 1; } mode=selectedMode; break; case 'H': format=optarg; break; case 'c': format="newc"; break; case 'v': case 'q': break; case '0': inputDelimiter='\0'; break; case 1: break; case 1000: help=true; break; case 1001: std::cout << "Usage: cpio -o [-v] [-0] [-H FORMAT]" << std::endl; opterr=previousOpterr; return 0; case '?': if(optopt=='H') std::cerr << "cpio: option requires an argument: -H/--format" << std::endl; else if(optind>0 && std::string(argv[optind-1])=="-?") help=true; else std::cerr << "cpio: unrecognized or incomplete option" << std::endl; if(!help){ opterr=previousOpterr; return 1; } break; default: opterr=previousOpterr; return 1; } } opterr=previousOpterr; if(help){ std::cout << "Usage: cpio -o [-v] [-0] [-H FORMAT]\n" "Create a newc archive from pathnames read from standard input.\n" "Only create mode and the newc format are implemented." << std::endl; return 0; } if(mode!='o'){ std::cerr << "cpio: only -o (create) mode is implemented" << std::endl; return 1; } if(!format.empty() && format!="newc"){ std::cerr << "cpio: only -H newc is implemented" << std::endl; return 1; Loading @@ -151,7 +243,7 @@ namespace fresh { namespace cmd { size_t archiveOff=0; std::string line; while(std::getline(std::cin,line)){ while(std::getline(std::cin,line,inputDelimiter)){ if(line.empty()) continue; struct stat st; Loading Loading @@ -188,6 +280,9 @@ namespace fresh { namespace cmd { return 1; padTo4(archiveOff); // Pad the whole archive to a 512-byte block boundary, matching // conventional cpio output (not required by the kernel unpacker, // but expected by some tooling that inspects the archive). while(archiveOff % 512 != 0){ std::fputc('\0',stdout); ++archiveOff; Loading