chiark / gitweb /
lib/dpkg/tarfn.c: Kludge `tar_header_decode' to handle spurious `errno'.
[dpkg] / src / infodb-upgrade.c
1 /*
2  * dpkg - main program for package management
3  * infodb-upgrade.c - package control information database format upgrade
4  *
5  * Copyright © 1995 Ian Jackson <ijackson@chiark.greenend.org.uk>
6  * Copyright © 2011-2014 Guillem Jover <guillem@debian.org>
7  * Copyright © 2011 Linaro Limited
8  * Copyright © 2011 Raphaël Hertzog <hertzog@debian.org>
9  *
10  * This is free software; you can redistribute it and/or modify
11  * it under the terms of the GNU General Public License as published by
12  * the Free Software Foundation; either version 2 of the License, or
13  * (at your option) any later version.
14  *
15  * This is distributed in the hope that it will be useful,
16  * but WITHOUT ANY WARRANTY; without even the implied warranty of
17  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
18  * GNU General Public License for more details.
19  *
20  * You should have received a copy of the GNU General Public License
21  * along with this program.  If not, see <https://www.gnu.org/licenses/>.
22  */
23
24 #include <config.h>
25 #include <compat.h>
26
27 #include <sys/types.h>
28 #include <sys/stat.h>
29
30 #include <errno.h>
31 #include <stdlib.h>
32 #include <unistd.h>
33
34 #include <dpkg/i18n.h>
35 #include <dpkg/dpkg.h>
36 #include <dpkg/dpkg-db.h>
37 #include <dpkg/path.h>
38 #include <dpkg/dir.h>
39
40 #include "filesdb.h"
41 #include "infodb.h"
42
43 struct rename_node {
44         struct rename_node *next;
45         char *old;
46         char *new;
47 };
48
49 /* Global variables. */
50 static struct rename_node *rename_head = NULL;
51
52 static struct rename_node *
53 rename_node_new(const char *old, const char *new, struct rename_node *next)
54 {
55         struct rename_node *node;
56
57         node = m_malloc(sizeof(*node));
58         node->next = next;
59         node->old = m_strdup(old);
60         node->new = m_strdup(new);
61
62         return node;
63 }
64
65 static void
66 rename_node_free(struct rename_node *node)
67 {
68         free(node->old);
69         free(node->new);
70         free(node);
71 }
72
73 static void
74 pkg_infodb_link_multiarch_files(void)
75 {
76         DIR *db_dir;
77         struct dirent *db_de;
78         struct varbuf pkgname = VARBUF_INIT;
79         struct varbuf oldname = VARBUF_INIT;
80         struct varbuf newname = VARBUF_INIT;
81         struct varbuf_state db_path_state;
82
83         varbuf_add_str(&oldname, pkg_infodb_get_dir());
84         varbuf_add_char(&oldname, '/');
85         varbuf_end_str(&oldname);
86         varbuf_snapshot(&oldname, &db_path_state);
87
88         varbuf_add_buf(&newname, oldname.buf, oldname.used);
89         varbuf_end_str(&newname);
90
91         db_dir = opendir(oldname.buf);
92         if (!db_dir)
93                 ohshite(_("cannot read info directory"));
94
95         push_cleanup(cu_closedir, ~0, NULL, 0, 1, (void *)db_dir);
96         while ((db_de = readdir(db_dir)) != NULL) {
97                 const char *filetype, *dot;
98                 struct pkginfo *pkg;
99                 struct pkgset *set;
100
101                 /* Ignore dotfiles, including ‘.’ and ‘..’. */
102                 if (db_de->d_name[0] == '.')
103                         continue;
104
105                 /* Ignore anything odd. */
106                 dot = strrchr(db_de->d_name, '.');
107                 if (dot == NULL)
108                         continue;
109
110                 varbuf_reset(&pkgname);
111                 varbuf_add_buf(&pkgname, db_de->d_name, dot - db_de->d_name);
112                 varbuf_end_str(&pkgname);
113
114                  /* Skip files already converted. */
115                 if (strchr(pkgname.buf, ':'))
116                         continue;
117
118                 set = pkg_db_find_set(pkgname.buf);
119                 for (pkg = &set->pkg; pkg; pkg = pkg->arch_next)
120                         if (pkg->status != PKG_STAT_NOTINSTALLED)
121                                 break;
122                 if (!pkg) {
123                         warning(_("info file %s/%s not associated to any package"),
124                                 pkg_infodb_get_dir(), db_de->d_name);
125                         continue;
126                 }
127
128                 /* Does it need to be upgraded? */
129                 if (pkg->installed.multiarch != PKG_MULTIARCH_SAME)
130                         continue;
131
132                 /* Skip past the full stop. */
133                 filetype = dot + 1;
134
135                 varbuf_rollback(&oldname, &db_path_state);
136                 varbuf_add_str(&oldname, db_de->d_name);
137                 varbuf_end_str(&oldname);
138
139                 varbuf_rollback(&newname, &db_path_state);
140                 varbuf_add_pkgbin_name(&newname, pkg, &pkg->installed, pnaw_always);
141                 varbuf_add_char(&newname, '.');
142                 varbuf_add_str(&newname, filetype);
143                 varbuf_end_str(&newname);
144
145                 if (link(oldname.buf, newname.buf) && errno != EEXIST)
146                         ohshite(_("error creating hard link '%.255s'"),
147                                 newname.buf);
148                 rename_head = rename_node_new(oldname.buf, newname.buf, rename_head);
149         }
150         pop_cleanup(ehflag_normaltidy); /* closedir */
151
152         varbuf_destroy(&pkgname);
153         varbuf_destroy(&newname);
154         varbuf_destroy(&oldname);
155 }
156
157 static void
158 cu_abort_db_upgrade(int argc, void **argv)
159 {
160         struct atomic_file *file = argv[0];
161         struct rename_node *next;
162
163         /* Restore the old files if needed and drop the newly created files. */
164         while (rename_head) {
165                 next = rename_head->next;
166                 if (link(rename_head->new, rename_head->old) && errno != EEXIST)
167                         ohshite(_("error creating hard link '%.255s'"),
168                                 rename_head->old);
169                 if (unlink(rename_head->new))
170                         ohshite(_("cannot remove '%.250s'"), rename_head->new);
171                 rename_node_free(rename_head);
172                 rename_head = next;
173         }
174         if (unlink(file->name_new) && errno != ENOENT)
175                 ohshite(_("cannot remove '%.250s'"), file->name_new);
176
177         atomic_file_free(file);
178 }
179
180 static void
181 pkg_infodb_write_format(struct atomic_file *file, int version)
182 {
183         if (fprintf(file->fp, "%d\n", version) < 0)
184                 ohshite(_("error while writing '%s'"), file->name_new);
185
186         atomic_file_sync(file);
187         atomic_file_close(file);
188         dir_sync_path_parent(file->name);
189
190         pkg_infodb_set_format(version);
191 }
192
193 static void
194 pkg_infodb_unlink_monoarch_files(void)
195 {
196         struct rename_node *next;
197
198         while (rename_head) {
199                 next = rename_head->next;
200                 if (unlink(rename_head->old))
201                         ohshite(_("cannot remove '%.250s'"), rename_head->old);
202                 rename_node_free(rename_head);
203                 rename_head = next;
204         }
205 }
206
207 static void
208 pkg_infodb_upgrade_to_multiarch(void)
209 {
210         struct atomic_file *db_file;
211         char *db_format_file;
212
213         db_format_file = dpkg_db_get_path(INFODIR "/format");
214         db_file = atomic_file_new(db_format_file, 0);
215         atomic_file_open(db_file);
216
217         push_cleanup(cu_abort_db_upgrade, ehflag_bombout, NULL, 0, 1, db_file);
218
219         pkg_infodb_link_multiarch_files();
220         pkg_infodb_write_format(db_file, 1);
221
222         pkg_infodb_unlink_monoarch_files();
223         atomic_file_commit(db_file);
224         dir_sync_path(pkg_infodb_get_dir());
225
226         pop_cleanup(ehflag_normaltidy);
227
228         atomic_file_free(db_file);
229         free(db_format_file);
230 }
231
232 /**
233  * Upgrade the infodb if there's the need and possibility.
234  *
235  * Currently this implies, that the modstatdb was opened for writing and:
236  * - previous upgrade has not been completed; or
237  * - current format is not the latest one.
238  */
239 void
240 pkg_infodb_upgrade(void)
241 {
242         enum pkg_infodb_format db_format;
243
244         /* Make sure to always read and verify the format version. */
245         db_format = pkg_infodb_get_format();
246
247         if (modstatdb_get_status() < msdbrw_write)
248                 return;
249
250         if (db_format < PKG_INFODB_FORMAT_MULTIARCH ||
251             pkg_infodb_is_upgrading())
252                 pkg_infodb_upgrade_to_multiarch();
253 }