XBPS Library API 20260501
The X Binary Package System
package_config_files.c
1/*-
2 * Copyright (c) 2009-2014 Juan Romero Pardines.
3 * All rights reserved.
4 *
5 * Redistribution and use in source and binary forms, with or without
6 * modification, are permitted provided that the following conditions
7 * are met:
8 * 1. Redistributions of source code must retain the above copyright
9 * notice, this list of conditions and the following disclaimer.
10 * 2. Redistributions in binary form must reproduce the above copyright
11 * notice, this list of conditions and the following disclaimer in the
12 * documentation and/or other materials provided with the distribution.
13 *
14 * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
15 * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
16 * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
17 * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
18 * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
19 * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
20 * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
21 * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
22 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
23 * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
24 */
25
26#include <errno.h>
27#include <limits.h>
28#include <stdio.h>
29#include <stdlib.h>
30#include <string.h>
31
32#include <archive_entry.h>
33
34#include "xbps_api_impl.h"
35
36/*
37 * Returns true if entry is a configuration file, false otherwise.
38 */
39int HIDDEN
40xbps_entry_is_a_conf_file(xbps_dictionary_t filesd,
41 const char *entry_pname)
42{
43 xbps_array_t array;
44 xbps_dictionary_t d;
45 const char *cffile;
46
47 array = xbps_dictionary_get(filesd, "conf_files");
48 if (xbps_array_count(array) == 0)
49 return false;
50
51 for (unsigned int i = 0; i < xbps_array_count(array); i++) {
52 d = xbps_array_get(array, i);
53 xbps_dictionary_get_cstring_nocopy(d, "file", &cffile);
54 if (strcmp(cffile, entry_pname) == 0)
55 return true;
56 }
57 return false;
58}
59
60/*
61 * Returns 1 if entry should be installed, 0 if don't or -1 on error.
62 */
63int HIDDEN
64xbps_entry_install_conf_file(struct xbps_handle *xhp,
65 xbps_dictionary_t binpkg_filesd,
66 xbps_dictionary_t pkg_filesd,
67 struct archive_entry *entry,
68 const char *entry_pname,
69 const char *pkgver,
70 bool mysymlink)
71{
72 xbps_object_t obj, obj2;
73 xbps_object_iterator_t iter, iter2;
74 const char *version = NULL, *cffile, *sha256_new = NULL;
75 char buf[PATH_MAX], sha256_cur[XBPS_SHA256_SIZE];
76 const char *sha256_orig = NULL;
77 int rv = 0;
78
79 assert(xbps_object_type(binpkg_filesd) == XBPS_TYPE_DICTIONARY);
80 assert(entry);
81 assert(entry_pname);
82 assert(pkgver);
83
84 iter = xbps_array_iter_from_dict(binpkg_filesd, "conf_files");
85 if (iter == NULL)
86 return -1;
87
88 /*
89 * Get original hash for the file from current
90 * installed package.
91 */
92 xbps_dbg_printf("%s: processing conf_file %s\n",
93 pkgver, entry_pname);
94
95 if (pkg_filesd == NULL || mysymlink) {
96 /*
97 * 1. File exists on disk but it's not managed by the same package.
98 * 2. File exists on disk as symlink.
99 * Install it as file.new-<version>.
100 */
101 version = xbps_pkg_version(pkgver);
102 if (!version)
104 xbps_dbg_printf("%s: conf_file %s not currently "
105 "installed, renaming to %s.new-%s\n", pkgver,
106 entry_pname, entry_pname, version);
107 snprintf(buf, sizeof(buf), "%s.new-%s", entry_pname, version);
108 xbps_set_cb_state(xhp, XBPS_STATE_CONFIG_FILE,
109 0, pkgver, "File `%s' exists, installing configuration file to `%s'.", entry_pname, buf);
110 archive_entry_copy_pathname(entry, buf);
111 rv = 1;
112 goto out;
113 }
114
115 iter2 = xbps_array_iter_from_dict(pkg_filesd, "conf_files");
116 if (iter2 != NULL) {
117 while ((obj2 = xbps_object_iterator_next(iter2))) {
118 xbps_dictionary_get_cstring_nocopy(obj2,
119 "file", &cffile);
120 snprintf(buf, sizeof(buf), ".%s", cffile);
121 if (strcmp(entry_pname, buf) == 0) {
122 xbps_dictionary_get_cstring_nocopy(obj2, "sha256", &sha256_orig);
123 break;
124 }
125 }
126 xbps_object_iterator_release(iter2);
127 }
128 /*
129 * First case: original hash not found, install new file.
130 */
131 if (sha256_orig == NULL) {
132 xbps_dbg_printf("%s: conf_file %s not installed\n",
133 pkgver, entry_pname);
134 rv = 1;
135 goto out;
136 }
137
138 /*
139 * Compare original, installed and new hash for current file.
140 */
141 while ((obj = xbps_object_iterator_next(iter))) {
142 xbps_dictionary_get_cstring_nocopy(obj, "file", &cffile);
143 snprintf(buf, sizeof(buf), ".%s", cffile);
144 if (strcmp(entry_pname, buf)) {
145 continue;
146 }
147 if (!xbps_file_sha256(sha256_cur, sizeof sha256_cur, buf)) {
148 if (errno == ENOENT) {
149 /*
150 * File not installed, install new one.
151 */
152 xbps_dbg_printf("%s: conf_file %s not "
153 "installed\n", pkgver, entry_pname);
154 rv = 1;
155 break;
156 } else {
157 rv = -1;
158 break;
159 }
160 }
161 xbps_dictionary_get_cstring_nocopy(obj, "sha256", &sha256_new);
162 /*
163 * Orig = X, Curr = X, New = X
164 *
165 * Keep file as is (no changes).
166 */
167 if ((strcmp(sha256_orig, sha256_cur) == 0) &&
168 (strcmp(sha256_orig, sha256_new) == 0) &&
169 (strcmp(sha256_cur, sha256_new) == 0)) {
170 xbps_dbg_printf("%s: conf_file %s orig = X, "
171 "cur = X, new = X\n", pkgver, entry_pname);
172 rv = 0;
173 break;
174 /*
175 * Orig = X, Curr = X, New = Y
176 *
177 * Install new file (installed file hasn't been modified) if
178 * configuration option keepconfig is NOT set.
179 */
180 } else if ((strcmp(sha256_orig, sha256_cur) == 0) &&
181 (strcmp(sha256_orig, sha256_new)) &&
182 (strcmp(sha256_cur, sha256_new)) &&
183 (!(xhp->flags & XBPS_FLAG_KEEP_CONFIG))) {
184 xbps_set_cb_state(xhp, XBPS_STATE_CONFIG_FILE,
185 0, pkgver,
186 "Updating configuration file `%s' provided "
187 "by `%s'.", cffile, pkgver);
188 rv = 1;
189 break;
190 /*
191 * Orig = X, Curr = Y, New = X
192 *
193 * Keep installed file as is because it has been modified,
194 * but new package doesn't contain new changes compared
195 * to the original version.
196 */
197 } else if ((strcmp(sha256_orig, sha256_new) == 0) &&
198 (strcmp(sha256_cur, sha256_new)) &&
199 (strcmp(sha256_orig, sha256_cur))) {
200 xbps_set_cb_state(xhp, XBPS_STATE_CONFIG_FILE,
201 0, pkgver,
202 "Keeping modified configuration file `%s'.",
203 cffile);
204 rv = 0;
205 break;
206 /*
207 * Orig = X, Curr = Y, New = Y
208 *
209 * Keep file as is because changes made are compatible
210 * with new version.
211 */
212 } else if ((strcmp(sha256_cur, sha256_new) == 0) &&
213 (strcmp(sha256_orig, sha256_new)) &&
214 (strcmp(sha256_orig, sha256_cur))) {
215 xbps_dbg_printf("%s: conf_file %s orig = X, "
216 "cur = Y, new = Y\n", pkgver, entry_pname);
217 rv = 0;
218 break;
219 /*
220 * Orig = X, Curr = Y, New = Z
221 * or
222 * Orig = X, Curr = X, New = Y if keepconf is set
223 *
224 * Install new file as <file>.new-<version>
225 */
226 } else if (((strcmp(sha256_orig, sha256_cur)) &&
227 (strcmp(sha256_cur, sha256_new)) &&
228 (strcmp(sha256_orig, sha256_new))) ||
229 (xhp->flags & XBPS_FLAG_KEEP_CONFIG)) {
230 version = xbps_pkg_version(pkgver);
231 if (!version)
233 snprintf(buf, sizeof(buf), ".%s.new-%s", cffile, version);
234 xbps_set_cb_state(xhp, XBPS_STATE_CONFIG_FILE,
235 0, pkgver, "File `%s' exists, installing configuration file to `%s'.", cffile, buf);
236 archive_entry_copy_pathname(entry, buf);
237 rv = 1;
238 break;
239 }
240 }
241
242out:
243
244 xbps_object_iterator_release(iter);
245
246 xbps_dbg_printf("%s: conf_file %s returned %d\n",
247 pkgver, entry_pname, rv);
248
249 return rv;
250}
int flags
Definition xbps.h:693
Generic XBPS structure handler for initialization.
Definition xbps.h:560
#define xbps_unreachable()
Log and abort for code that should be unreachable.
Definition xbps.h:783
void xbps_dbg_printf(const char *fmt,...)
Prints debug messages to stderr.
Definition log.c:67
xbps_object_iterator_t xbps_array_iter_from_dict(xbps_dictionary_t dict, const char *key)
Definition plist.c:232
bool xbps_file_sha256(char *dst, size_t len, const char *file)
Definition util_hash.c:148
const char * xbps_pkg_version(const char *pkg)
Definition util.c:120