123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523 |
- /*
- * libdpkg - Debian packaging suite library routines
- * dump.c - code to write in-core database to a file
- *
- * Copyright © 1995 Ian Jackson <ijackson@chiark.greenend.org.uk>
- * Copyright © 2001 Wichert Akkerman
- * Copyright © 2006,2008-2014 Guillem Jover <guillem@debian.org>
- * Copyright © 2011 Linaro Limited
- * Copyright © 2011 Raphaël Hertzog <hertzog@debian.org>
- *
- * This is free software; you can redistribute it and/or modify
- * it under the terms of the GNU General Public License as published by
- * the Free Software Foundation; either version 2 of the License, or
- * (at your option) any later version.
- *
- * This is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
- * GNU General Public License for more details.
- *
- * You should have received a copy of the GNU General Public License
- * along with this program. If not, see <https://www.gnu.org/licenses/>.
- */
- /* FIXME: Don't write uninteresting packages. */
- #include <config.h>
- #include <compat.h>
- #include <sys/types.h>
- #include <sys/stat.h>
- #include <assert.h>
- #include <errno.h>
- #include <string.h>
- #include <unistd.h>
- #include <stdio.h>
- #include <stdlib.h>
- #include <stdbool.h>
- #include <dpkg/i18n.h>
- #include <dpkg/dpkg.h>
- #include <dpkg/dpkg-db.h>
- #include <dpkg/string.h>
- #include <dpkg/dir.h>
- #include <dpkg/parsedump.h>
- static inline void
- varbuf_add_fieldname(struct varbuf *vb, const struct fieldinfo *fip)
- {
- varbuf_add_str(vb, fip->name);
- varbuf_add_str(vb, ": ");
- }
- void
- w_name(struct varbuf *vb,
- const struct pkginfo *pkg, const struct pkgbin *pkgbin,
- enum fwriteflags flags, const struct fieldinfo *fip)
- {
- assert(pkg->set->name);
- if (flags&fw_printheader)
- varbuf_add_str(vb, "Package: ");
- varbuf_add_str(vb, pkg->set->name);
- if (flags&fw_printheader)
- varbuf_add_char(vb, '\n');
- }
- void
- w_version(struct varbuf *vb,
- const struct pkginfo *pkg, const struct pkgbin *pkgbin,
- enum fwriteflags flags, const struct fieldinfo *fip)
- {
- if (!dpkg_version_is_informative(&pkgbin->version))
- return;
- if (flags&fw_printheader)
- varbuf_add_str(vb, "Version: ");
- varbufversion(vb, &pkgbin->version, vdew_nonambig);
- if (flags&fw_printheader)
- varbuf_add_char(vb, '\n');
- }
- void
- w_configversion(struct varbuf *vb,
- const struct pkginfo *pkg, const struct pkgbin *pkgbin,
- enum fwriteflags flags, const struct fieldinfo *fip)
- {
- if (pkgbin != &pkg->installed)
- return;
- if (!dpkg_version_is_informative(&pkg->configversion))
- return;
- if (pkg->status == PKG_STAT_INSTALLED ||
- pkg->status == PKG_STAT_NOTINSTALLED ||
- pkg->status == PKG_STAT_TRIGGERSPENDING)
- return;
- if (flags&fw_printheader)
- varbuf_add_str(vb, "Config-Version: ");
- varbufversion(vb, &pkg->configversion, vdew_nonambig);
- if (flags&fw_printheader)
- varbuf_add_char(vb, '\n');
- }
- void
- w_null(struct varbuf *vb,
- const struct pkginfo *pkg, const struct pkgbin *pkgbin,
- enum fwriteflags flags, const struct fieldinfo *fip)
- {
- }
- void
- w_section(struct varbuf *vb,
- const struct pkginfo *pkg, const struct pkgbin *pkgbin,
- enum fwriteflags flags, const struct fieldinfo *fip)
- {
- const char *value = pkg->section;
- if (str_is_unset(value))
- return;
- if (flags&fw_printheader)
- varbuf_add_str(vb, "Section: ");
- varbuf_add_str(vb, value);
- if (flags&fw_printheader)
- varbuf_add_char(vb, '\n');
- }
- void
- w_charfield(struct varbuf *vb,
- const struct pkginfo *pkg, const struct pkgbin *pkgbin,
- enum fwriteflags flags, const struct fieldinfo *fip)
- {
- const char *value = STRUCTFIELD(pkgbin, fip->integer, const char *);
- if (str_is_unset(value))
- return;
- if (flags & fw_printheader)
- varbuf_add_fieldname(vb, fip);
- varbuf_add_str(vb, value);
- if (flags&fw_printheader)
- varbuf_add_char(vb, '\n');
- }
- void
- w_filecharf(struct varbuf *vb,
- const struct pkginfo *pkg, const struct pkgbin *pkgbin,
- enum fwriteflags flags, const struct fieldinfo *fip)
- {
- struct filedetails *fdp;
- if (pkgbin != &pkg->available)
- return;
- fdp = pkg->files;
- if (!fdp || !STRUCTFIELD(fdp, fip->integer, const char *))
- return;
- if (flags&fw_printheader) {
- varbuf_add_str(vb, fip->name);
- varbuf_add_char(vb, ':');
- }
- while (fdp) {
- varbuf_add_char(vb, ' ');
- varbuf_add_str(vb, STRUCTFIELD(fdp, fip->integer, const char *));
- fdp= fdp->next;
- }
- if (flags&fw_printheader)
- varbuf_add_char(vb, '\n');
- }
- void
- w_booleandefno(struct varbuf *vb,
- const struct pkginfo *pkg, const struct pkgbin *pkgbin,
- enum fwriteflags flags, const struct fieldinfo *fip)
- {
- bool value = STRUCTFIELD(pkgbin, fip->integer, bool);
- if ((flags & fw_printheader) && !value)
- return;
- if (flags & fw_printheader)
- varbuf_add_fieldname(vb, fip);
- varbuf_add_str(vb, value ? "yes" : "no");
- if (flags & fw_printheader)
- varbuf_add_char(vb, '\n');
- }
- void
- w_multiarch(struct varbuf *vb,
- const struct pkginfo *pkg, const struct pkgbin *pkgbin,
- enum fwriteflags flags, const struct fieldinfo *fip)
- {
- int value = STRUCTFIELD(pkgbin, fip->integer, int);
- if ((flags & fw_printheader) && !value)
- return;
- if (flags & fw_printheader)
- varbuf_add_fieldname(vb, fip);
- varbuf_add_str(vb, multiarchinfos[value].name);
- if (flags & fw_printheader)
- varbuf_add_char(vb, '\n');
- }
- void
- w_architecture(struct varbuf *vb,
- const struct pkginfo *pkg, const struct pkgbin *pkgbin,
- enum fwriteflags flags, const struct fieldinfo *fip)
- {
- if (!pkgbin->arch)
- return;
- if (pkgbin->arch->type == DPKG_ARCH_NONE)
- return;
- if (pkgbin->arch->type == DPKG_ARCH_EMPTY)
- return;
- if (flags & fw_printheader)
- varbuf_add_fieldname(vb, fip);
- varbuf_add_str(vb, pkgbin->arch->name);
- if (flags & fw_printheader)
- varbuf_add_char(vb, '\n');
- }
- void
- w_priority(struct varbuf *vb,
- const struct pkginfo *pkg, const struct pkgbin *pkgbin,
- enum fwriteflags flags, const struct fieldinfo *fip)
- {
- if (pkg->priority == PKG_PRIO_UNKNOWN)
- return;
- assert(pkg->priority <= PKG_PRIO_UNKNOWN);
- if (flags&fw_printheader)
- varbuf_add_str(vb, "Priority: ");
- varbuf_add_str(vb, pkg_priority_name(pkg));
- if (flags&fw_printheader)
- varbuf_add_char(vb, '\n');
- }
- void
- w_status(struct varbuf *vb,
- const struct pkginfo *pkg, const struct pkgbin *pkgbin,
- enum fwriteflags flags, const struct fieldinfo *fip)
- {
- if (pkgbin != &pkg->installed)
- return;
- assert(pkg->want <= PKG_WANT_PURGE);
- assert(pkg->eflag <= PKG_EFLAG_REINSTREQ);
- #define PEND pkg->trigpend_head
- #define AW pkg->trigaw.head
- switch (pkg->status) {
- case PKG_STAT_NOTINSTALLED:
- case PKG_STAT_CONFIGFILES:
- assert(!PEND);
- assert(!AW);
- break;
- case PKG_STAT_HALFINSTALLED:
- case PKG_STAT_UNPACKED:
- case PKG_STAT_HALFCONFIGURED:
- assert(!PEND);
- break;
- case PKG_STAT_TRIGGERSAWAITED:
- assert(AW);
- break;
- case PKG_STAT_TRIGGERSPENDING:
- assert(PEND);
- assert(!AW);
- break;
- case PKG_STAT_INSTALLED:
- assert(!PEND);
- assert(!AW);
- break;
- default:
- internerr("unknown package status '%d'", pkg->status);
- }
- #undef PEND
- #undef AW
- if (flags&fw_printheader)
- varbuf_add_str(vb, "Status: ");
- varbuf_add_str(vb, pkg_want_name(pkg));
- varbuf_add_char(vb, ' ');
- varbuf_add_str(vb, pkg_eflag_name(pkg));
- varbuf_add_char(vb, ' ');
- varbuf_add_str(vb, pkg_status_name(pkg));
- if (flags&fw_printheader)
- varbuf_add_char(vb, '\n');
- }
- void varbufdependency(struct varbuf *vb, struct dependency *dep) {
- struct deppossi *dop;
- const char *possdel;
- possdel= "";
- for (dop= dep->list; dop; dop= dop->next) {
- assert(dop->up == dep);
- varbuf_add_str(vb, possdel);
- possdel = " | ";
- varbuf_add_str(vb, dop->ed->name);
- if (!dop->arch_is_implicit)
- varbuf_add_archqual(vb, dop->arch);
- if (dop->verrel != DPKG_RELATION_NONE) {
- varbuf_add_str(vb, " (");
- switch (dop->verrel) {
- case DPKG_RELATION_EQ:
- varbuf_add_char(vb, '=');
- break;
- case DPKG_RELATION_GE:
- varbuf_add_str(vb, ">=");
- break;
- case DPKG_RELATION_LE:
- varbuf_add_str(vb, "<=");
- break;
- case DPKG_RELATION_GT:
- varbuf_add_str(vb, ">>");
- break;
- case DPKG_RELATION_LT:
- varbuf_add_str(vb, "<<");
- break;
- default:
- internerr("unknown dpkg_relation %d", dop->verrel);
- }
- varbuf_add_char(vb, ' ');
- varbufversion(vb,&dop->version,vdew_nonambig);
- varbuf_add_char(vb, ')');
- }
- }
- }
- void
- w_dependency(struct varbuf *vb,
- const struct pkginfo *pkg, const struct pkgbin *pkgbin,
- enum fwriteflags flags, const struct fieldinfo *fip)
- {
- struct dependency *dyp;
- bool dep_found = false;
- for (dyp = pkgbin->depends; dyp; dyp = dyp->next) {
- if (dyp->type != fip->integer) continue;
- assert(dyp->up == pkg);
- if (dep_found) {
- varbuf_add_str(vb, ", ");
- } else {
- if (flags & fw_printheader)
- varbuf_add_fieldname(vb, fip);
- dep_found = true;
- }
- varbufdependency(vb,dyp);
- }
- if ((flags & fw_printheader) && dep_found)
- varbuf_add_char(vb, '\n');
- }
- void
- w_conffiles(struct varbuf *vb,
- const struct pkginfo *pkg, const struct pkgbin *pkgbin,
- enum fwriteflags flags, const struct fieldinfo *fip)
- {
- struct conffile *i;
- if (!pkgbin->conffiles || pkgbin == &pkg->available)
- return;
- if (flags&fw_printheader)
- varbuf_add_str(vb, "Conffiles:\n");
- for (i = pkgbin->conffiles; i; i = i->next) {
- if (i != pkgbin->conffiles)
- varbuf_add_char(vb, '\n');
- varbuf_add_char(vb, ' ');
- varbuf_add_str(vb, i->name);
- varbuf_add_char(vb, ' ');
- varbuf_add_str(vb, i->hash);
- if (i->obsolete)
- varbuf_add_str(vb, " obsolete");
- }
- if (flags&fw_printheader)
- varbuf_add_char(vb, '\n');
- }
- void
- w_trigpend(struct varbuf *vb,
- const struct pkginfo *pkg, const struct pkgbin *pkgbin,
- enum fwriteflags flags, const struct fieldinfo *fip)
- {
- struct trigpend *tp;
- if (pkgbin == &pkg->available || !pkg->trigpend_head)
- return;
- assert(pkg->status >= PKG_STAT_TRIGGERSAWAITED &&
- pkg->status <= PKG_STAT_TRIGGERSPENDING);
- if (flags & fw_printheader)
- varbuf_add_str(vb, "Triggers-Pending:");
- for (tp = pkg->trigpend_head; tp; tp = tp->next) {
- varbuf_add_char(vb, ' ');
- varbuf_add_str(vb, tp->name);
- }
- if (flags & fw_printheader)
- varbuf_add_char(vb, '\n');
- }
- void
- w_trigaw(struct varbuf *vb,
- const struct pkginfo *pkg, const struct pkgbin *pkgbin,
- enum fwriteflags flags, const struct fieldinfo *fip)
- {
- struct trigaw *ta;
- if (pkgbin == &pkg->available || !pkg->trigaw.head)
- return;
- assert(pkg->status > PKG_STAT_CONFIGFILES &&
- pkg->status <= PKG_STAT_TRIGGERSAWAITED);
- if (flags & fw_printheader)
- varbuf_add_str(vb, "Triggers-Awaited:");
- for (ta = pkg->trigaw.head; ta; ta = ta->sameaw.next) {
- varbuf_add_char(vb, ' ');
- varbuf_add_pkgbin_name(vb, ta->pend, &ta->pend->installed, pnaw_nonambig);
- }
- if (flags & fw_printheader)
- varbuf_add_char(vb, '\n');
- }
- void
- varbuf_add_arbfield(struct varbuf *vb, const struct arbitraryfield *arbfield,
- enum fwriteflags flags)
- {
- if (flags & fw_printheader) {
- varbuf_add_str(vb, arbfield->name);
- varbuf_add_str(vb, ": ");
- }
- varbuf_add_str(vb, arbfield->value);
- if (flags & fw_printheader)
- varbuf_add_char(vb, '\n');
- }
- void
- varbufrecord(struct varbuf *vb,
- const struct pkginfo *pkg, const struct pkgbin *pkgbin)
- {
- const struct fieldinfo *fip;
- const struct arbitraryfield *afp;
- for (fip= fieldinfos; fip->name; fip++) {
- fip->wcall(vb, pkg, pkgbin, fw_printheader, fip);
- }
- for (afp = pkgbin->arbs; afp; afp = afp->next) {
- varbuf_add_arbfield(vb, afp, fw_printheader);
- }
- }
- void
- writerecord(FILE *file, const char *filename,
- const struct pkginfo *pkg, const struct pkgbin *pkgbin)
- {
- struct varbuf vb = VARBUF_INIT;
- varbufrecord(&vb, pkg, pkgbin);
- varbuf_end_str(&vb);
- if (fputs(vb.buf,file) < 0) {
- struct varbuf pkgname = VARBUF_INIT;
- int errno_saved = errno;
- varbuf_add_pkgbin_name(&pkgname, pkg, pkgbin, pnaw_nonambig);
- errno = errno_saved;
- ohshite(_("failed to write details of '%.50s' to '%.250s'"),
- pkgname.buf, filename);
- }
- varbuf_destroy(&vb);
- }
- void
- writedb(const char *filename, enum writedb_flags flags)
- {
- static char writebuf[8192];
- struct pkgiterator *iter;
- struct pkginfo *pkg;
- struct pkgbin *pkgbin;
- const char *which;
- struct atomic_file *file;
- struct varbuf vb = VARBUF_INIT;
- which = (flags & wdb_dump_available) ? "available" : "status";
- file = atomic_file_new(filename, ATOMIC_FILE_BACKUP);
- atomic_file_open(file);
- if (setvbuf(file->fp, writebuf, _IOFBF, sizeof(writebuf)))
- ohshite(_("unable to set buffering on %s database file"), which);
- iter = pkg_db_iter_new();
- while ((pkg = pkg_db_iter_next_pkg(iter)) != NULL) {
- pkgbin = (flags & wdb_dump_available) ? &pkg->available : &pkg->installed;
- /* Don't dump records which have no useful content. */
- if (!pkg_is_informative(pkg, pkgbin))
- continue;
- varbufrecord(&vb, pkg, pkgbin);
- varbuf_add_char(&vb, '\n');
- varbuf_end_str(&vb);
- if (fputs(vb.buf, file->fp) < 0)
- ohshite(_("failed to write %s database record about '%.50s' to '%.250s'"),
- which, pkgbin_name(pkg, pkgbin, pnaw_nonambig), filename);
- varbuf_reset(&vb);
- }
- pkg_db_iter_free(iter);
- varbuf_destroy(&vb);
- if (flags & wdb_must_sync)
- atomic_file_sync(file);
- atomic_file_close(file);
- atomic_file_commit(file);
- atomic_file_free(file);
- if (flags & wdb_must_sync)
- dir_sync_path_parent(filename);
- }
|