~ubuntu-branches/ubuntu/oneiric/dpkg/oneiric-proposed

« back to all changes in this revision

Viewing changes to src/infodb.c

  • Committer: Steve Langasek
  • Date: 2011-03-15 00:11:56 UTC
  • Revision ID: steve.langasek@linaro.org-20110315001156-uyrlgh501d69seku
Merge newer snapshot from Raphael, to keep us in tune with mainline

Show diffs side-by-side

added added

removed removed

Lines of Context:
 
1
/*
 
2
 * dpkg - main program for package management
 
3
 * infodb.c - package control information database
 
4
 *
 
5
 * Copyright © 1995 Ian Jackson <ian@chiark.greenend.org.uk>
 
6
 * Copyright © 2011 Guillem Jover <guillem@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 <http://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 <fcntl.h>
 
30
#include <dirent.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/dir.h>
 
38
#include <dpkg/fdio.h>
 
39
#include <dpkg/debug.h>
 
40
#include <dpkg/varbuf.h>
 
41
 
 
42
#include "filesdb.h"
 
43
#include "infodb.h"
 
44
 
 
45
/* Forward declarations of static functions */
 
46
static void pkg_infodb_upgrade_to_multiarch(void);
 
47
 
 
48
/* Global variables */
 
49
static int db_format;
 
50
static char *db_format_file;
 
51
 
 
52
void
 
53
pkg_infodb_init(const enum modstatdb_rw flags)
 
54
{
 
55
        int fd;
 
56
 
 
57
        if (db_format_file)
 
58
                free(db_format_file);
 
59
        db_format_file = dpkg_db_get_path("format");
 
60
        fd = open(db_format_file, O_RDONLY);
 
61
        if (fd < 0 && errno == ENOENT) {
 
62
                db_format = 0; /* Lack of file means old format */
 
63
        } else if (fd < 0) {
 
64
                ohshite(_("error trying to open %.250s"), db_format_file);
 
65
        } else {
 
66
                char format[16], *endptr = NULL;
 
67
                ssize_t size;
 
68
 
 
69
                size = fd_read(fd, format, sizeof(format) - 1);
 
70
                if (size < 0) {
 
71
                        ohshite(_("error while reading %s"), db_format_file);
 
72
                }
 
73
                format[size] = '\0';
 
74
                db_format = strtol(format, &endptr, 10);
 
75
                if (endptr && *endptr != '\0' && *endptr != '\n')
 
76
                        ohshit(_("%s is corrupted, it should contain the "
 
77
                                 "database format version (an integer)"),
 
78
                               db_format_file);
 
79
                close(fd);
 
80
        }
 
81
        if (flags >= msdbrw_write && db_format < 2)
 
82
                pkg_infodb_upgrade_to_multiarch();
 
83
}
 
84
 
 
85
int
 
86
pkg_infodb_format(void)
 
87
{
 
88
        return db_format;
 
89
}
 
90
 
 
91
struct match_node {
 
92
        struct match_node *next;
 
93
        char *old;
 
94
        char *new;
 
95
};
 
96
 
 
97
static struct match_node *match_head = NULL;
 
98
 
 
99
static struct match_node *
 
100
match_node_new(const char *old, const char *new, struct match_node *next)
 
101
{
 
102
        struct match_node *node;
 
103
 
 
104
        node = m_malloc(sizeof(*node));
 
105
        node->next = next;
 
106
        node->old = m_strdup(old);
 
107
        node->new = m_strdup(new);
 
108
 
 
109
        return node;
 
110
}
 
111
 
 
112
static void
 
113
match_node_free(struct match_node *node)
 
114
{
 
115
        free(node->old);
 
116
        free(node->new);
 
117
        free(node);
 
118
}
 
119
 
 
120
static void
 
121
pkg_infodb_setup_multiarch_path(const char *filename, const char *filetype)
 
122
{
 
123
        static struct varbuf pkgname;
 
124
        const char *name, *dot;
 
125
        struct pkginfo *pkg;
 
126
        struct pkgset *set;
 
127
 
 
128
        dot = strrchr(filename, '.');
 
129
        name = strrchr(filename, '/');
 
130
        if (name == NULL)
 
131
                name = filename;
 
132
        else
 
133
                name++;
 
134
 
 
135
        varbuf_reset(&pkgname);
 
136
        varbuf_add_buf(&pkgname, name, dot - name);
 
137
        varbuf_end_str(&pkgname);
 
138
 
 
139
        if (strchr(pkgname.buf, ':'))
 
140
                return; /* Skip files already converted */
 
141
 
 
142
        set = pkg_db_find_set(pkgname.buf);
 
143
        pkg = &set->pkg;
 
144
        while (pkg) {
 
145
                if (pkg->status != stat_notinstalled)
 
146
                        break;
 
147
                pkg = pkg->arch_next;
 
148
        }
 
149
        if (!pkg) {
 
150
                warning(_("Info file %s not associated to any package"), filename);
 
151
                return;
 
152
        }
 
153
        if (pkg->installed.multiarch == multiarch_same) {
 
154
                /* We found one to ugprade */
 
155
                struct varbuf new = VARBUF_INIT;
 
156
                struct stat st;
 
157
 
 
158
                varbuf_add_str(&new, pkgadmindir());
 
159
                varbuf_pkg(&new, pkg, pdo_always);
 
160
                varbuf_add_char(&new, '.');
 
161
                varbuf_add_str(&new, filetype);
 
162
                varbuf_end_str(&new);
 
163
                if (stat(new.buf, &st) && errno == ENOENT) {
 
164
                        if (link(filename, new.buf))
 
165
                                ohshite(_("error creating hard link `%.255s'"),
 
166
                                        new.buf);
 
167
                }
 
168
                match_head = match_node_new(filename, new.buf, match_head);
 
169
                varbuf_destroy(&new);
 
170
        }
 
171
}
 
172
 
 
173
static void
 
174
pkg_infodb_record_format(int version)
 
175
{
 
176
        int fd, size;
 
177
        char format[16];
 
178
        ssize_t written;
 
179
 
 
180
        size = snprintf(format, sizeof(format), "%d", version);
 
181
        fd = open(db_format_file, O_WRONLY | O_CREAT | O_TRUNC, 0644);
 
182
        if (fd < 1)
 
183
                ohshite(_("unable to open/create '%s'"), db_format_file);
 
184
        written = fd_write(fd, format, size);
 
185
        if (written < 0) {
 
186
                ohshite(_("error while writing '%s'"), db_format_file);
 
187
        }
 
188
        if (fsync(fd))
 
189
                ohshite(_("unable to sync file '%s'"), db_format_file);
 
190
        if (close(fd))
 
191
                ohshite(_("unable to close file '%s'"), db_format_file);
 
192
        dir_sync_path_parent(db_format_file);
 
193
        db_format = version;
 
194
}
 
195
 
 
196
static void
 
197
cu_abort_db_upgrade(int argc, void **argv)
 
198
{
 
199
        struct match_node *next;
 
200
        struct stat st;
 
201
 
 
202
        /* Restore the old files if needed and drop the newly created files */
 
203
        while (match_head) {
 
204
                next = match_head->next;
 
205
                if (stat(match_head->old, &st) && errno == ENOENT)
 
206
                        if (link(match_head->new, match_head->old))
 
207
                                ohshite(_("error creating hard link `%.255s'"),
 
208
                                        match_head->old);
 
209
                if (unlink(match_head->new))
 
210
                        ohshite(_("cannot remove `%.250s'"), match_head->new);
 
211
                match_node_free(match_head);
 
212
                match_head = next;
 
213
        }
 
214
        pkg_infodb_record_format(0);
 
215
}
 
216
 
 
217
static void
 
218
pkg_infodb_upgrade_to_multiarch(void)
 
219
{
 
220
        struct match_node *next;
 
221
 
 
222
        push_cleanup(cu_abort_db_upgrade, ehflag_bombout, NULL, 0, 0);
 
223
        pkg_infodb_foreach(NULL, NULL, pkg_infodb_setup_multiarch_path);
 
224
        pkg_infodb_record_format(1);
 
225
        while (match_head) {
 
226
                next = match_head->next;
 
227
                if (unlink(match_head->old))
 
228
                        ohshite(_("cannot remove `%.250s'"), match_head->old);
 
229
                match_node_free(match_head);
 
230
                match_head = next;
 
231
        }
 
232
        pkg_infodb_record_format(2);
 
233
        pop_cleanup(ehflag_normaltidy);
 
234
}
 
235
 
 
236
bool
 
237
pkg_infodb_has_file(struct pkginfo *pkg, struct pkgbin *pkgbin,
 
238
                    const char *name)
 
239
{
 
240
        const char *filename;
 
241
        struct stat stab;
 
242
 
 
243
        filename = pkgadminfile(pkg, pkgbin, name);
 
244
        if (lstat(filename, &stab) == 0)
 
245
                return true;
 
246
        else if (errno == ENOENT)
 
247
                return false;
 
248
        else
 
249
                ohshite(_("unable to check existence of `%.250s'"), filename);
 
250
}
 
251
 
 
252
void
 
253
pkg_infodb_foreach(struct pkginfo *pkg, struct pkgbin *pkgbin,
 
254
                   pkg_infodb_file_func *func)
 
255
{
 
256
        DIR *db_dir;
 
257
        struct dirent *db_de;
 
258
        struct varbuf db_path = VARBUF_INIT;
 
259
        struct varbuf pkgname = VARBUF_INIT;
 
260
        size_t db_path_len;
 
261
 
 
262
        if (pkg) {
 
263
                varbuf_add_str(&pkgname, pkg->set->name);
 
264
                if (pkgbin->multiarch == multiarch_same &&
 
265
                    pkg_infodb_format() > 0) {
 
266
                        varbuf_add_char(&pkgname, ':');
 
267
                        varbuf_add_str(&pkgname, pkgbin->arch->name);
 
268
                }
 
269
                varbuf_end_str(&pkgname);
 
270
        }
 
271
 
 
272
        varbuf_add_str(&db_path, pkgadmindir());
 
273
        db_path_len = db_path.used;
 
274
        varbuf_add_char(&db_path, '\0');
 
275
 
 
276
        db_dir = opendir(db_path.buf);
 
277
        if (!db_dir)
 
278
                ohshite(_("cannot read info directory"));
 
279
 
 
280
        push_cleanup(cu_closedir, ~0, NULL, 0, 1, (void *)db_dir);
 
281
        while ((db_de = readdir(db_dir)) != NULL) {
 
282
                const char *filename, *filetype, *dot;
 
283
 
 
284
                debug(dbg_veryverbose, "infodb foreach info file '%s'",
 
285
                      db_de->d_name);
 
286
 
 
287
                /* Ignore dotfiles, including ‘.’ and ‘..’. */
 
288
                if (db_de->d_name[0] == '.')
 
289
                        continue;
 
290
 
 
291
                /* Ignore anything odd. */
 
292
                dot = strrchr(db_de->d_name, '.');
 
293
                if (dot == NULL)
 
294
                        continue;
 
295
 
 
296
                /* Ignore files from other packages if pkg is supplied. */
 
297
                if (pkg) {
 
298
                        if (pkgname.used != (size_t)(dot - db_de->d_name) ||
 
299
                            strncmp(db_de->d_name, pkgname.buf, pkgname.used))
 
300
                                continue;
 
301
                        debug(dbg_stupidlyverbose,
 
302
                              "infodb foreach file this pkg");
 
303
                }
 
304
 
 
305
                /* Skip past the full stop. */
 
306
                filetype = dot + 1;
 
307
 
 
308
                varbuf_trunc(&db_path, db_path_len);
 
309
                varbuf_add_str(&db_path, db_de->d_name);
 
310
                varbuf_end_str(&db_path);
 
311
                filename = db_path.buf;
 
312
 
 
313
                func(filename, filetype);
 
314
        }
 
315
        pop_cleanup(ehflag_normaltidy); /* closedir */
 
316
 
 
317
        varbuf_destroy(&db_path);
 
318
        varbuf_destroy(&pkgname);
 
319
}