dpkg (1.18.25) stretch; urgency=medium
[dpkg] / lib / dpkg / dump.c
CommitLineData
1479465f
GJ
1/*
2 * libdpkg - Debian packaging suite library routines
3 * dump.c - code to write in-core database to a file
4 *
5 * Copyright © 1995 Ian Jackson <ijackson@chiark.greenend.org.uk>
6 * Copyright © 2001 Wichert Akkerman
7 * Copyright © 2006,2008-2014 Guillem Jover <guillem@debian.org>
8 * Copyright © 2011 Linaro Limited
9 * Copyright © 2011 Raphaël Hertzog <hertzog@debian.org>
10 *
11 * This is free software; you can redistribute it and/or modify
12 * it under the terms of the GNU General Public License as published by
13 * the Free Software Foundation; either version 2 of the License, or
14 * (at your option) any later version.
15 *
16 * This is distributed in the hope that it will be useful,
17 * but WITHOUT ANY WARRANTY; without even the implied warranty of
18 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
19 * GNU General Public License for more details.
20 *
21 * You should have received a copy of the GNU General Public License
22 * along with this program. If not, see <https://www.gnu.org/licenses/>.
23 */
24
25/* FIXME: Don't write uninteresting packages. */
26
27#include <config.h>
28#include <compat.h>
29
30#include <sys/types.h>
31#include <sys/stat.h>
32
33#include <assert.h>
34#include <errno.h>
35#include <string.h>
36#include <unistd.h>
37#include <stdio.h>
38#include <stdlib.h>
39#include <stdbool.h>
40
41#include <dpkg/i18n.h>
42#include <dpkg/dpkg.h>
43#include <dpkg/dpkg-db.h>
44#include <dpkg/string.h>
45#include <dpkg/dir.h>
46#include <dpkg/parsedump.h>
47
48static inline void
49varbuf_add_fieldname(struct varbuf *vb, const struct fieldinfo *fip)
50{
51 varbuf_add_str(vb, fip->name);
52 varbuf_add_str(vb, ": ");
53}
54
55void
56w_name(struct varbuf *vb,
57 const struct pkginfo *pkg, const struct pkgbin *pkgbin,
58 enum fwriteflags flags, const struct fieldinfo *fip)
59{
60 assert(pkg->set->name);
61 if (flags&fw_printheader)
62 varbuf_add_str(vb, "Package: ");
63 varbuf_add_str(vb, pkg->set->name);
64 if (flags&fw_printheader)
65 varbuf_add_char(vb, '\n');
66}
67
68void
69w_version(struct varbuf *vb,
70 const struct pkginfo *pkg, const struct pkgbin *pkgbin,
71 enum fwriteflags flags, const struct fieldinfo *fip)
72{
73 if (!dpkg_version_is_informative(&pkgbin->version))
74 return;
75 if (flags&fw_printheader)
76 varbuf_add_str(vb, "Version: ");
77 varbufversion(vb, &pkgbin->version, vdew_nonambig);
78 if (flags&fw_printheader)
79 varbuf_add_char(vb, '\n');
80}
81
82void
83w_configversion(struct varbuf *vb,
84 const struct pkginfo *pkg, const struct pkgbin *pkgbin,
85 enum fwriteflags flags, const struct fieldinfo *fip)
86{
87 if (pkgbin != &pkg->installed)
88 return;
89 if (!dpkg_version_is_informative(&pkg->configversion))
90 return;
91 if (pkg->status == PKG_STAT_INSTALLED ||
92 pkg->status == PKG_STAT_NOTINSTALLED ||
93 pkg->status == PKG_STAT_TRIGGERSPENDING)
94 return;
95 if (flags&fw_printheader)
96 varbuf_add_str(vb, "Config-Version: ");
97 varbufversion(vb, &pkg->configversion, vdew_nonambig);
98 if (flags&fw_printheader)
99 varbuf_add_char(vb, '\n');
100}
101
102void
103w_null(struct varbuf *vb,
104 const struct pkginfo *pkg, const struct pkgbin *pkgbin,
105 enum fwriteflags flags, const struct fieldinfo *fip)
106{
107}
108
109void
110w_section(struct varbuf *vb,
111 const struct pkginfo *pkg, const struct pkgbin *pkgbin,
112 enum fwriteflags flags, const struct fieldinfo *fip)
113{
114 const char *value = pkg->section;
115
116 if (str_is_unset(value))
117 return;
118 if (flags&fw_printheader)
119 varbuf_add_str(vb, "Section: ");
120 varbuf_add_str(vb, value);
121 if (flags&fw_printheader)
122 varbuf_add_char(vb, '\n');
123}
124
125void
126w_charfield(struct varbuf *vb,
127 const struct pkginfo *pkg, const struct pkgbin *pkgbin,
128 enum fwriteflags flags, const struct fieldinfo *fip)
129{
130 const char *value = STRUCTFIELD(pkgbin, fip->integer, const char *);
131
132 if (str_is_unset(value))
133 return;
134 if (flags & fw_printheader)
135 varbuf_add_fieldname(vb, fip);
136 varbuf_add_str(vb, value);
137 if (flags&fw_printheader)
138 varbuf_add_char(vb, '\n');
139}
140
141void
142w_filecharf(struct varbuf *vb,
143 const struct pkginfo *pkg, const struct pkgbin *pkgbin,
144 enum fwriteflags flags, const struct fieldinfo *fip)
145{
146 struct filedetails *fdp;
147
148 if (pkgbin != &pkg->available)
149 return;
150 fdp = pkg->files;
151 if (!fdp || !STRUCTFIELD(fdp, fip->integer, const char *))
152 return;
153
154 if (flags&fw_printheader) {
155 varbuf_add_str(vb, fip->name);
156 varbuf_add_char(vb, ':');
157 }
158
159 while (fdp) {
160 varbuf_add_char(vb, ' ');
161 varbuf_add_str(vb, STRUCTFIELD(fdp, fip->integer, const char *));
162 fdp= fdp->next;
163 }
164
165 if (flags&fw_printheader)
166 varbuf_add_char(vb, '\n');
167}
168
169void
170w_booleandefno(struct varbuf *vb,
171 const struct pkginfo *pkg, const struct pkgbin *pkgbin,
172 enum fwriteflags flags, const struct fieldinfo *fip)
173{
174 bool value = STRUCTFIELD(pkgbin, fip->integer, bool);
175
176 if ((flags & fw_printheader) && !value)
177 return;
178
179 if (flags & fw_printheader)
180 varbuf_add_fieldname(vb, fip);
181
182 varbuf_add_str(vb, value ? "yes" : "no");
183
184 if (flags & fw_printheader)
185 varbuf_add_char(vb, '\n');
186}
187
188void
189w_multiarch(struct varbuf *vb,
190 const struct pkginfo *pkg, const struct pkgbin *pkgbin,
191 enum fwriteflags flags, const struct fieldinfo *fip)
192{
193 int value = STRUCTFIELD(pkgbin, fip->integer, int);
194
195 if ((flags & fw_printheader) && !value)
196 return;
197
198 if (flags & fw_printheader)
199 varbuf_add_fieldname(vb, fip);
200
201 varbuf_add_str(vb, multiarchinfos[value].name);
202
203 if (flags & fw_printheader)
204 varbuf_add_char(vb, '\n');
205}
206
207void
208w_architecture(struct varbuf *vb,
209 const struct pkginfo *pkg, const struct pkgbin *pkgbin,
210 enum fwriteflags flags, const struct fieldinfo *fip)
211{
212 if (!pkgbin->arch)
213 return;
214 if (pkgbin->arch->type == DPKG_ARCH_NONE)
215 return;
216 if (pkgbin->arch->type == DPKG_ARCH_EMPTY)
217 return;
218
219 if (flags & fw_printheader)
220 varbuf_add_fieldname(vb, fip);
221 varbuf_add_str(vb, pkgbin->arch->name);
222 if (flags & fw_printheader)
223 varbuf_add_char(vb, '\n');
224}
225
226void
227w_priority(struct varbuf *vb,
228 const struct pkginfo *pkg, const struct pkgbin *pkgbin,
229 enum fwriteflags flags, const struct fieldinfo *fip)
230{
231 if (pkg->priority == PKG_PRIO_UNKNOWN)
232 return;
233 assert(pkg->priority <= PKG_PRIO_UNKNOWN);
234 if (flags&fw_printheader)
235 varbuf_add_str(vb, "Priority: ");
236 varbuf_add_str(vb, pkg_priority_name(pkg));
237 if (flags&fw_printheader)
238 varbuf_add_char(vb, '\n');
239}
240
241void
242w_status(struct varbuf *vb,
243 const struct pkginfo *pkg, const struct pkgbin *pkgbin,
244 enum fwriteflags flags, const struct fieldinfo *fip)
245{
246 if (pkgbin != &pkg->installed)
247 return;
248 assert(pkg->want <= PKG_WANT_PURGE);
249 assert(pkg->eflag <= PKG_EFLAG_REINSTREQ);
250
251#define PEND pkg->trigpend_head
252#define AW pkg->trigaw.head
253 switch (pkg->status) {
254 case PKG_STAT_NOTINSTALLED:
255 case PKG_STAT_CONFIGFILES:
256 assert(!PEND);
257 assert(!AW);
258 break;
259 case PKG_STAT_HALFINSTALLED:
260 case PKG_STAT_UNPACKED:
261 case PKG_STAT_HALFCONFIGURED:
262 assert(!PEND);
263 break;
264 case PKG_STAT_TRIGGERSAWAITED:
265 assert(AW);
266 break;
267 case PKG_STAT_TRIGGERSPENDING:
268 assert(PEND);
269 assert(!AW);
270 break;
271 case PKG_STAT_INSTALLED:
272 assert(!PEND);
273 assert(!AW);
274 break;
275 default:
276 internerr("unknown package status '%d'", pkg->status);
277 }
278#undef PEND
279#undef AW
280
281 if (flags&fw_printheader)
282 varbuf_add_str(vb, "Status: ");
283 varbuf_add_str(vb, pkg_want_name(pkg));
284 varbuf_add_char(vb, ' ');
285 varbuf_add_str(vb, pkg_eflag_name(pkg));
286 varbuf_add_char(vb, ' ');
287 varbuf_add_str(vb, pkg_status_name(pkg));
288 if (flags&fw_printheader)
289 varbuf_add_char(vb, '\n');
290}
291
292void varbufdependency(struct varbuf *vb, struct dependency *dep) {
293 struct deppossi *dop;
294 const char *possdel;
295
296 possdel= "";
297 for (dop= dep->list; dop; dop= dop->next) {
298 assert(dop->up == dep);
299 varbuf_add_str(vb, possdel);
300 possdel = " | ";
301 varbuf_add_str(vb, dop->ed->name);
302 if (!dop->arch_is_implicit)
303 varbuf_add_archqual(vb, dop->arch);
304 if (dop->verrel != DPKG_RELATION_NONE) {
305 varbuf_add_str(vb, " (");
306 switch (dop->verrel) {
307 case DPKG_RELATION_EQ:
308 varbuf_add_char(vb, '=');
309 break;
310 case DPKG_RELATION_GE:
311 varbuf_add_str(vb, ">=");
312 break;
313 case DPKG_RELATION_LE:
314 varbuf_add_str(vb, "<=");
315 break;
316 case DPKG_RELATION_GT:
317 varbuf_add_str(vb, ">>");
318 break;
319 case DPKG_RELATION_LT:
320 varbuf_add_str(vb, "<<");
321 break;
322 default:
323 internerr("unknown dpkg_relation %d", dop->verrel);
324 }
325 varbuf_add_char(vb, ' ');
326 varbufversion(vb,&dop->version,vdew_nonambig);
327 varbuf_add_char(vb, ')');
328 }
329 }
330}
331
332void
333w_dependency(struct varbuf *vb,
334 const struct pkginfo *pkg, const struct pkgbin *pkgbin,
335 enum fwriteflags flags, const struct fieldinfo *fip)
336{
337 struct dependency *dyp;
338 bool dep_found = false;
339
340 for (dyp = pkgbin->depends; dyp; dyp = dyp->next) {
341 if (dyp->type != fip->integer) continue;
342 assert(dyp->up == pkg);
343
344 if (dep_found) {
345 varbuf_add_str(vb, ", ");
346 } else {
347 if (flags & fw_printheader)
348 varbuf_add_fieldname(vb, fip);
349 dep_found = true;
350 }
351 varbufdependency(vb,dyp);
352 }
353 if ((flags & fw_printheader) && dep_found)
354 varbuf_add_char(vb, '\n');
355}
356
357void
358w_conffiles(struct varbuf *vb,
359 const struct pkginfo *pkg, const struct pkgbin *pkgbin,
360 enum fwriteflags flags, const struct fieldinfo *fip)
361{
362 struct conffile *i;
363
364 if (!pkgbin->conffiles || pkgbin == &pkg->available)
365 return;
366 if (flags&fw_printheader)
367 varbuf_add_str(vb, "Conffiles:\n");
368 for (i = pkgbin->conffiles; i; i = i->next) {
369 if (i != pkgbin->conffiles)
370 varbuf_add_char(vb, '\n');
371 varbuf_add_char(vb, ' ');
372 varbuf_add_str(vb, i->name);
373 varbuf_add_char(vb, ' ');
374 varbuf_add_str(vb, i->hash);
375 if (i->obsolete)
376 varbuf_add_str(vb, " obsolete");
377 }
378 if (flags&fw_printheader)
379 varbuf_add_char(vb, '\n');
380}
381
382void
383w_trigpend(struct varbuf *vb,
384 const struct pkginfo *pkg, const struct pkgbin *pkgbin,
385 enum fwriteflags flags, const struct fieldinfo *fip)
386{
387 struct trigpend *tp;
388
389 if (pkgbin == &pkg->available || !pkg->trigpend_head)
390 return;
391
392 assert(pkg->status >= PKG_STAT_TRIGGERSAWAITED &&
393 pkg->status <= PKG_STAT_TRIGGERSPENDING);
394
395 if (flags & fw_printheader)
396 varbuf_add_str(vb, "Triggers-Pending:");
397 for (tp = pkg->trigpend_head; tp; tp = tp->next) {
398 varbuf_add_char(vb, ' ');
399 varbuf_add_str(vb, tp->name);
400 }
401 if (flags & fw_printheader)
402 varbuf_add_char(vb, '\n');
403}
404
405void
406w_trigaw(struct varbuf *vb,
407 const struct pkginfo *pkg, const struct pkgbin *pkgbin,
408 enum fwriteflags flags, const struct fieldinfo *fip)
409{
410 struct trigaw *ta;
411
412 if (pkgbin == &pkg->available || !pkg->trigaw.head)
413 return;
414
415 assert(pkg->status > PKG_STAT_CONFIGFILES &&
416 pkg->status <= PKG_STAT_TRIGGERSAWAITED);
417
418 if (flags & fw_printheader)
419 varbuf_add_str(vb, "Triggers-Awaited:");
420 for (ta = pkg->trigaw.head; ta; ta = ta->sameaw.next) {
421 varbuf_add_char(vb, ' ');
422 varbuf_add_pkgbin_name(vb, ta->pend, &ta->pend->installed, pnaw_nonambig);
423 }
424 if (flags & fw_printheader)
425 varbuf_add_char(vb, '\n');
426}
427
428void
429varbuf_add_arbfield(struct varbuf *vb, const struct arbitraryfield *arbfield,
430 enum fwriteflags flags)
431{
432 if (flags & fw_printheader) {
433 varbuf_add_str(vb, arbfield->name);
434 varbuf_add_str(vb, ": ");
435 }
436 varbuf_add_str(vb, arbfield->value);
437 if (flags & fw_printheader)
438 varbuf_add_char(vb, '\n');
439}
440
441void
442varbufrecord(struct varbuf *vb,
443 const struct pkginfo *pkg, const struct pkgbin *pkgbin)
444{
445 const struct fieldinfo *fip;
446 const struct arbitraryfield *afp;
447
448 for (fip= fieldinfos; fip->name; fip++) {
449 fip->wcall(vb, pkg, pkgbin, fw_printheader, fip);
450 }
451 for (afp = pkgbin->arbs; afp; afp = afp->next) {
452 varbuf_add_arbfield(vb, afp, fw_printheader);
453 }
454}
455
456void
457writerecord(FILE *file, const char *filename,
458 const struct pkginfo *pkg, const struct pkgbin *pkgbin)
459{
460 struct varbuf vb = VARBUF_INIT;
461
462 varbufrecord(&vb, pkg, pkgbin);
463 varbuf_end_str(&vb);
464 if (fputs(vb.buf,file) < 0) {
465 struct varbuf pkgname = VARBUF_INIT;
466 int errno_saved = errno;
467
468 varbuf_add_pkgbin_name(&pkgname, pkg, pkgbin, pnaw_nonambig);
469
470 errno = errno_saved;
471 ohshite(_("failed to write details of '%.50s' to '%.250s'"),
472 pkgname.buf, filename);
473 }
474
475 varbuf_destroy(&vb);
476}
477
478void
479writedb(const char *filename, enum writedb_flags flags)
480{
481 static char writebuf[8192];
482
483 struct pkgiterator *iter;
484 struct pkginfo *pkg;
485 struct pkgbin *pkgbin;
486 const char *which;
487 struct atomic_file *file;
488 struct varbuf vb = VARBUF_INIT;
489
490 which = (flags & wdb_dump_available) ? "available" : "status";
491
492 file = atomic_file_new(filename, ATOMIC_FILE_BACKUP);
493 atomic_file_open(file);
494 if (setvbuf(file->fp, writebuf, _IOFBF, sizeof(writebuf)))
495 ohshite(_("unable to set buffering on %s database file"), which);
496
497 iter = pkg_db_iter_new();
498 while ((pkg = pkg_db_iter_next_pkg(iter)) != NULL) {
499 pkgbin = (flags & wdb_dump_available) ? &pkg->available : &pkg->installed;
500 /* Don't dump records which have no useful content. */
501 if (!pkg_is_informative(pkg, pkgbin))
502 continue;
503 varbufrecord(&vb, pkg, pkgbin);
504 varbuf_add_char(&vb, '\n');
505 varbuf_end_str(&vb);
506 if (fputs(vb.buf, file->fp) < 0)
507 ohshite(_("failed to write %s database record about '%.50s' to '%.250s'"),
508 which, pkgbin_name(pkg, pkgbin, pnaw_nonambig), filename);
509 varbuf_reset(&vb);
510 }
511 pkg_db_iter_free(iter);
512 varbuf_destroy(&vb);
513 if (flags & wdb_must_sync)
514 atomic_file_sync(file);
515
516 atomic_file_close(file);
517 atomic_file_commit(file);
518 atomic_file_free(file);
519
520 if (flags & wdb_must_sync)
521 dir_sync_path_parent(filename);
522}