static void info_prepare(const char *const **argvp, const char **debarp, const char **dirp, int admininfo) { char *dbuf; *debarp= *(*argvp)++; if (!*debarp) badusage(_("--%s needs a .deb filename argument"),cipaction->olong); dbuf = mkdtemp(path_make_temp_template("dpkg-deb")); if (!dbuf) ohshite(_("unable to create temporary directory")); *dirp = dbuf; push_cleanup(cu_info_prepare, -1, NULL, 0, 1, (void *)dbuf); extracthalf(*debarp, dbuf, DPKG_TAR_EXTRACT | DPKG_TAR_NOMTIME, admininfo); }
static char * get_control_dir(char *cidir) { if (f_noact) { char *tmpdir; tmpdir = mkdtemp(path_make_temp_template("dpkg")); if (tmpdir == NULL) ohshite(_("unable to create temporary directory")); cidir = m_realloc(cidir, strlen(tmpdir) + MAXCONTROLFILENAME + 10); strcpy(cidir, tmpdir); free(tmpdir); } else { const char *admindir; admindir = dpkg_db_get_dir(); /* The admindir length is always constant on a dpkg execution run. */ if (cidir == NULL) cidir = m_malloc(strlen(admindir) + sizeof(CONTROLDIRTMP) + MAXCONTROLFILENAME + 10); /* We want it to be on the same filesystem so that we can * use rename(2) to install the postinst &c. */ strcpy(cidir, admindir); strcat(cidir, "/" CONTROLDIRTMP); /* Make sure the control information directory is empty. */ ensure_pathname_nonexisting(cidir); } strcat(cidir, "/"); return cidir; }
/** * Overly complex function that builds a .deb file. */ int do_build(const char *const *argv) { struct compress_params control_compress_params; struct dpkg_error err; struct dpkg_ar *ar; time_t timestamp; const char *timestamp_str; const char *dir, *dest; char *ctrldir; char *debar; char *tfbuf; int gzfd; /* Decode our arguments. */ dir = *argv++; if (!dir) badusage(_("--%s needs a <directory> argument"), cipaction->olong); dest = *argv++; if (dest && *argv) badusage(_("--%s takes at most two arguments"), cipaction->olong); debar = gen_dest_pathname(dir, dest); ctrldir = str_fmt("%s/%s", dir, BUILDCONTROLDIR); /* Perform some sanity checks on the to-be-build package. */ if (nocheckflag) { if (debar == NULL) ohshit(_("target is directory - cannot skip control file check")); warning(_("not checking contents of control area")); info(_("building an unknown package in '%s'."), debar); } else { struct pkginfo *pkg; pkg = check_control_area(ctrldir, dir); if (debar == NULL) debar = gen_dest_pathname_from_pkg(dest, pkg); info(_("building package '%s' in '%s'."), pkg->set->name, debar); } m_output(stdout, _("<standard output>")); timestamp_str = getenv("SOURCE_DATE_EPOCH"); if (timestamp_str) timestamp = parse_timestamp(timestamp_str); else timestamp = time(NULL); /* Now that we have verified everything its time to actually * build something. Let's start by making the ar-wrapper. */ ar = dpkg_ar_create(debar, 0644); dpkg_ar_set_mtime(ar, timestamp); unsetenv("TAR_OPTIONS"); /* 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); /* Select the compressor to use for our control archive. */ if (opt_uniform_compression) { control_compress_params = compress_params; } else { control_compress_params.type = COMPRESSOR_TYPE_GZIP; control_compress_params.strategy = COMPRESSOR_STRATEGY_NONE; control_compress_params.level = -1; if (!compressor_check_params(&control_compress_params, &err)) internerr("invalid control member compressor params: %s", err.str); } /* Fork a tar to package the control-section of the package. */ tarball_pack(ctrldir, control_treewalk_feed, timestamp, &control_compress_params, gzfd); free(ctrldir); 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 (deb_format.major == 0) { 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(ar->fd, versionbuf, strlen(versionbuf)) < 0) ohshite(_("error writing '%s'"), debar); if (fd_fd_copy(gzfd, ar->fd, -1, &err) < 0) ohshit(_("cannot copy '%s' into archive '%s': %s"), _("control member"), ar->name, err.str); } else if (deb_format.major == 2) { const char deb_magic[] = ARCHIVEVERSION "\n"; char adminmember[16 + 1]; sprintf(adminmember, "%s%s", ADMINMEMBER, compressor_get_extension(control_compress_params.type)); dpkg_ar_put_magic(ar); dpkg_ar_member_put_mem(ar, DEBMAGIC, deb_magic, strlen(deb_magic)); dpkg_ar_member_put_file(ar, adminmember, gzfd, -1); } else { internerr("unknown deb format version %d.%d", deb_format.major, deb_format.minor); } close(gzfd); /* Control is done, now we need to archive the data. */ if (deb_format.major == 0) { /* 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 = ar->fd; } else if (deb_format.major == 2) { /* 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); } else { internerr("unknown deb format version %d.%d", deb_format.major, deb_format.minor); } /* Pack the directory into a tarball, feeding files from the callback. */ tarball_pack(dir, file_treewalk_feed, timestamp, &compress_params, gzfd); /* Okay, we have data.tar as well now, add it to the ar wrapper. */ if (deb_format.major == 2) { 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(ar, datamember, gzfd, -1); close(gzfd); } if (fsync(ar->fd)) ohshite(_("unable to sync file '%s'"), ar->name); dpkg_ar_close(ar); free(debar); return 0; }
/** * Overly complex function that builds a .deb file. */ int do_build(const char *const *argv) { struct dpkg_error err; const char *debar, *dir; bool subdir; char *tfbuf; int arfd; int p1[2], p2[2], gzfd; pid_t c1, c2; /* 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(_("--%s takes at most two arguments"), cipaction->olong); 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"), pkg->set->name, 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.strategy = compressor_strategy_none; params.level = 9; compress_filter(¶ms, p1[0], gzfd, _("compressing 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 (deb_format.major == 0) { 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); if (fd_fd_copy(gzfd, arfd, -1, &err) < 0) ohshit(_("cannot copy '%s' into archive '%s': %s"), _("control member"), debar, err.str); } else if (deb_format.major == 2) { 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); } else { internerr("unknown deb format version %d.%d", deb_format.major, deb_format.minor); } close(gzfd); /* Control is done, now we need to archive the data. */ if (deb_format.major == 0) { /* 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 if (deb_format.major == 2) { /* 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); } else { internerr("unknown deb format version %d.%d", deb_format.major, deb_format.minor); } /* 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, _("compressing data member")); exit(0); } close(p2[0]); /* All the pipes are set, now lets walk the tree, and start feeding * filenames to tar. */ file_treewalk_feed(dir, p1[1]); /* All done, clean up wait for tar and gzip to finish their job. */ close(p1[1]); 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 (deb_format.major == 2) { 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); close(gzfd); } if (fsync(arfd)) ohshite(_("unable to sync file '%s'"), debar); if (close(arfd)) ohshite(_("unable to close file '%s'"), debar); return 0; }
/** * Overly complex function that builds a .deb file. */ void do_build(const char *const *argv) { static const char *const maintainerscripts[]= { PREINSTFILE, POSTINSTFILE, PRERMFILE, POSTRMFILE, NULL }; char *m; const char *debar, *directory, *const *mscriptp, *versionstring, *arch; bool subdir; char *controlfile, *tfbuf; struct pkginfo *checkedinfo; struct arbitraryfield *field; FILE *ar, *cf; int p1[2], p2[2], p3[2], warns, n, c, gzfd; pid_t c1,c2,c3; struct stat controlstab, mscriptstab, debarstab; char conffilename[MAXCONFFILENAME+1]; struct file_info *fi; struct file_info *symlist = NULL; struct file_info *symlist_end = NULL; /* Decode our arguments. */ directory = *argv++; if (!directory) badusage(_("--%s needs a <directory> argument"), cipaction->olong); subdir = false; debar = *argv++; if (debar != NULL) { if (*argv) badusage(_("--build takes at most two arguments")); if (debar) { 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 { m= m_malloc(strlen(directory) + sizeof(DEBEXT)); strcpy(m, directory); 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 { controlfile= m_malloc(strlen(directory) + sizeof(BUILDCONTROLDIR) + sizeof(CONTROLFILE) + sizeof(CONFFILESFILE) + sizeof(POSTINSTFILE) + sizeof(PREINSTFILE) + sizeof(POSTRMFILE) + sizeof(PRERMFILE) + MAXCONFFILENAME + 5); /* Let's start by reading in the control-file so we can check its * contents. */ strcpy(controlfile, directory); strcat(controlfile, "/" BUILDCONTROLDIR "/" CONTROLFILE); warns = 0; parsedb(controlfile, pdb_recordavailable|pdb_rejectstatus, &checkedinfo, &warns); if (strspn(checkedinfo->name, "abcdefghijklmnopqrstuvwxyz0123456789+-.") != strlen(checkedinfo->name)) ohshit(_("package name has characters that aren't lowercase alphanums or `-+.'")); if (checkedinfo->priority == pri_other) { warning(_("'%s' contains user-defined Priority value '%s'"), controlfile, checkedinfo->otherpriority); warns++; } for (field= checkedinfo->available.arbs; field; field= field->next) { if (known_arbitrary_field(field)) continue; warning(_("'%s' contains user-defined field '%s'"), controlfile, field->name); warns++; } if (subdir) { versionstring= versiondescribe(&checkedinfo->available.version,vdew_never); arch= checkedinfo->available.architecture; if (!arch) arch= ""; m= m_malloc(sizeof(DEBEXT)+1+strlen(debar)+1+strlen(checkedinfo->name)+ strlen(versionstring)+1+strlen(arch)); sprintf(m,"%s/%s_%s%s%s" DEBEXT,debar,checkedinfo->name,versionstring, arch[0] ? "_" : "", arch); debar= m; } printf(_("dpkg-deb: building package `%s' in `%s'.\n"), checkedinfo->name, debar); /* Check file permissions. */ strcpy(controlfile, directory); strcat(controlfile, "/" BUILDCONTROLDIR "/"); if (lstat(controlfile, &mscriptstab)) ohshite(_("unable to stat control directory")); if (!S_ISDIR(mscriptstab.st_mode)) ohshit(_("control directory is not a directory")); if ((mscriptstab.st_mode & 07757) != 0755) ohshit(_("control directory has bad permissions %03lo (must be >=0755 " "and <=0775)"), (unsigned long)(mscriptstab.st_mode & 07777)); for (mscriptp= maintainerscripts; *mscriptp; mscriptp++) { strcpy(controlfile, directory); strcat(controlfile, "/" BUILDCONTROLDIR "/"); strcat(controlfile, *mscriptp); if (!lstat(controlfile,&mscriptstab)) { if (S_ISLNK(mscriptstab.st_mode)) continue; if (!S_ISREG(mscriptstab.st_mode)) ohshit(_("maintainer script `%.50s' is not a plain file or symlink"),*mscriptp); if ((mscriptstab.st_mode & 07557) != 0555) ohshit(_("maintainer script `%.50s' has bad permissions %03lo " "(must be >=0555 and <=0775)"), *mscriptp, (unsigned long)(mscriptstab.st_mode & 07777)); } else if (errno != ENOENT) { ohshite(_("maintainer script `%.50s' is not stattable"),*mscriptp); } } /* Check if conffiles contains sane information. */ strcpy(controlfile, directory); strcat(controlfile, "/" BUILDCONTROLDIR "/" CONFFILESFILE); if ((cf= fopen(controlfile,"r"))) { struct file_info *conffiles_head = NULL; struct file_info *conffiles_tail = NULL; while (fgets(conffilename,MAXCONFFILENAME+1,cf)) { n= strlen(conffilename); if (!n) ohshite(_("empty string from fgets reading conffiles")); if (conffilename[n-1] != '\n') { warning(_("conffile name '%.50s...' is too long, or missing final newline"), conffilename); warns++; while ((c= getc(cf)) != EOF && c != '\n'); continue; } conffilename[n - 1] = '\0'; strcpy(controlfile, directory); strcat(controlfile, "/"); strcat(controlfile, conffilename); if (lstat(controlfile,&controlstab)) { if (errno == ENOENT) { if((n > 1) && isspace(conffilename[n-2])) warning(_("conffile filename '%s' contains trailing white spaces"), conffilename); ohshit(_("conffile `%.250s' does not appear in package"), conffilename); } else ohshite(_("conffile `%.250s' is not stattable"), conffilename); } else if (!S_ISREG(controlstab.st_mode)) { warning(_("conffile '%s' is not a plain file"), conffilename); warns++; } if (file_info_find_name(conffiles_head, conffilename)) warning(_("conffile name '%s' is duplicated"), conffilename); else { struct file_info *conffile; conffile = file_info_new(conffilename); add_to_filist(&conffiles_head, &conffiles_tail, conffile); } } free_filist(conffiles_head); if (ferror(cf)) ohshite(_("error reading conffiles file")); fclose(cf); } else if (errno != ENOENT) { ohshite(_("error opening conffiles file")); } if (warns) warning(P_("ignoring %d warning about the control file(s)\n", "ignoring %d warnings about the control file(s)\n", warns), warns); } 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. */ if (!(ar=fopen(debar,"wb"))) ohshite(_("unable to create `%.255s'"),debar); if (setvbuf(ar, NULL, _IONBF, 0)) ohshite(_("unable to unbuffer `%.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(directory)) ohshite(_("failed to chdir to `%.255s'"),directory); 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) { m_dup2(p1[0],0); m_dup2(gzfd,1); close(p1[0]); close(gzfd); compress_filter(&compressor_gzip, 0, 1, 9, _("control member")); } 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) { if (fstat(gzfd, &controlstab)) ohshite(_("failed to stat temporary file (%s)"), _("control member")); if (fprintf(ar, "%-8s\n%ld\n", OLDARCHIVEVERSION, (long)controlstab.st_size) == EOF) werr(debar); fd_fd_copy(gzfd, fileno(ar), -1, _("control member")); } else { const char deb_magic[] = ARCHIVEVERSION "\n"; dpkg_ar_put_magic(debar, fileno(ar)); dpkg_ar_member_put_mem(debar, fileno(ar), DEBMAGIC, deb_magic, strlen(deb_magic)); dpkg_ar_member_put_file(debar, fileno(ar), ADMINMEMBER, gzfd); } /* Control is done, now we need to archive the data. Start by creating * a new temporary file. Immediately unlink the temporary file so others * can't mess with it. */ if (!oldformatflag) { close(gzfd); 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(directory)) ohshite(_("failed to chdir to `%.255s'"),directory); 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]); m_dup2(p2[0],0); close(p2[0]); m_dup2(oldformatflag ? fileno(ar) : gzfd,1); compress_filter(compressor, 0, 1, compress_level, _("data member")); } 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(directory)) ohshite(_("failed to chdir to `%.255s'"),directory); 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=getfi(directory, p3[0]))!=NULL) if (S_ISLNK(fi->st.st_mode)) add_to_filist(&symlist, &symlist_end, fi); else { if (write(p1[1], fi->fn, strlen(fi->fn)+1) ==- 1) 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 (write(p1[1], fi->fn, strlen(fi->fn)+1) == -1) 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]); free_filist(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->extension); if (lseek(gzfd, 0, SEEK_SET)) ohshite(_("failed to rewind temporary file (%s)"), _("data member")); dpkg_ar_member_put_file(debar, fileno(ar), datamember, gzfd); } if (fflush(ar)) ohshite(_("unable to flush file '%s'"), debar); if (fsync(fileno(ar))) ohshite(_("unable to sync file '%s'"), debar); if (fclose(ar)) werr(debar); exit(0); }