1 /*
2  * dpkg - main program for package management
3  * db-ctrl-format.c - package control information database format
4  *
5  * Copyright © 2011-2014 Guillem Jover <guillem@debian.org>
6  *
7  * This is free software; you can redistribute it and/or modify
8  * it under the terms of the GNU General Public License as published by
9  * the Free Software Foundation; either version 2 of the License, or
10  * (at your option) any later version.
11  *
12  * This is distributed in the hope that it will be useful,
13  * but WITHOUT ANY WARRANTY; without even the implied warranty of
14  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
15  * GNU General Public License for more details.
16  *
17  * You should have received a copy of the GNU General Public License
18  * along with this program.  If not, see <https://www.gnu.org/licenses/>.
19  */
20 
21 #include <config.h>
22 #include <compat.h>
23 
24 #include <sys/types.h>
25 #include <sys/stat.h>
26 
27 #include <errno.h>
28 #include <stdlib.h>
29 #include <stdio.h>
30 
31 #include <dpkg/i18n.h>
32 #include <dpkg/dpkg.h>
33 #include <dpkg/dpkg-db.h>
34 #include <dpkg/varbuf.h>
35 #include <dpkg/db-ctrl.h>
36 
37 static enum pkg_infodb_format db_format = PKG_INFODB_FORMAT_UNKNOWN;
38 static bool db_upgrading;
39 static char *db_infodir;
40 
41 static enum pkg_infodb_format
pkg_infodb_parse_format(const char * file)42 pkg_infodb_parse_format(const char *file)
43 {
44 	FILE *fp;
45 	unsigned int format;
46 
47 	fp = fopen(file, "r");
48 	if (fp == NULL) {
49 		/* A missing format file means legacy format (0). */
50 		if (errno == ENOENT)
51 			return PKG_INFODB_FORMAT_LEGACY;
52 		ohshite(_("error trying to open %.250s"), file);
53 	}
54 
55 	if (fscanf(fp, "%u", &format) != 1)
56 		ohshit(_("corrupt info database format file '%s'"), file);
57 
58 	fclose(fp);
59 
60 	return format;
61 }
62 
63 static enum pkg_infodb_format
pkg_infodb_read_format(void)64 pkg_infodb_read_format(void)
65 {
66 	struct atomic_file *file;
67 	struct stat st;
68 	char *filename;
69 
70 	filename = dpkg_db_get_path(INFODIR "/format");
71 	file = atomic_file_new(filename, 0);
72 
73 	db_format = pkg_infodb_parse_format(file->name);
74 
75 	/* Check if a previous upgrade got interrupted. Because we are only
76 	 * supposed to upgrade the db layout one format at a time, if the
77 	 * new file exists that means the new format is just one ahead,
78 	 * we don't try to read it because it contains unreliable data. */
79 	if (stat(file->name_new, &st) == 0) {
80 		db_format++;
81 		db_upgrading = true;
82 	}
83 
84 	atomic_file_free(file);
85 	free(filename);
86 
87 	if (db_format < 0 || db_format >= PKG_INFODB_FORMAT_LAST)
88 		ohshit(_("info database format (%d) is bogus or too new; "
89 		         "try getting a newer dpkg"), db_format);
90 
91 	return db_format;
92 }
93 
94 enum pkg_infodb_format
pkg_infodb_get_format(void)95 pkg_infodb_get_format(void)
96 {
97 	if (db_format > PKG_INFODB_FORMAT_UNKNOWN)
98 		return db_format;
99 	else
100 		return pkg_infodb_read_format();
101 }
102 
103 void
pkg_infodb_set_format(enum pkg_infodb_format version)104 pkg_infodb_set_format(enum pkg_infodb_format version)
105 {
106 	db_format = version;
107 }
108 
109 bool
pkg_infodb_is_upgrading(void)110 pkg_infodb_is_upgrading(void)
111 {
112 	if (db_format < 0)
113 		pkg_infodb_read_format();
114 
115 	return db_upgrading;
116 }
117 
118 const char *
pkg_infodb_get_dir(void)119 pkg_infodb_get_dir(void)
120 {
121 	if (db_infodir == NULL)
122 		db_infodir = dpkg_db_get_path(INFODIR);
123 
124 	return db_infodir;
125 }
126 
127 const char *
pkg_infodb_get_file(const struct pkginfo * pkg,const struct pkgbin * pkgbin,const char * filetype)128 pkg_infodb_get_file(const struct pkginfo *pkg, const struct pkgbin *pkgbin,
129                     const char *filetype)
130 {
131 	static struct varbuf vb;
132 	enum pkg_infodb_format format;
133 
134 	/* Make sure to always read and verify the format version. */
135 	format = pkg_infodb_get_format();
136 
137 	varbuf_reset(&vb);
138 	varbuf_add_str(&vb, pkg_infodb_get_dir());
139 	varbuf_add_char(&vb, '/');
140 	varbuf_add_str(&vb, pkg->set->name);
141 	if (pkgbin->multiarch == PKG_MULTIARCH_SAME &&
142 	    format == PKG_INFODB_FORMAT_MULTIARCH)
143 		varbuf_add_archqual(&vb, pkgbin->arch);
144 	varbuf_add_char(&vb, '.');
145 	varbuf_add_str(&vb, filetype);
146 	varbuf_end_str(&vb);
147 
148 	return vb.buf;
149 }
150 
151 const char *
pkg_infodb_reset_dir(void)152 pkg_infodb_reset_dir(void)
153 {
154 	free(db_infodir);
155 	db_infodir = NULL;
156 
157 	return pkg_infodb_get_dir();
158 }
159