static void file_treewalk_feed(const char *dir, int fd_out) { int pipefd[2]; pid_t pid; struct file_info *fi; struct file_info *symlist = NULL; struct file_info *symlist_end = NULL; m_pipe(pipefd); pid = subproc_fork(); if (pid == 0) { m_dup2(pipefd[1], 1); close(pipefd[0]); close(pipefd[1]); if (chdir(dir)) ohshite(_("failed to chdir to `%.255s'"), dir); execlp(FIND, "find", ".", "-path", "./" BUILDCONTROLDIR, "-prune", "-o", "-print0", NULL); ohshite(_("unable to execute %s (%s)"), "find", FIND); } close(pipefd[1]); /* We need to reorder the files so we can make sure that symlinks * will not appear before their target. */ while ((fi = file_info_get(dir, pipefd[0])) != NULL) { if (S_ISLNK(fi->st.st_mode)) { file_info_list_append(&symlist, &symlist_end, fi); } else { if (fd_write(fd_out, fi->fn, strlen(fi->fn) + 1) < 0) ohshite(_("failed to write filename to tar pipe (%s)"), _("data member")); file_info_free(fi); } } close(pipefd[0]); subproc_wait_check(pid, "find", 0); for (fi = symlist; fi; fi = fi->next) if (fd_write(fd_out, fi->fn, strlen(fi->fn) + 1) < 0) ohshite(_("failed to write filename to tar pipe (%s)"), _("data member")); file_info_list_free(symlist); }
/** * Overly complex function that builds a .deb file. */ int do_build(const char *const *argv) { const char *debar, *dir; bool subdir; char *tfbuf; int arfd; int p1[2], p2[2], p3[2], gzfd; pid_t c1,c2,c3; struct file_info *fi; struct file_info *symlist = NULL; struct file_info *symlist_end = NULL; /* Decode our arguments. */ dir = *argv++; if (!dir) badusage(_("--%s needs a <directory> argument"), cipaction->olong); subdir = false; debar = *argv++; if (debar != NULL) { struct stat debarstab; if (*argv) badusage(_("--build takes at most two arguments")); if (stat(debar, &debarstab)) { if (errno != ENOENT) ohshite(_("unable to check for existence of archive `%.250s'"), debar); } else if (S_ISDIR(debarstab.st_mode)) { subdir = true; } } else { char *m; m= m_malloc(strlen(dir) + sizeof(DEBEXT)); strcpy(m, dir); path_trim_slash_slashdot(m); strcat(m, DEBEXT); debar= m; } /* Perform some sanity checks on the to-be-build package. */ if (nocheckflag) { if (subdir) ohshit(_("target is directory - cannot skip control file check")); warning(_("not checking contents of control area.")); printf(_("dpkg-deb: building an unknown package in '%s'.\n"), debar); } else { struct pkginfo *pkg; pkg = check_new_pkg(dir); if (subdir) debar = pkg_get_pathname(debar, pkg); printf(_("dpkg-deb: building package `%s' in `%s'.\n"), pkgbin_name(pkg, &pkg->available, pnaw_nonambig), debar); } m_output(stdout, _("<standard output>")); /* Now that we have verified everything its time to actually * build something. Let's start by making the ar-wrapper. */ arfd = creat(debar, 0644); if (arfd < 0) ohshite(_("unable to create `%.255s'"), debar); /* Fork a tar to package the control-section of the package. */ unsetenv("TAR_OPTIONS"); m_pipe(p1); c1 = subproc_fork(); if (!c1) { m_dup2(p1[1],1); close(p1[0]); close(p1[1]); if (chdir(dir)) ohshite(_("failed to chdir to `%.255s'"), dir); if (chdir(BUILDCONTROLDIR)) ohshite(_("failed to chdir to `%.255s'"), ".../DEBIAN"); execlp(TAR, "tar", "-cf", "-", "--format=gnu", ".", NULL); ohshite(_("unable to execute %s (%s)"), "tar -cf", TAR); } close(p1[1]); /* Create a temporary file to store the control data in. Immediately * unlink our temporary file so others can't mess with it. */ tfbuf = path_make_temp_template("dpkg-deb"); gzfd = mkstemp(tfbuf); if (gzfd == -1) ohshite(_("failed to make temporary file (%s)"), _("control member")); /* Make sure it's gone, the fd will remain until we close it. */ if (unlink(tfbuf)) ohshit(_("failed to unlink temporary file (%s), %s"), _("control member"), tfbuf); free(tfbuf); /* And run gzip to compress our control archive. */ c2 = subproc_fork(); if (!c2) { struct compress_params params; params.type = compressor_type_gzip; params.level = 9; params.strategy = NULL; compress_filter(¶ms, p1[0], gzfd, _("control member")); exit(0); } close(p1[0]); subproc_wait_check(c2, "gzip -9c", 0); subproc_wait_check(c1, "tar -cf", 0); if (lseek(gzfd, 0, SEEK_SET)) ohshite(_("failed to rewind temporary file (%s)"), _("control member")); /* We have our first file for the ar-archive. Write a header for it * to the package and insert it. */ if (oldformatflag) { struct stat controlstab; char versionbuf[40]; if (fstat(gzfd, &controlstab)) ohshite(_("failed to stat temporary file (%s)"), _("control member")); sprintf(versionbuf, "%-8s\n%jd\n", OLDARCHIVEVERSION, (intmax_t)controlstab.st_size); if (fd_write(arfd, versionbuf, strlen(versionbuf)) < 0) ohshite(_("error writing `%s'"), debar); fd_fd_copy(gzfd, arfd, -1, _("control member")); } else { const char deb_magic[] = ARCHIVEVERSION "\n"; dpkg_ar_put_magic(debar, arfd); dpkg_ar_member_put_mem(debar, arfd, DEBMAGIC, deb_magic, strlen(deb_magic)); dpkg_ar_member_put_file(debar, arfd, ADMINMEMBER, gzfd, -1); } close(gzfd); /* Control is done, now we need to archive the data. */ if (oldformatflag) { /* In old format, the data member is just concatenated after the * control member, so we do not need a temporary file and can use * the compression file descriptor. */ gzfd = arfd; } else { /* Start by creating a new temporary file. Immediately unlink the * temporary file so others can't mess with it. */ tfbuf = path_make_temp_template("dpkg-deb"); gzfd = mkstemp(tfbuf); if (gzfd == -1) ohshite(_("failed to make temporary file (%s)"), _("data member")); /* Make sure it's gone, the fd will remain until we close it. */ if (unlink(tfbuf)) ohshit(_("failed to unlink temporary file (%s), %s"), _("data member"), tfbuf); free(tfbuf); } /* Fork off a tar. We will feed it a list of filenames on stdin later. */ m_pipe(p1); m_pipe(p2); c1 = subproc_fork(); if (!c1) { m_dup2(p1[0],0); close(p1[0]); close(p1[1]); m_dup2(p2[1],1); close(p2[0]); close(p2[1]); if (chdir(dir)) ohshite(_("failed to chdir to `%.255s'"), dir); execlp(TAR, "tar", "-cf", "-", "--format=gnu", "--null", "-T", "-", "--no-recursion", NULL); ohshite(_("unable to execute %s (%s)"), "tar -cf", TAR); } close(p1[0]); close(p2[1]); /* Of course we should not forget to compress the archive as well. */ c2 = subproc_fork(); if (!c2) { close(p1[1]); compress_filter(&compress_params, p2[0], gzfd, _("data member")); exit(0); } close(p2[0]); /* All the pipes are set, now lets run find, and start feeding * filenames to tar. */ m_pipe(p3); c3 = subproc_fork(); if (!c3) { m_dup2(p3[1],1); close(p3[0]); close(p3[1]); if (chdir(dir)) ohshite(_("failed to chdir to `%.255s'"), dir); execlp(FIND, "find", ".", "-path", "./" BUILDCONTROLDIR, "-prune", "-o", "-print0", NULL); ohshite(_("unable to execute %s (%s)"), "find", FIND); } close(p3[1]); /* We need to reorder the files so we can make sure that symlinks * will not appear before their target. */ while ((fi = file_info_get(dir, p3[0])) != NULL) if (S_ISLNK(fi->st.st_mode)) file_info_list_append(&symlist, &symlist_end, fi); else { if (fd_write(p1[1], fi->fn, strlen(fi->fn) + 1) < 0) ohshite(_("failed to write filename to tar pipe (%s)"), _("data member")); file_info_free(fi); } close(p3[0]); subproc_wait_check(c3, "find", 0); for (fi= symlist;fi;fi= fi->next) if (fd_write(p1[1], fi->fn, strlen(fi->fn) + 1) < 0) ohshite(_("failed to write filename to tar pipe (%s)"), _("data member")); /* All done, clean up wait for tar and gzip to finish their job. */ close(p1[1]); file_info_list_free(symlist); subproc_wait_check(c2, _("<compress> from tar -cf"), 0); subproc_wait_check(c1, "tar -cf", 0); /* Okay, we have data.tar as well now, add it to the ar wrapper. */ if (!oldformatflag) { char datamember[16 + 1]; sprintf(datamember, "%s%s", DATAMEMBER, compressor_get_extension(compress_params.type)); if (lseek(gzfd, 0, SEEK_SET)) ohshite(_("failed to rewind temporary file (%s)"), _("data member")); dpkg_ar_member_put_file(debar, arfd, datamember, gzfd, -1); } if (fsync(arfd)) ohshite(_("unable to sync file '%s'"), debar); if (close(arfd)) ohshite(_("unable to close file '%s'"), debar); return 0; }