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 <errno.h>
34 #include <string.h>
35 #include <unistd.h>
36 #include <stdio.h>
37 #include <stdlib.h>
38 #include <stdbool.h>
39
40 #include <dpkg/i18n.h>
41 #include <dpkg/dpkg.h>
42 #include <dpkg/dpkg-db.h>
43 #include <dpkg/pkg-array.h>
44 #include <dpkg/pkg-show.h>
45 #include <dpkg/string.h>
46 #include <dpkg/dir.h>
47 #include <dpkg/parsedump.h>
48
49 static inline void
varbuf_add_fieldname(struct varbuf * vb,const struct fieldinfo * fip)50 varbuf_add_fieldname(struct varbuf *vb, const struct fieldinfo *fip)
51 {
52 varbuf_add_str(vb, fip->name);
53 varbuf_add_str(vb, ": ");
54 }
55
56 void
w_name(struct varbuf * vb,const struct pkginfo * pkg,const struct pkgbin * pkgbin,enum fwriteflags flags,const struct fieldinfo * fip)57 w_name(struct varbuf *vb,
58 const struct pkginfo *pkg, const struct pkgbin *pkgbin,
59 enum fwriteflags flags, const struct fieldinfo *fip)
60 {
61 if (pkg->set->name == NULL)
62 internerr("pkgset has no name");
63
64 if (flags&fw_printheader)
65 varbuf_add_str(vb, "Package: ");
66 varbuf_add_str(vb, pkg->set->name);
67 if (flags&fw_printheader)
68 varbuf_add_char(vb, '\n');
69 }
70
71 void
w_version(struct varbuf * vb,const struct pkginfo * pkg,const struct pkgbin * pkgbin,enum fwriteflags flags,const struct fieldinfo * fip)72 w_version(struct varbuf *vb,
73 const struct pkginfo *pkg, const struct pkgbin *pkgbin,
74 enum fwriteflags flags, const struct fieldinfo *fip)
75 {
76 if (!dpkg_version_is_informative(&pkgbin->version))
77 return;
78 if (flags&fw_printheader)
79 varbuf_add_str(vb, "Version: ");
80 varbufversion(vb, &pkgbin->version, vdew_nonambig);
81 if (flags&fw_printheader)
82 varbuf_add_char(vb, '\n');
83 }
84
85 void
w_configversion(struct varbuf * vb,const struct pkginfo * pkg,const struct pkgbin * pkgbin,enum fwriteflags flags,const struct fieldinfo * fip)86 w_configversion(struct varbuf *vb,
87 const struct pkginfo *pkg, const struct pkgbin *pkgbin,
88 enum fwriteflags flags, const struct fieldinfo *fip)
89 {
90 if (pkgbin != &pkg->installed)
91 return;
92 if (!dpkg_version_is_informative(&pkg->configversion))
93 return;
94 if (pkg->status == PKG_STAT_INSTALLED ||
95 pkg->status == PKG_STAT_NOTINSTALLED ||
96 pkg->status == PKG_STAT_TRIGGERSPENDING)
97 return;
98 if (flags&fw_printheader)
99 varbuf_add_str(vb, "Config-Version: ");
100 varbufversion(vb, &pkg->configversion, vdew_nonambig);
101 if (flags&fw_printheader)
102 varbuf_add_char(vb, '\n');
103 }
104
105 void
w_null(struct varbuf * vb,const struct pkginfo * pkg,const struct pkgbin * pkgbin,enum fwriteflags flags,const struct fieldinfo * fip)106 w_null(struct varbuf *vb,
107 const struct pkginfo *pkg, const struct pkgbin *pkgbin,
108 enum fwriteflags flags, const struct fieldinfo *fip)
109 {
110 }
111
112 void
w_section(struct varbuf * vb,const struct pkginfo * pkg,const struct pkgbin * pkgbin,enum fwriteflags flags,const struct fieldinfo * fip)113 w_section(struct varbuf *vb,
114 const struct pkginfo *pkg, const struct pkgbin *pkgbin,
115 enum fwriteflags flags, const struct fieldinfo *fip)
116 {
117 const char *value = pkg->section;
118
119 if (str_is_unset(value))
120 return;
121 if (flags&fw_printheader)
122 varbuf_add_str(vb, "Section: ");
123 varbuf_add_str(vb, value);
124 if (flags&fw_printheader)
125 varbuf_add_char(vb, '\n');
126 }
127
128 void
w_charfield(struct varbuf * vb,const struct pkginfo * pkg,const struct pkgbin * pkgbin,enum fwriteflags flags,const struct fieldinfo * fip)129 w_charfield(struct varbuf *vb,
130 const struct pkginfo *pkg, const struct pkgbin *pkgbin,
131 enum fwriteflags flags, const struct fieldinfo *fip)
132 {
133 const char *value = STRUCTFIELD(pkgbin, fip->integer, const char *);
134
135 if (str_is_unset(value))
136 return;
137 if (flags & fw_printheader)
138 varbuf_add_fieldname(vb, fip);
139 varbuf_add_str(vb, value);
140 if (flags&fw_printheader)
141 varbuf_add_char(vb, '\n');
142 }
143
144 void
w_archives(struct varbuf * vb,const struct pkginfo * pkg,const struct pkgbin * pkgbin,enum fwriteflags flags,const struct fieldinfo * fip)145 w_archives(struct varbuf *vb,
146 const struct pkginfo *pkg, const struct pkgbin *pkgbin,
147 enum fwriteflags flags, const struct fieldinfo *fip)
148 {
149 struct archivedetails *archive;
150
151 if (pkgbin != &pkg->available)
152 return;
153 archive = pkg->archives;
154 if (!archive || !STRUCTFIELD(archive, fip->integer, const char *))
155 return;
156
157 if (flags&fw_printheader) {
158 varbuf_add_str(vb, fip->name);
159 varbuf_add_char(vb, ':');
160 }
161
162 while (archive) {
163 varbuf_add_char(vb, ' ');
164 varbuf_add_str(vb, STRUCTFIELD(archive, fip->integer, const char *));
165 archive = archive->next;
166 }
167
168 if (flags&fw_printheader)
169 varbuf_add_char(vb, '\n');
170 }
171
172 void
w_booleandefno(struct varbuf * vb,const struct pkginfo * pkg,const struct pkgbin * pkgbin,enum fwriteflags flags,const struct fieldinfo * fip)173 w_booleandefno(struct varbuf *vb,
174 const struct pkginfo *pkg, const struct pkgbin *pkgbin,
175 enum fwriteflags flags, const struct fieldinfo *fip)
176 {
177 bool value = STRUCTFIELD(pkgbin, fip->integer, bool);
178
179 if ((flags & fw_printheader) && !value)
180 return;
181
182 if (flags & fw_printheader)
183 varbuf_add_fieldname(vb, fip);
184
185 varbuf_add_str(vb, value ? "yes" : "no");
186
187 if (flags & fw_printheader)
188 varbuf_add_char(vb, '\n');
189 }
190
191 void
w_multiarch(struct varbuf * vb,const struct pkginfo * pkg,const struct pkgbin * pkgbin,enum fwriteflags flags,const struct fieldinfo * fip)192 w_multiarch(struct varbuf *vb,
193 const struct pkginfo *pkg, const struct pkgbin *pkgbin,
194 enum fwriteflags flags, const struct fieldinfo *fip)
195 {
196 int value = STRUCTFIELD(pkgbin, fip->integer, int);
197
198 if ((flags & fw_printheader) && !value)
199 return;
200
201 if (flags & fw_printheader)
202 varbuf_add_fieldname(vb, fip);
203
204 varbuf_add_str(vb, multiarchinfos[value].name);
205
206 if (flags & fw_printheader)
207 varbuf_add_char(vb, '\n');
208 }
209
210 void
w_architecture(struct varbuf * vb,const struct pkginfo * pkg,const struct pkgbin * pkgbin,enum fwriteflags flags,const struct fieldinfo * fip)211 w_architecture(struct varbuf *vb,
212 const struct pkginfo *pkg, const struct pkgbin *pkgbin,
213 enum fwriteflags flags, const struct fieldinfo *fip)
214 {
215 if (!pkgbin->arch)
216 return;
217 if (pkgbin->arch->type == DPKG_ARCH_NONE)
218 return;
219 if (pkgbin->arch->type == DPKG_ARCH_EMPTY)
220 return;
221
222 if (flags & fw_printheader)
223 varbuf_add_fieldname(vb, fip);
224 varbuf_add_str(vb, pkgbin->arch->name);
225 if (flags & fw_printheader)
226 varbuf_add_char(vb, '\n');
227 }
228
229 void
w_priority(struct varbuf * vb,const struct pkginfo * pkg,const struct pkgbin * pkgbin,enum fwriteflags flags,const struct fieldinfo * fip)230 w_priority(struct varbuf *vb,
231 const struct pkginfo *pkg, const struct pkgbin *pkgbin,
232 enum fwriteflags flags, const struct fieldinfo *fip)
233 {
234 if (pkg->priority == PKG_PRIO_UNKNOWN)
235 return;
236
237 if (pkg->priority > PKG_PRIO_UNKNOWN)
238 internerr("package %s has out-of-range priority %d",
239 pkgbin_name_const(pkg, pkgbin, pnaw_always), pkg->priority);
240
241 if (flags&fw_printheader)
242 varbuf_add_str(vb, "Priority: ");
243 varbuf_add_str(vb, pkg_priority_name(pkg));
244 if (flags&fw_printheader)
245 varbuf_add_char(vb, '\n');
246 }
247
248 void
w_status(struct varbuf * vb,const struct pkginfo * pkg,const struct pkgbin * pkgbin,enum fwriteflags flags,const struct fieldinfo * fip)249 w_status(struct varbuf *vb,
250 const struct pkginfo *pkg, const struct pkgbin *pkgbin,
251 enum fwriteflags flags, const struct fieldinfo *fip)
252 {
253 if (pkgbin != &pkg->installed)
254 return;
255
256 if (pkg->want > PKG_WANT_PURGE)
257 internerr("package %s has unknown want state %d",
258 pkgbin_name_const(pkg, pkgbin, pnaw_always), pkg->want);
259 if (pkg->eflag > PKG_EFLAG_REINSTREQ)
260 internerr("package %s has unknown error state %d",
261 pkgbin_name_const(pkg, pkgbin, pnaw_always), pkg->eflag);
262
263 switch (pkg->status) {
264 case PKG_STAT_NOTINSTALLED:
265 case PKG_STAT_CONFIGFILES:
266 if (pkg->trigpend_head || pkg->trigaw.head)
267 internerr("package %s in state %s, has awaited or pending triggers",
268 pkgbin_name_const(pkg, pkgbin, pnaw_always), pkg_status_name(pkg));
269 break;
270 case PKG_STAT_HALFINSTALLED:
271 case PKG_STAT_UNPACKED:
272 case PKG_STAT_HALFCONFIGURED:
273 if (pkg->trigpend_head)
274 internerr("package %s in state %s, has pending triggers",
275 pkgbin_name_const(pkg, pkgbin, pnaw_always), pkg_status_name(pkg));
276 break;
277 case PKG_STAT_TRIGGERSAWAITED:
278 if (pkg->trigaw.head == NULL)
279 internerr("package %s in state %s, has no awaited triggers",
280 pkgbin_name_const(pkg, pkgbin, pnaw_always), pkg_status_name(pkg));
281 break;
282 case PKG_STAT_TRIGGERSPENDING:
283 if (pkg->trigpend_head == NULL || pkg->trigaw.head)
284 internerr("package %s in stata %s, has awaited or no pending triggers",
285 pkgbin_name_const(pkg, pkgbin, pnaw_always), pkg_status_name(pkg));
286 break;
287 case PKG_STAT_INSTALLED:
288 if (pkg->trigpend_head || pkg->trigaw.head)
289 internerr("package %s in state %s, has awaited or pending triggers",
290 pkgbin_name_const(pkg, pkgbin, pnaw_always), pkg_status_name(pkg));
291 break;
292 default:
293 internerr("unknown package status '%d'", pkg->status);
294 }
295
296 if (flags&fw_printheader)
297 varbuf_add_str(vb, "Status: ");
298 varbuf_add_str(vb, pkg_want_name(pkg));
299 varbuf_add_char(vb, ' ');
300 varbuf_add_str(vb, pkg_eflag_name(pkg));
301 varbuf_add_char(vb, ' ');
302 varbuf_add_str(vb, pkg_status_name(pkg));
303 if (flags&fw_printheader)
304 varbuf_add_char(vb, '\n');
305 }
306
varbufdependency(struct varbuf * vb,struct dependency * dep)307 void varbufdependency(struct varbuf *vb, struct dependency *dep) {
308 struct deppossi *dop;
309 const char *possdel;
310
311 possdel= "";
312 for (dop= dep->list; dop; dop= dop->next) {
313 if (dop->up != dep)
314 internerr("dependency and deppossi not linked properly");
315
316 varbuf_add_str(vb, possdel);
317 possdel = " | ";
318 varbuf_add_str(vb, dop->ed->name);
319 if (!dop->arch_is_implicit)
320 varbuf_add_archqual(vb, dop->arch);
321 if (dop->verrel != DPKG_RELATION_NONE) {
322 varbuf_add_str(vb, " (");
323 switch (dop->verrel) {
324 case DPKG_RELATION_EQ:
325 varbuf_add_char(vb, '=');
326 break;
327 case DPKG_RELATION_GE:
328 varbuf_add_str(vb, ">=");
329 break;
330 case DPKG_RELATION_LE:
331 varbuf_add_str(vb, "<=");
332 break;
333 case DPKG_RELATION_GT:
334 varbuf_add_str(vb, ">>");
335 break;
336 case DPKG_RELATION_LT:
337 varbuf_add_str(vb, "<<");
338 break;
339 default:
340 internerr("unknown dpkg_relation %d", dop->verrel);
341 }
342 varbuf_add_char(vb, ' ');
343 varbufversion(vb,&dop->version,vdew_nonambig);
344 varbuf_add_char(vb, ')');
345 }
346 }
347 }
348
349 void
w_dependency(struct varbuf * vb,const struct pkginfo * pkg,const struct pkgbin * pkgbin,enum fwriteflags flags,const struct fieldinfo * fip)350 w_dependency(struct varbuf *vb,
351 const struct pkginfo *pkg, const struct pkgbin *pkgbin,
352 enum fwriteflags flags, const struct fieldinfo *fip)
353 {
354 struct dependency *dyp;
355 bool dep_found = false;
356
357 for (dyp = pkgbin->depends; dyp; dyp = dyp->next) {
358 if (dyp->type != fip->integer) continue;
359
360 if (dyp->up != pkg)
361 internerr("dependency and package %s not linked properly",
362 pkgbin_name_const(pkg, pkgbin, pnaw_always));
363
364 if (dep_found) {
365 varbuf_add_str(vb, ", ");
366 } else {
367 if (flags & fw_printheader)
368 varbuf_add_fieldname(vb, fip);
369 dep_found = true;
370 }
371 varbufdependency(vb,dyp);
372 }
373 if ((flags & fw_printheader) && dep_found)
374 varbuf_add_char(vb, '\n');
375 }
376
377 void
w_conffiles(struct varbuf * vb,const struct pkginfo * pkg,const struct pkgbin * pkgbin,enum fwriteflags flags,const struct fieldinfo * fip)378 w_conffiles(struct varbuf *vb,
379 const struct pkginfo *pkg, const struct pkgbin *pkgbin,
380 enum fwriteflags flags, const struct fieldinfo *fip)
381 {
382 struct conffile *i;
383
384 if (!pkgbin->conffiles || pkgbin == &pkg->available)
385 return;
386 if (flags&fw_printheader)
387 varbuf_add_str(vb, "Conffiles:\n");
388 for (i = pkgbin->conffiles; i; i = i->next) {
389 if (i != pkgbin->conffiles)
390 varbuf_add_char(vb, '\n');
391 varbuf_add_char(vb, ' ');
392 varbuf_add_str(vb, i->name);
393 varbuf_add_char(vb, ' ');
394 varbuf_add_str(vb, i->hash);
395 if (i->obsolete)
396 varbuf_add_str(vb, " obsolete");
397 }
398 if (flags&fw_printheader)
399 varbuf_add_char(vb, '\n');
400 }
401
402 void
w_trigpend(struct varbuf * vb,const struct pkginfo * pkg,const struct pkgbin * pkgbin,enum fwriteflags flags,const struct fieldinfo * fip)403 w_trigpend(struct varbuf *vb,
404 const struct pkginfo *pkg, const struct pkgbin *pkgbin,
405 enum fwriteflags flags, const struct fieldinfo *fip)
406 {
407 struct trigpend *tp;
408
409 if (pkgbin == &pkg->available || !pkg->trigpend_head)
410 return;
411
412 if (pkg->status < PKG_STAT_TRIGGERSAWAITED ||
413 pkg->status > PKG_STAT_TRIGGERSPENDING)
414 internerr("package %s in non-trigger state %s, has pending triggers",
415 pkgbin_name_const(pkg, pkgbin, pnaw_always), pkg_status_name(pkg));
416
417 if (flags & fw_printheader)
418 varbuf_add_str(vb, "Triggers-Pending:");
419 for (tp = pkg->trigpend_head; tp; tp = tp->next) {
420 varbuf_add_char(vb, ' ');
421 varbuf_add_str(vb, tp->name);
422 }
423 if (flags & fw_printheader)
424 varbuf_add_char(vb, '\n');
425 }
426
427 void
w_trigaw(struct varbuf * vb,const struct pkginfo * pkg,const struct pkgbin * pkgbin,enum fwriteflags flags,const struct fieldinfo * fip)428 w_trigaw(struct varbuf *vb,
429 const struct pkginfo *pkg, const struct pkgbin *pkgbin,
430 enum fwriteflags flags, const struct fieldinfo *fip)
431 {
432 struct trigaw *ta;
433
434 if (pkgbin == &pkg->available || !pkg->trigaw.head)
435 return;
436
437 if (pkg->status <= PKG_STAT_CONFIGFILES ||
438 pkg->status > PKG_STAT_TRIGGERSAWAITED)
439 internerr("package %s in state %s, has awaited triggers",
440 pkgbin_name_const(pkg, pkgbin, pnaw_always), pkg_status_name(pkg));
441
442 if (flags & fw_printheader)
443 varbuf_add_str(vb, "Triggers-Awaited:");
444 for (ta = pkg->trigaw.head; ta; ta = ta->sameaw.next) {
445 varbuf_add_char(vb, ' ');
446 varbuf_add_pkgbin_name(vb, ta->pend, &ta->pend->installed, pnaw_nonambig);
447 }
448 if (flags & fw_printheader)
449 varbuf_add_char(vb, '\n');
450 }
451
452 void
varbuf_add_arbfield(struct varbuf * vb,const struct arbitraryfield * arbfield,enum fwriteflags flags)453 varbuf_add_arbfield(struct varbuf *vb, const struct arbitraryfield *arbfield,
454 enum fwriteflags flags)
455 {
456 if (flags & fw_printheader) {
457 varbuf_add_str(vb, arbfield->name);
458 varbuf_add_str(vb, ": ");
459 }
460 varbuf_add_str(vb, arbfield->value);
461 if (flags & fw_printheader)
462 varbuf_add_char(vb, '\n');
463 }
464
465 void
varbufrecord(struct varbuf * vb,const struct pkginfo * pkg,const struct pkgbin * pkgbin)466 varbufrecord(struct varbuf *vb,
467 const struct pkginfo *pkg, const struct pkgbin *pkgbin)
468 {
469 const struct fieldinfo *fip;
470 const struct arbitraryfield *afp;
471
472 for (fip= fieldinfos; fip->name; fip++) {
473 fip->wcall(vb, pkg, pkgbin, fw_printheader, fip);
474 }
475 for (afp = pkgbin->arbs; afp; afp = afp->next) {
476 varbuf_add_arbfield(vb, afp, fw_printheader);
477 }
478 }
479
480 void
writerecord(FILE * file,const char * filename,const struct pkginfo * pkg,const struct pkgbin * pkgbin)481 writerecord(FILE *file, const char *filename,
482 const struct pkginfo *pkg, const struct pkgbin *pkgbin)
483 {
484 struct varbuf vb = VARBUF_INIT;
485
486 varbufrecord(&vb, pkg, pkgbin);
487 varbuf_end_str(&vb);
488
489 if (fputs(vb.buf, file) < 0)
490 ohshite(_("failed to write details of '%.50s' to '%.250s'"),
491 pkgbin_name_const(pkg, pkgbin, pnaw_nonambig), filename);
492
493 varbuf_destroy(&vb);
494 }
495
496 void
writedb_records(FILE * fp,const char * filename,enum writedb_flags flags)497 writedb_records(FILE *fp, const char *filename, enum writedb_flags flags)
498 {
499 static char writebuf[8192];
500
501 struct pkg_array array;
502 struct pkginfo *pkg;
503 struct pkgbin *pkgbin;
504 const char *which;
505 struct varbuf vb = VARBUF_INIT;
506 int i;
507
508 which = (flags & wdb_dump_available) ? "available" : "status";
509
510 if (setvbuf(fp, writebuf, _IOFBF, sizeof(writebuf)))
511 ohshite(_("unable to set buffering on %s database file"), which);
512
513 pkg_array_init_from_hash(&array);
514 pkg_array_sort(&array, pkg_sorter_by_nonambig_name_arch);
515
516 for (i = 0; i < array.n_pkgs; i++) {
517 pkg = array.pkgs[i];
518 pkgbin = (flags & wdb_dump_available) ? &pkg->available : &pkg->installed;
519
520 /* Don't dump records which have no useful content. */
521 if (!pkg_is_informative(pkg, pkgbin))
522 continue;
523
524 varbufrecord(&vb, pkg, pkgbin);
525 varbuf_add_char(&vb, '\n');
526 varbuf_end_str(&vb);
527 if (fputs(vb.buf, fp) < 0)
528 ohshite(_("failed to write %s database record about '%.50s' to '%.250s'"),
529 which, pkgbin_name(pkg, pkgbin, pnaw_nonambig), filename);
530 varbuf_reset(&vb);
531 }
532
533 pkg_array_destroy(&array);
534 varbuf_destroy(&vb);
535 }
536
537 void
writedb(const char * filename,enum writedb_flags flags)538 writedb(const char *filename, enum writedb_flags flags)
539 {
540 struct atomic_file *file;
541
542 file = atomic_file_new(filename, ATOMIC_FILE_BACKUP);
543 atomic_file_open(file);
544
545 writedb_records(file->fp, filename, flags);
546
547 if (flags & wdb_must_sync)
548 atomic_file_sync(file);
549
550 atomic_file_close(file);
551 atomic_file_commit(file);
552 atomic_file_free(file);
553
554 if (flags & wdb_must_sync)
555 dir_sync_path_parent(filename);
556 }
557