chiark / gitweb /
lib/dpkg/tarfn.c: Kludge `tar_header_decode' to handle spurious `errno'.
[dpkg] / src / divertdb.c
1 /*
2  * dpkg - main program for package management
3  * divertdb.c - management of database of diverted files
4  *
5  * Copyright © 1995 Ian Jackson <ijackson@chiark.greenend.org.uk>
6  * Copyright © 2000, 2001 Wichert Akkerman <wakkerma@debian.org>
7  *
8  * This is free software; you can redistribute it and/or modify
9  * it under the terms of the GNU General Public License as published by
10  * the Free Software Foundation; either version 2 of the License, or
11  * (at your option) any later version.
12  *
13  * This is distributed in the hope that it will be useful,
14  * but WITHOUT ANY WARRANTY; without even the implied warranty of
15  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
16  * GNU General Public License for more details.
17  *
18  * You should have received a copy of the GNU General Public License
19  * along with this program.  If not, see <https://www.gnu.org/licenses/>.
20  */
21
22 #include <config.h>
23 #include <compat.h>
24
25 #include <sys/types.h>
26 #include <sys/stat.h>
27
28 #include <errno.h>
29 #include <string.h>
30 #include <pwd.h>
31 #include <grp.h>
32 #include <fcntl.h>
33 #include <unistd.h>
34 #include <stdlib.h>
35
36 #include <dpkg/i18n.h>
37 #include <dpkg/dpkg.h>
38 #include <dpkg/dpkg-db.h>
39
40 #include "filesdb.h"
41 #include "main.h"
42
43 static struct diversion *diversions = NULL;
44 static char *diversionsname;
45
46 void
47 ensure_diversions(void)
48 {
49         static struct stat sb_prev;
50         struct stat sb_next;
51         char linebuf[MAXDIVERTFILENAME];
52         static FILE *file_prev;
53         FILE *file;
54         struct diversion *ov, *oicontest, *oialtname;
55
56         if (diversionsname == NULL)
57                 diversionsname = dpkg_db_get_path(DIVERSIONSFILE);
58
59         onerr_abort++;
60
61         file = fopen(diversionsname, "r");
62         if (!file) {
63                 if (errno != ENOENT)
64                         ohshite(_("failed to open diversions file"));
65         } else {
66                 setcloexec(fileno(file), diversionsname);
67
68                 if (fstat(fileno(file), &sb_next))
69                         ohshite(_("failed to fstat diversions file"));
70
71                 /*
72                  * We need to keep the database file open so that the
73                  * filesystem cannot reuse the inode number (f.ex. during
74                  * multiple dpkg-divert invocations in a maintainer script),
75                  * otherwise the following check might turn true, and we
76                  * would skip reloading a modified database.
77                  */
78                 if (file_prev &&
79                     sb_prev.st_dev == sb_next.st_dev &&
80                     sb_prev.st_ino == sb_next.st_ino) {
81                         fclose(file);
82                         onerr_abort--;
83                         debug(dbg_general, "%s: same, skipping", __func__);
84                         return;
85                 }
86                 sb_prev = sb_next;
87         }
88         if (file_prev)
89                 fclose(file_prev);
90         file_prev = file;
91
92         for (ov = diversions; ov; ov = ov->next) {
93                 ov->useinstead->divert->camefrom->divert = NULL;
94                 ov->useinstead->divert = NULL;
95         }
96         diversions = NULL;
97         if (!file) {
98                 onerr_abort--;
99                 debug(dbg_general, "%s: none, resetting", __func__);
100                 return;
101         }
102         debug(dbg_general, "%s: new, (re)loading", __func__);
103
104         while (fgets_checked(linebuf, sizeof(linebuf), file, diversionsname) >= 0) {
105                 oicontest = nfmalloc(sizeof(struct diversion));
106                 oialtname = nfmalloc(sizeof(struct diversion));
107
108                 oialtname->camefrom = findnamenode(linebuf, 0);
109                 oialtname->useinstead = NULL;
110
111                 fgets_must(linebuf, sizeof(linebuf), file, diversionsname);
112                 oicontest->useinstead = findnamenode(linebuf, 0);
113                 oicontest->camefrom = NULL;
114
115                 fgets_must(linebuf, sizeof(linebuf), file, diversionsname);
116                 oicontest->pkgset = strcmp(linebuf, ":") ?
117                                     pkg_db_find_set(linebuf) : NULL;
118                 oialtname->pkgset = oicontest->pkgset;
119
120                 if (oialtname->camefrom->divert ||
121                     oicontest->useinstead->divert)
122                         ohshit(_("conflicting diversions involving '%.250s' or '%.250s'"),
123                                oialtname->camefrom->name, oicontest->useinstead->name);
124
125                 oialtname->camefrom->divert = oicontest;
126                 oicontest->useinstead->divert = oialtname;
127
128                 oicontest->next = diversions;
129                 diversions = oicontest;
130         }
131
132         onerr_abort--;
133 }