• Bug#1107203: unblock: initramfs-tools/0.148.1 (5/5)

    From Ben Hutchings@1:229/2 to All on Tue Jun 3 00:20:01 2025
    [continued from previous message]

    + argv[argc] = NULL;
    +
    + if (pipe(pipe_fds)) {
    + warn("pipe");
    + return false;
    + }
    + pid = fork();
    + if (pid < 0) {
    + warn("fork");
    + return false;
    + }
    +
    + /* Child */
    + if (pid == 0) {
    + /*
    + * Close write end of the pipe; make the read end
    + * stdout.
    + */
    + close(pipe_fds[1]);
    + dup2(pipe_fds[0], 0);
    + close(pipe_fds[0]);
    +
    + execvp("cpio", (char **)argv);
    + _exit(127);
    + }
    +
    + /*
    + * Parent: close read end of the pipe; return child pid and
    + * write end of pipe.
    + */
    + close(pipe_fds[0]);
    + proc->pid = pid;
    + proc->pipe = pipe_fds[1];
    + return true;
    +}
    +
    +static bool end_cpio(const struct cpio_proc *proc, bool ok)
    +{
    + int wstatus;
    +
    + close(proc->pipe);
    +
    + if (ok) {
    + if (waitpid(proc->pid, &wstatus, 0) != proc->pid ||
    + !WIFEXITED(wstatus) || WEXITSTATUS(wstatus) != 0) {
    + warnx("cpio failed");
    + return false;
    + }
    + } else {
    + kill(proc->pid, SIGTERM);
    + }
    +
    + return true;
    +}
    +
    +static const struct option long_opts[] = {
    + { "help", no_argument, NULL, 'h' },
    + { "list", no_argument, NULL, 'l' },
    + { "verbose", no_argument, NULL, 'v' },
    + { NULL }
    +};
    +
    +static void usage(FILE *stream)
    +{
    + fprintf(stream, "\
    +\n\
    +Usage: unmkinitramfs [-v|--verbose] INITRAMFS-FILE DIRECTORY\n\
    +\n\
    +Options:\n\
    + -v | --verbose Display verbose messages about extraction\n\
    +\n\
    +See unmkinitramfs(8) for further details.\n\
    +\n"
    + );
    +}
    +
    +int main(int argc, char **argv)
    +{
    + int opt;
    + bool do_list = false;
    + bool verbose = false;
    + const char *in_filename;
    + FILE *in_file;
    + const char *out_dirname = NULL;
    + char *out_subdirname = NULL;
    + const char *cpio_optv[3];
    + int cpio_optc;
    + struct cpio_proc cpio_proc = { 0 };
    + unsigned int early_count = 0;
    + bool ok;
    +
    + /* Parse options */
    + opterr = 0;
    + while ((opt = getopt_long(argc, argv, "hv", long_opts, NULL)) >= 0) {
    + switch (opt) {
    + case '?':
    + usage(stderr);
    + return 2;
    + case 'h':
    + usage(stdout);
    + return 0;
    + case 'l':
    + do_list = true;
    + break;
    + case 'v':
    + verbose = true;
    + break;
    + }
    + }
    +
    + /* Check number of non-option arguments */
    + if (argc - optind != (do_list ? 1 : 2)) {
    + usage(stderr);
    + return 2;
    + }
    +
    + /* Set up input file and output directory */
    + in_filename = argv[optind];
    + in_file = fopen(in_filename, "rb");
    + if (!in_file)
    + err(1, "%s", in_filename);
    + if (!do_list) {
    + out_dirname = argv[optind + 1];
    + if (!mkdir_allow_exist(out_dirname, 0777))
    + err(1, "%s", out_dirname);
    + out_subdirname = malloc(strlen(out_dirname) + 20);
    + if (!out_subdirname)
    + err(1, "malloc");
    + }
    +
    + /* Set up extra options for cpio */
    + cpio_optc = 0;
    + if (do_list) {
    + cpio_optv[cpio_optc++] = "--list";
    + } else {
    + cpio_optv[cpio_optc++] = "-D";
    + cpio_optv[cpio_optc++] = out_subdirname;
    + }
    + if (verbose)
    + cpio_optv[cpio_optc++] = "-v";
    +
    + /* Iterate over archives within the initramfs */
    + for (;;) {
    + unsigned char magic_buf[MAX_MAGIC_LEN];
    + size_t read_len;
    + const struct magic_entry *me;
    +
    + /* Peek at first bytes of next archive; handle EOF */
    + read_len = fread(magic_buf, 1, sizeof(magic_buf), in_file);
    + if (read_len == 0) {
    + /*
    + * EOF with no compresed archive. Add back a
    + * trailer to keep cpio happy.
    + */
    + if (ferror(in_file)) {
    + warn("%s", in_filename);
    + ok = false;
    + }
    + if (cpio_proc.pid && !write_trailer(cpio_proc.pipe))
    + ok = false;
    + break;
    + }
    + fseek(in_file, -(long)read_len, SEEK_CUR);
    +
    + /* Identify format */
    + for (me = magic_table; me->magic_len; ++me)
    + if (read_len >= me->magic_len &&
    + memcmp(magic_buf, me->magic, me->magic_len) == 0)
    + break;
    + if (me->magic_len == 0) {
    + warnx("%s: unrecognised compression or corrupted file", + in_filename);
    + ok = false;
    + break;
    + }
    +
    + /*
    + * Extract the archive to an "early" or "early<n>"
    + * subdirectory if:
    + * - We have not already started the main cpio process
    + * - We are not listing
    + * - This looks like an early initramfs (uncompressed
    + * and contains files under kernel/)
    + */
    + if (!cpio_proc.pid && !do_list &&
    + me->format == FORMAT_CPIO_NEW &&
    + detect_early_initramfs(in_file, in_filename)) {
    + struct cpio_proc early_cpio_proc;
    +
    + if (++early_count == 1)
    + sprintf(out_subdirname, "%s/early",
    + out_dirname);
    + else
    + sprintf(out_subdirname, "%s/early%u",
    + out_dirname, early_count);
    + if (!mkdir_allow_exist(out_subdirname, 0777)) {
    + warn("%s", out_subdirname);
    + ok = false;
    + break;
    + }
    + if (!spawn_cpio(cpio_optc, cpio_optv,
    + &early_cpio_proc)) {
    + ok = false;
    + break;
    + }
    + ok = handle_uncompressed(in_file, in_filename,
    + early_cpio_proc.pipe)
    + && write_trailer(early_cpio_proc.pipe);
    + if (!end_cpio(&early_cpio_proc, ok))
    + ok = false;
    + if (!ok)
    + break;
    + } else {
    + /*
    + * Otherwise, extract to either the base
    + * output directory or a "main" subdirectory,
    + * depending on whether we already created
    + * subdirectories.
    + */
    + if (!cpio_proc.pid) {
    + if (do_list) {
    + ;
    + } else if (early_count) {
    + sprintf(out_subdirname, "%s/main",
    + out_dirname);
    + if (!mkdir_allow_exist(out_subdirname, + 0777)) {
    + warn("%s", out_subdirname);
    + ok = false;
    + break;
    + }
    + } else {
    + strcpy(out_subdirname, out_dirname);
    + }
    + if (!spawn_cpio(cpio_optc, cpio_optv,
    + &cpio_proc)) {
    + ok = false;
    + break;
    + }
    + }
    + if (me->format == FORMAT_CPIO_NEW) {
    + ok = handle_uncompressed(in_file, in_filename, + cpio_proc.pipe);
    + if (!ok)
    + break;
    + } else {
    + ok = handle_compressed(in_file, me->format,
    + cpio_proc.pipe);
    + break;
    + }
    + }
    + }
    +
    + fclose(in_file);
    +
    + if (cpio_proc.pid && !end_cpio(&cpio_proc, ok))
    + ok = false;
    +
    + return !ok;
    +}

    --- SoupGate-Win32 v1.05
    * Origin: you cannot sedate... all the things you hate (1:229/2)