// Take files given on stdin and make them into a ramfs image of our // own, (stupid) simple format. // In the format: for each file comes the null-terminated string // with filename, then null-padding until a 4-aligned offset, then // 4-byte little-endian size of the file and then the contents // of the file and then another null-padding until a 4-aligned offset. // Files encoded this way go one after another (so it's easy to add // something at the beginning). // At the and comes one null-byte (as if a file with empty name // was there). #include <stdint.h> #include <sys/types.h> #include <sys/wait.h> #include <unistd.h> #include <stdlib.h> #include <stdio.h> #include <err.h> #include <sys/stat.h> #include <string.h> #define ANSI_FG_RED "\033[0;31m" #define ANSI_FG_DEFAULT "\033[0;39m" int main(int argc, char **argv) { // process files in the order they are provided on the command line for (int i = 1; i < argc; i++) { struct stat fileinfo; if (stat(argv[i], &fileinfo)) err(-1, "couldn't stat " ANSI_FG_RED "%s" ANSI_FG_DEFAULT, argv[i]); if (!S_ISREG(fileinfo.st_mode)) errx(-1, ANSI_FG_RED "%s" ANSI_FG_DEFAULT " is not a regular file.", argv[i]); // don't allow files with size so big, that it can't be encoded // in a 4-byte unsigned int... In practice even smaller files // won't fit on the rpi. if (fileinfo.st_size > UINT32_MAX) errx(-1, ANSI_FG_RED "%s" ANSI_FG_DEFAULT " is too big.", argv[i]); uint32_t file_size = fileinfo.st_size; uint32_t name_size = strlen(argv[i]) + 1; // 1 for null-byte if (fwrite(argv[i], 1, name_size, stdout) != name_size) errx(-1, "error writing to stdout"); // pad with null-bytes until a 4-aligned offset for (uint32_t j = 0; (j + name_size) & 0b11; j++) if (putchar('\0')) errx(-1, "error writing to stdout"); // TODO convert file_size to little endian first (in case our // host is be). if (fwrite(&file_size, 4, 1, stdout) != 1) errx(-1, "error writing to stdout"); // flush b4 running cat, so that stuff we've written comes // b4 the actual file contents in the output if (fflush(stdout)) err(-1, "couldn't flush stdout"); // we don't copy the actual file ourselves - we run cat for that pid_t pid; int wstatus; switch (pid = fork()) { case -1: err(-1, "couldn't fork"); case 0: if (execlp("cat", "cat", argv[i], NULL)) err(-1, "couldn't execute cat"); default: if (wait(&wstatus) == -1) err(-1, "error waiting for child"); if (!WIFEXITED(wstatus) || WEXITSTATUS(wstatus)) exit(-1); } // again, pad with null-bytes until a 4-aligned offset for (uint32_t j = 0; (j + file_size) & 0b11; j++) if (putchar('\0')) errx(-1, "error writing to stdout"); } if (putchar('\0')) errx(-1, "error writing to stdout"); return 0; }