dpkg (1.18.25) stretch; urgency=medium
[dpkg] / src / filesdb.c
CommitLineData
1479465f
GJ
1/*
2 * dpkg - main program for package management
3 * filesdb.c - management of database of files installed on system
4 *
5 * Copyright © 1995 Ian Jackson <ijackson@chiark.greenend.org.uk>
6 * Copyright © 2000,2001 Wichert Akkerman <wakkerma@debian.org>
7 * Copyright © 2008-2014 Guillem Jover <guillem@debian.org>
8 *
9 * This is free software; you can redistribute it and/or modify
10 * it under the terms of the GNU General Public License as published by
11 * the Free Software Foundation; either version 2 of the License, or
12 * (at your option) any later version.
13 *
14 * This is distributed in the hope that it will be useful,
15 * but WITHOUT ANY WARRANTY; without even the implied warranty of
16 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
17 * GNU General Public License for more details.
18 *
19 * You should have received a copy of the GNU General Public License
20 * along with this program. If not, see <https://www.gnu.org/licenses/>.
21 */
22
23#include <config.h>
24#include <compat.h>
25
26#ifdef HAVE_LINUX_FIEMAP_H
27#include <linux/fiemap.h>
28#include <linux/fs.h>
29#include <sys/ioctl.h>
30#include <sys/vfs.h>
31#endif
32#include <sys/types.h>
33#include <sys/stat.h>
34
35#include <assert.h>
36#include <errno.h>
37#include <string.h>
38#include <pwd.h>
39#include <grp.h>
40#include <fcntl.h>
41#include <unistd.h>
42#include <stdlib.h>
43
44#include <dpkg/i18n.h>
45#include <dpkg/dpkg.h>
46#include <dpkg/dpkg-db.h>
47#include <dpkg/string.h>
48#include <dpkg/path.h>
49#include <dpkg/dir.h>
50#include <dpkg/fdio.h>
51#include <dpkg/pkg-array.h>
52#include <dpkg/progress.h>
53
54#include "filesdb.h"
55#include "infodb.h"
56#include "main.h"
57
58/*** filepackages support for tracking packages owning a file. ***/
59
60struct filepackages_iterator {
61 struct pkg_list *pkg_node;
62};
63
64struct filepackages_iterator *
65filepackages_iter_new(struct filenamenode *fnn)
66{
67 struct filepackages_iterator *iter;
68
69 iter = m_malloc(sizeof(*iter));
70 iter->pkg_node = fnn->packages;
71
72 return iter;
73}
74
75struct pkginfo *
76filepackages_iter_next(struct filepackages_iterator *iter)
77{
78 struct pkg_list *pkg_node;
79
80 if (iter->pkg_node == NULL)
81 return NULL;
82
83 pkg_node = iter->pkg_node;
84 iter->pkg_node = pkg_node->next;
85
86 return pkg_node->pkg;
87}
88
89void
90filepackages_iter_free(struct filepackages_iterator *iter)
91{
92 free(iter);
93}
94
95/*** Generic data structures and routines. ***/
96
97static bool allpackagesdone = false;
98static int nfiles= 0;
99
100void
101ensure_package_clientdata(struct pkginfo *pkg)
102{
103 if (pkg->clientdata)
104 return;
105 pkg->clientdata = nfmalloc(sizeof(struct perpackagestate));
106 pkg->clientdata->istobe = PKG_ISTOBE_NORMAL;
107 pkg->clientdata->color = PKG_CYCLE_WHITE;
108 pkg->clientdata->enqueued = false;
109 pkg->clientdata->fileslistvalid = false;
110 pkg->clientdata->files = NULL;
111 pkg->clientdata->replacingfilesandsaid = 0;
112 pkg->clientdata->cmdline_seen = 0;
113 pkg->clientdata->listfile_phys_offs = 0;
114 pkg->clientdata->trigprocdeferred = NULL;
115}
116
117void note_must_reread_files_inpackage(struct pkginfo *pkg) {
118 allpackagesdone = false;
119 ensure_package_clientdata(pkg);
120 pkg->clientdata->fileslistvalid = false;
121}
122
123enum pkg_filesdb_load_status {
124 PKG_FILESDB_LOAD_NONE = 0,
125 PKG_FILESDB_LOAD_INPROGRESS = 1,
126 PKG_FILESDB_LOAD_DONE = 2,
127};
128
129static enum pkg_filesdb_load_status saidread = PKG_FILESDB_LOAD_NONE;
130
131/**
132 * Erase the files saved in pkg.
133 */
134static void
135pkg_files_blank(struct pkginfo *pkg)
136{
137 struct fileinlist *current;
138
139 /* Anything to empty? */
140 if (!pkg->clientdata)
141 return;
142
143 for (current= pkg->clientdata->files;
144 current;
145 current= current->next) {
146 struct pkg_list *pkg_node, *pkg_prev = NULL;
147
148 /* For each file that used to be in the package,
149 * go through looking for this package's entry in the list
150 * of packages containing this file, and blank it out. */
151 for (pkg_node = current->namenode->packages;
152 pkg_node;
153 pkg_node = pkg_node->next) {
154 if (pkg_node->pkg == pkg) {
155 if (pkg_prev)
156 pkg_prev->next = pkg_node->next;
157 else
158 current->namenode->packages = pkg_node->next;
159
160 /* The actual filelist links were allocated using nfmalloc, so
161 * we shouldn't free them. */
162 break;
163 }
164 pkg_prev = pkg_node;
165 }
166 }
167 pkg->clientdata->files = NULL;
168}
169
170static struct fileinlist **
171pkg_files_add_file(struct pkginfo *pkg, struct filenamenode *namenode,
172 struct fileinlist **file_tail)
173{
174 struct fileinlist *newent;
175 struct pkg_list *pkg_node;
176
177 ensure_package_clientdata(pkg);
178
179 if (file_tail == NULL)
180 file_tail = &pkg->clientdata->files;
181
182 /* Make sure we're at the end. */
183 while ((*file_tail) != NULL) {
184 file_tail = &((*file_tail)->next);
185 }
186
187 /* Create a new node. */
188 newent = nfmalloc(sizeof(struct fileinlist));
189 newent->namenode = namenode;
190 newent->next = NULL;
191 *file_tail = newent;
192 file_tail = &newent->next;
193
194 /* Add pkg to newent's package list. */
195 pkg_node = nfmalloc(sizeof(*pkg_node));
196 pkg_node->pkg = pkg;
197 pkg_node->next = newent->namenode->packages;
198 newent->namenode->packages = pkg_node;
199
200 /* Return the position for the next guy. */
201 return file_tail;
202}
203
204/**
205 * Load the list of files in this package into memory, or update the
206 * list if it is there but stale.
207 */
208void
209ensure_packagefiles_available(struct pkginfo *pkg)
210{
211 static int fd;
212 const char *filelistfile;
213 struct fileinlist **lendp;
214 struct stat stat_buf;
215 char *loaded_list, *loaded_list_end, *thisline, *nextline, *ptr;
216
217 if (pkg->clientdata && pkg->clientdata->fileslistvalid)
218 return;
219 ensure_package_clientdata(pkg);
220
221 /* Throw away any stale data, if there was any. */
222 pkg_files_blank(pkg);
223
224 /* Packages which aren't installed don't have a files list. */
225 if (pkg->status == PKG_STAT_NOTINSTALLED) {
226 pkg->clientdata->fileslistvalid = true;
227 return;
228 }
229
230 filelistfile = pkg_infodb_get_file(pkg, &pkg->installed, LISTFILE);
231
232 onerr_abort++;
233
234 fd= open(filelistfile,O_RDONLY);
235
236 if (fd==-1) {
237 if (errno != ENOENT)
238 ohshite(_("unable to open files list file for package '%.250s'"),
239 pkg_name(pkg, pnaw_nonambig));
240 onerr_abort--;
241 if (pkg->status != PKG_STAT_CONFIGFILES &&
242 dpkg_version_is_informative(&pkg->configversion)) {
243 warning(_("files list file for package '%.250s' missing; assuming "
244 "package has no files currently installed"),
245 pkg_name(pkg, pnaw_nonambig));
246 }
247 pkg->clientdata->files = NULL;
248 pkg->clientdata->fileslistvalid = true;
249 return;
250 }
251
252 push_cleanup(cu_closefd, ehflag_bombout, NULL, 0, 1, &fd);
253
254 if (fstat(fd, &stat_buf))
255 ohshite(_("unable to stat files list file for package '%.250s'"),
256 pkg_name(pkg, pnaw_nonambig));
257
258 if (!S_ISREG(stat_buf.st_mode))
259 ohshit(_("files list for package '%.250s' is not a regular file"),
260 pkg_name(pkg, pnaw_nonambig));
261
262 if (stat_buf.st_size) {
263 loaded_list = nfmalloc(stat_buf.st_size);
264 loaded_list_end = loaded_list + stat_buf.st_size;
265
266 if (fd_read(fd, loaded_list, stat_buf.st_size) < 0)
267 ohshite(_("reading files list for package '%.250s'"),
268 pkg_name(pkg, pnaw_nonambig));
269
270 lendp= &pkg->clientdata->files;
271 thisline = loaded_list;
272 while (thisline < loaded_list_end) {
273 struct filenamenode *namenode;
274
275 ptr = memchr(thisline, '\n', loaded_list_end - thisline);
276 if (ptr == NULL)
277 ohshit(_("files list file for package '%.250s' is missing final newline"),
278 pkg_name(pkg, pnaw_nonambig));
279 /* Where to start next time around. */
280 nextline = ptr + 1;
281 /* Strip trailing ‘/’. */
282 if (ptr > thisline && ptr[-1] == '/') ptr--;
283 /* Add the file to the list. */
284 if (ptr == thisline)
285 ohshit(_("files list file for package '%.250s' contains empty filename"),
286 pkg_name(pkg, pnaw_nonambig));
287 *ptr = '\0';
288
289 namenode = findnamenode(thisline, fnn_nocopy);
290 lendp = pkg_files_add_file(pkg, namenode, lendp);
291 thisline = nextline;
292 }
293 }
294 pop_cleanup(ehflag_normaltidy); /* fd = open() */
295 if (close(fd))
296 ohshite(_("error closing files list file for package '%.250s'"),
297 pkg_name(pkg, pnaw_nonambig));
298
299 onerr_abort--;
300
301 pkg->clientdata->fileslistvalid = true;
302}
303
304#if defined(HAVE_LINUX_FIEMAP_H)
305static int
306pkg_sorter_by_listfile_phys_offs(const void *a, const void *b)
307{
308 const struct pkginfo *pa = *(const struct pkginfo **)a;
309 const struct pkginfo *pb = *(const struct pkginfo **)b;
310
311 /* We can't simply subtract, because the difference may be greater than
312 * INT_MAX. */
313 if (pa->clientdata->listfile_phys_offs < pb->clientdata->listfile_phys_offs)
314 return -1;
315 else if (pa->clientdata->listfile_phys_offs > pb->clientdata->listfile_phys_offs)
316 return 1;
317 else
318 return 0;
319}
320
321static void
322pkg_files_optimize_load(struct pkg_array *array)
323{
324 struct statfs fs;
325 int i;
326
327 /* Get the filesystem block size. */
328 if (statfs(pkg_infodb_get_dir(), &fs) < 0)
329 return;
330
331 /* Sort packages by the physical location of their list files, so that
332 * scanning them later will minimize disk drive head movements. */
333 for (i = 0; i < array->n_pkgs; i++) {
334 struct pkginfo *pkg = array->pkgs[i];
335 struct {
336 struct fiemap fiemap;
337 struct fiemap_extent extent;
338 } fm;
339 const char *listfile;
340 int fd;
341
342 ensure_package_clientdata(pkg);
343
344 if (pkg->status == PKG_STAT_NOTINSTALLED ||
345 pkg->clientdata->listfile_phys_offs != 0)
346 continue;
347
348 pkg->clientdata->listfile_phys_offs = -1;
349
350 listfile = pkg_infodb_get_file(pkg, &pkg->installed, LISTFILE);
351
352 fd = open(listfile, O_RDONLY);
353 if (fd < 0)
354 continue;
355
356 memset(&fm, 0, sizeof(fm));
357 fm.fiemap.fm_start = 0;
358 fm.fiemap.fm_length = fs.f_bsize;
359 fm.fiemap.fm_flags = 0;
360 fm.fiemap.fm_extent_count = 1;
361
362 if (ioctl(fd, FS_IOC_FIEMAP, (unsigned long)&fm) == 0)
363 pkg->clientdata->listfile_phys_offs = fm.fiemap.fm_extents[0].fe_physical;
364
365 close(fd);
366 }
367
368 pkg_array_sort(array, pkg_sorter_by_listfile_phys_offs);
369}
370#elif defined(HAVE_POSIX_FADVISE)
371static void
372pkg_files_optimize_load(struct pkg_array *array)
373{
374 int i;
375
376 /* Ask the kernel to start preloading the list files, so as to get a
377 * boost when later we actually load them. */
378 for (i = 0; i < array->n_pkgs; i++) {
379 struct pkginfo *pkg = array->pkgs[i];
380 const char *listfile;
381 int fd;
382
383 listfile = pkg_infodb_get_file(pkg, &pkg->installed, LISTFILE);
384
385 fd = open(listfile, O_RDONLY | O_NONBLOCK);
386 if (fd != -1) {
387 posix_fadvise(fd, 0, 0, POSIX_FADV_WILLNEED);
388 close(fd);
389 }
390 }
391}
392#else
393static void
394pkg_files_optimize_load(struct pkg_array *array)
395{
396}
397#endif
398
399void ensure_allinstfiles_available(void) {
400 struct pkg_array array;
401 struct pkginfo *pkg;
402 struct progress progress;
403 int i;
404
405 if (allpackagesdone) return;
406 if (saidread < PKG_FILESDB_LOAD_DONE) {
407 int max = pkg_db_count_pkg();
408
409 saidread = PKG_FILESDB_LOAD_INPROGRESS;
410 progress_init(&progress, _("(Reading database ... "), max);
411 }
412
413 pkg_array_init_from_db(&array);
414
415 pkg_files_optimize_load(&array);
416
417 for (i = 0; i < array.n_pkgs; i++) {
418 pkg = array.pkgs[i];
419 ensure_packagefiles_available(pkg);
420
421 if (saidread == PKG_FILESDB_LOAD_INPROGRESS)
422 progress_step(&progress);
423 }
424
425 pkg_array_destroy(&array);
426
427 allpackagesdone = true;
428
429 if (saidread == PKG_FILESDB_LOAD_INPROGRESS) {
430 progress_done(&progress);
431 printf(P_("%d file or directory currently installed.)\n",
432 "%d files and directories currently installed.)\n", nfiles),
433 nfiles);
434 saidread = PKG_FILESDB_LOAD_DONE;
435 }
436}
437
438void ensure_allinstfiles_available_quiet(void) {
439 saidread = PKG_FILESDB_LOAD_DONE;
440 ensure_allinstfiles_available();
441}
442
443/*
444 * If mask is nonzero, will not write any file whose filenamenode
445 * has any flag bits set in mask.
446 */
447void
448write_filelist_except(struct pkginfo *pkg, struct pkgbin *pkgbin,
449 struct fileinlist *list, enum filenamenode_flags mask)
450{
451 struct atomic_file *file;
452 struct fileinlist *node;
453 const char *listfile;
454
455 listfile = pkg_infodb_get_file(pkg, pkgbin, LISTFILE);
456
457 file = atomic_file_new(listfile, 0);
458 atomic_file_open(file);
459
460 for (node = list; node; node = node->next) {
461 if (!(mask && (node->namenode->flags & mask))) {
462 fputs(node->namenode->name, file->fp);
463 putc('\n', file->fp);
464 }
465 }
466
467 atomic_file_sync(file);
468 atomic_file_close(file);
469 atomic_file_commit(file);
470 atomic_file_free(file);
471
472 dir_sync_path(pkg_infodb_get_dir());
473
474 note_must_reread_files_inpackage(pkg);
475}
476
477/*
478 * Initializes an iterator that appears to go through the file
479 * list ‘files’ in reverse order, returning the namenode from
480 * each. What actually happens is that we walk the list here,
481 * building up a reverse list, and then peel it apart one
482 * entry at a time.
483 */
484void
485reversefilelist_init(struct reversefilelistiter *iter, struct fileinlist *files)
486{
487 struct fileinlist *newent;
488
489 iter->todo = NULL;
490 while (files) {
491 newent= m_malloc(sizeof(struct fileinlist));
492 newent->namenode= files->namenode;
493 newent->next = iter->todo;
494 iter->todo = newent;
495 files= files->next;
496 }
497}
498
499struct filenamenode *
500reversefilelist_next(struct reversefilelistiter *iter)
501{
502 struct filenamenode *ret;
503 struct fileinlist *todo;
504
505 todo = iter->todo;
506 if (!todo)
507 return NULL;
508 ret= todo->namenode;
509 iter->todo = todo->next;
510 free(todo);
511 return ret;
512}
513
514/*
515 * Clients must call this function to clean up the reversefilelistiter
516 * if they wish to break out of the iteration before it is all done.
517 * Calling this function is not necessary if reversefilelist_next has
518 * been called until it returned 0.
519 */
520void
521reversefilelist_abort(struct reversefilelistiter *iter)
522{
523 while (reversefilelist_next(iter));
524}
525
526struct fileiterator {
527 struct filenamenode *namenode;
528 int nbinn;
529};
530
531/* This must always be a prime for optimal performance.
532 * This is the closest one to 2^18 (262144). */
533#define BINS 262139
534
535static struct filenamenode *bins[BINS];
536
537struct fileiterator *
538files_db_iter_new(void)
539{
540 struct fileiterator *iter;
541
542 iter = m_malloc(sizeof(struct fileiterator));
543 iter->namenode = NULL;
544 iter->nbinn = 0;
545
546 return iter;
547}
548
549struct filenamenode *
550files_db_iter_next(struct fileiterator *iter)
551{
552 struct filenamenode *r= NULL;
553
554 while (!iter->namenode) {
555 if (iter->nbinn >= BINS)
556 return NULL;
557 iter->namenode = bins[iter->nbinn++];
558 }
559 r = iter->namenode;
560 iter->namenode = r->next;
561
562 return r;
563}
564
565void
566files_db_iter_free(struct fileiterator *iter)
567{
568 free(iter);
569}
570
571void filesdbinit(void) {
572 struct filenamenode *fnn;
573 int i;
574
575 for (i=0; i<BINS; i++)
576 for (fnn= bins[i]; fnn; fnn= fnn->next) {
577 fnn->flags= 0;
578 fnn->oldhash = NULL;
579 fnn->newhash = EMPTYHASHFLAG;
580 fnn->filestat = NULL;
581 }
582}
583
584void
585files_db_reset(void)
586{
587 int i;
588
589 for (i = 0; i < BINS; i++)
590 bins[i] = NULL;
591}
592
593struct filenamenode *findnamenode(const char *name, enum fnnflags flags) {
594 struct filenamenode **pointerp, *newnode;
595 const char *orig_name = name;
596
597 /* We skip initial slashes and ‘./’ pairs, and add our own single
598 * leading slash. */
599 name = path_skip_slash_dotslash(name);
600
601 pointerp = bins + (str_fnv_hash(name) % (BINS));
602 while (*pointerp) {
603 /* XXX: Why is the assert needed? It's checking already added entries. */
604 assert((*pointerp)->name[0] == '/');
605 if (strcmp((*pointerp)->name + 1, name) == 0)
606 break;
607 pointerp= &(*pointerp)->next;
608 }
609 if (*pointerp) return *pointerp;
610
611 if (flags & fnn_nonew)
612 return NULL;
613
614 newnode= nfmalloc(sizeof(struct filenamenode));
615 newnode->packages = NULL;
616 if((flags & fnn_nocopy) && name > orig_name && name[-1] == '/')
617 newnode->name = name - 1;
618 else {
619 char *newname= nfmalloc(strlen(name)+2);
620 newname[0]= '/'; strcpy(newname+1,name);
621 newnode->name= newname;
622 }
623 newnode->flags= 0;
624 newnode->next = NULL;
625 newnode->divert = NULL;
626 newnode->statoverride = NULL;
627 newnode->oldhash = NULL;
628 newnode->newhash = EMPTYHASHFLAG;
629 newnode->filestat = NULL;
630 newnode->trig_interested = NULL;
631 *pointerp= newnode;
632 nfiles++;
633
634 return newnode;
635}