/** * 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; }