chiark / gitweb /
lib/dpkg/tarfn.c: Kludge `tar_header_decode' to handle spurious `errno'.
[dpkg] / src / filesdb.c
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
60 struct filepackages_iterator {
61   struct pkg_list *pkg_node;
62 };
63
64 struct filepackages_iterator *
65 filepackages_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
75 struct pkginfo *
76 filepackages_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
89 void
90 filepackages_iter_free(struct filepackages_iterator *iter)
91 {
92   free(iter);
93 }
94
95 /*** Generic data structures and routines. ***/
96
97 static bool allpackagesdone = false;
98 static int nfiles= 0;
99
100 void
101 ensure_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
117 void note_must_reread_files_inpackage(struct pkginfo *pkg) {
118   allpackagesdone = false;
119   ensure_package_clientdata(pkg);
120   pkg->clientdata->fileslistvalid = false;
121 }
122
123 enum pkg_filesdb_load_status {
124   PKG_FILESDB_LOAD_NONE = 0,
125   PKG_FILESDB_LOAD_INPROGRESS = 1,
126   PKG_FILESDB_LOAD_DONE = 2,
127 };
128
129 static enum pkg_filesdb_load_status saidread = PKG_FILESDB_LOAD_NONE;
130
131 /**
132  * Erase the files saved in pkg.
133  */
134 static void
135 pkg_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
170 static struct fileinlist **
171 pkg_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  */
208 void
209 ensure_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)
305 static int
306 pkg_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
321 static void
322 pkg_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)
371 static void
372 pkg_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
393 static void
394 pkg_files_optimize_load(struct pkg_array *array)
395 {
396 }
397 #endif
398
399 void 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
438 void 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  */
447 void
448 write_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  */
484 void
485 reversefilelist_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
499 struct filenamenode *
500 reversefilelist_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  */
520 void
521 reversefilelist_abort(struct reversefilelistiter *iter)
522 {
523   while (reversefilelist_next(iter));
524 }
525
526 struct 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
535 static struct filenamenode *bins[BINS];
536
537 struct fileiterator *
538 files_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
549 struct filenamenode *
550 files_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
565 void
566 files_db_iter_free(struct fileiterator *iter)
567 {
568   free(iter);
569 }
570
571 void 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
584 void
585 files_db_reset(void)
586 {
587   int i;
588
589   for (i = 0; i < BINS; i++)
590     bins[i] = NULL;
591 }
592
593 struct 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 }