XBPS Library API 20240111
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 assert(version);
103 xbps_dbg_printf("%s: conf_file %s not currently "
104 "installed, renaming to %s.new-%s\n", pkgver,
105 entry_pname, entry_pname, version);
106 snprintf(buf, sizeof(buf), "%s.new-%s", entry_pname, version);
107 xbps_set_cb_state(xhp, XBPS_STATE_CONFIG_FILE,
108 0, pkgver, "File `%s' exists, installing configuration file to `%s'.", entry_pname, buf);
109 archive_entry_copy_pathname(entry, buf);
110 rv = 1;
111 goto out;
112 }
113
114 iter2 = xbps_array_iter_from_dict(pkg_filesd, "conf_files");
115 if (iter2 != NULL) {
116 while ((obj2 = xbps_object_iterator_next(iter2))) {
117 xbps_dictionary_get_cstring_nocopy(obj2,
118 "file", &cffile);
119 snprintf(buf, sizeof(buf), ".%s", cffile);
120 if (strcmp(entry_pname, buf) == 0) {
121 xbps_dictionary_get_cstring_nocopy(obj2, "sha256", &sha256_orig);
122 break;
123 }
124 }
125 xbps_object_iterator_release(iter2);
126 }
127 /*
128 * First case: original hash not found, install new file.
129 */
130 if (sha256_orig == NULL) {
131 xbps_dbg_printf("%s: conf_file %s not installed\n",
132 pkgver, entry_pname);
133 rv = 1;
134 goto out;
135 }
136
137 /*
138 * Compare original, installed and new hash for current file.
139 */
140 while ((obj = xbps_object_iterator_next(iter))) {
141 xbps_dictionary_get_cstring_nocopy(obj, "file", &cffile);
142 snprintf(buf, sizeof(buf), ".%s", cffile);
143 if (strcmp(entry_pname, buf)) {
144 continue;
145 }
146 if (!xbps_file_sha256(sha256_cur, sizeof sha256_cur, buf)) {
147 if (errno == ENOENT) {
148 /*
149 * File not installed, install new one.
150 */
151 xbps_dbg_printf("%s: conf_file %s not "
152 "installed\n", pkgver, entry_pname);
153 rv = 1;
154 break;
155 } else {
156 rv = -1;
157 break;
158 }
159 }
160 xbps_dictionary_get_cstring_nocopy(obj, "sha256", &sha256_new);
161 /*
162 * Orig = X, Curr = X, New = X
163 *
164 * Keep file as is (no changes).
165 */
166 if ((strcmp(sha256_orig, sha256_cur) == 0) &&
167 (strcmp(sha256_orig, sha256_new) == 0) &&
168 (strcmp(sha256_cur, sha256_new) == 0)) {
169 xbps_dbg_printf("%s: conf_file %s orig = X, "
170 "cur = X, new = X\n", pkgver, entry_pname);
171 rv = 0;
172 break;
173 /*
174 * Orig = X, Curr = X, New = Y
175 *
176 * Install new file (installed file hasn't been modified) if
177 * configuration option keepconfig is NOT set.
178 */
179 } else if ((strcmp(sha256_orig, sha256_cur) == 0) &&
180 (strcmp(sha256_orig, sha256_new)) &&
181 (strcmp(sha256_cur, sha256_new)) &&
182 (!(xhp->flags & XBPS_FLAG_KEEP_CONFIG))) {
183 xbps_set_cb_state(xhp, XBPS_STATE_CONFIG_FILE,
184 0, pkgver,
185 "Updating configuration file `%s' provided "
186 "by `%s'.", cffile, pkgver);
187 rv = 1;
188 break;
189 /*
190 * Orig = X, Curr = Y, New = X
191 *
192 * Keep installed file as is because it has been modified,
193 * but new package doesn't contain new changes compared
194 * to the original version.
195 */
196 } else if ((strcmp(sha256_orig, sha256_new) == 0) &&
197 (strcmp(sha256_cur, sha256_new)) &&
198 (strcmp(sha256_orig, sha256_cur))) {
199 xbps_set_cb_state(xhp, XBPS_STATE_CONFIG_FILE,
200 0, pkgver,
201 "Keeping modified configuration file `%s'.",
202 cffile);
203 rv = 0;
204 break;
205 /*
206 * Orig = X, Curr = Y, New = Y
207 *
208 * Keep file as is because changes made are compatible
209 * with new version.
210 */
211 } else if ((strcmp(sha256_cur, sha256_new) == 0) &&
212 (strcmp(sha256_orig, sha256_new)) &&
213 (strcmp(sha256_orig, sha256_cur))) {
214 xbps_dbg_printf("%s: conf_file %s orig = X, "
215 "cur = Y, new = Y\n", pkgver, entry_pname);
216 rv = 0;
217 break;
218 /*
219 * Orig = X, Curr = Y, New = Z
220 * or
221 * Orig = X, Curr = X, New = Y if keepconf is set
222 *
223 * Install new file as <file>.new-<version>
224 */
225 } else if (((strcmp(sha256_orig, sha256_cur)) &&
226 (strcmp(sha256_cur, sha256_new)) &&
227 (strcmp(sha256_orig, sha256_new))) ||
228 (xhp->flags & XBPS_FLAG_KEEP_CONFIG)) {
229 version = xbps_pkg_version(pkgver);
230 assert(version);
231 snprintf(buf, sizeof(buf), ".%s.new-%s", cffile, version);
232 xbps_set_cb_state(xhp, XBPS_STATE_CONFIG_FILE,
233 0, pkgver, "File `%s' exists, installing configuration file to `%s'.", cffile, buf);
234 archive_entry_copy_pathname(entry, buf);
235 rv = 1;
236 break;
237 }
238 }
239
240out:
241
242 xbps_object_iterator_release(iter);
243
244 xbps_dbg_printf("%s: conf_file %s returned %d\n",
245 pkgver, entry_pname, rv);
246
247 return rv;
248}
int flags
Definition xbps.h:679
Generic XBPS structure handler for initialization.
Definition xbps.h:550
xbps_object_iterator_t xbps_array_iter_from_dict(xbps_dictionary_t dict, const char *key)
Definition plist.c:202
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:124