XBPS Library API  0.19
The X Binary Package System
package_config_files.c
1 /*-
2  * Copyright (c) 2009-2012 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 <stdio.h>
27 #include <stdlib.h>
28 #include <string.h>
29 #include <errno.h>
30 
31 #include "xbps_api_impl.h"
32 
33 /*
34  * Returns true if entry is a configuration file, false otherwise.
35  */
36 int HIDDEN
37 xbps_entry_is_a_conf_file(prop_dictionary_t propsd,
38  const char *entry_pname)
39 {
40  prop_array_t array;
41  const char *cffile;
42  size_t i;
43 
44  assert(prop_object_type(propsd) == PROP_TYPE_DICTIONARY);
45  assert(entry_pname != NULL);
46 
47  array = prop_dictionary_get(propsd, "conf_files");
48  if (array == NULL || prop_array_count(array) == 0)
49  return false;
50 
51  for (i = 0; i < prop_array_count(array); i++) {
52  prop_array_get_cstring_nocopy(array, i, &cffile);
53  if (strcmp(cffile, entry_pname) == 0)
54  return true;
55  }
56  return false;
57 }
58 
59 /*
60  * Returns 1 if entry should be installed, 0 if don't or -1 on error.
61  */
62 int HIDDEN
63 xbps_entry_install_conf_file(struct xbps_handle *xhp,
64  prop_dictionary_t filesd,
65  struct archive_entry *entry,
66  const char *entry_pname,
67  const char *pkgname,
68  const char *version)
69 {
70  prop_dictionary_t forigd;
71  prop_object_t obj, obj2;
72  prop_object_iterator_t iter, iter2;
73  const char *cffile, *sha256_new = NULL;
74  char *buf, *sha256_cur = NULL, *sha256_orig = NULL;
75  int rv = 0;
76 
77  assert(prop_object_type(filesd) == PROP_TYPE_DICTIONARY);
78  assert(entry != NULL);
79  assert(entry_pname != NULL);
80  assert(pkgname != NULL);
81  assert(version != NULL);
82 
83  iter = xbps_array_iter_from_dict(filesd, "conf_files");
84  if (iter == NULL)
85  return -1;
86 
87  /*
88  * Get original hash for the file from current
89  * installed package.
90  */
91  xbps_dbg_printf(xhp, "%s-%s: processing conf_file %s\n",
92  pkgname, version, entry_pname);
93 
94  forigd = xbps_pkgdb_get_pkg_metadata(xhp, pkgname);
95  if (forigd == NULL) {
96  xbps_dbg_printf(xhp, "%s-%s: conf_file %s not currently "
97  "installed\n", pkgname, version, entry_pname);
98  rv = 1;
99  goto out;
100  }
101 
102  iter2 = xbps_array_iter_from_dict(forigd, "conf_files");
103  if (iter2 != NULL) {
104  while ((obj2 = prop_object_iterator_next(iter2))) {
105  prop_dictionary_get_cstring_nocopy(obj2,
106  "file", &cffile);
107  buf = xbps_xasprintf(".%s", cffile);
108  if (strcmp(entry_pname, buf) == 0) {
109  prop_dictionary_get_cstring(obj2, "sha256",
110  &sha256_orig);
111  free(buf);
112  break;
113  }
114  free(buf);
115  buf = NULL;
116  }
117  prop_object_iterator_release(iter2);
118  }
119  /*
120  * First case: original hash not found, install new file.
121  */
122  if (sha256_orig == NULL) {
123  xbps_dbg_printf(xhp, "%s-%s: conf_file %s not installed\n",
124  pkgname, version, entry_pname);
125  rv = 1;
126  goto out;
127  }
128 
129  /*
130  * Compare original, installed and new hash for current file.
131  */
132  while ((obj = prop_object_iterator_next(iter))) {
133  prop_dictionary_get_cstring_nocopy(obj, "file", &cffile);
134  buf = xbps_xasprintf(".%s", cffile);
135  if (strcmp(entry_pname, buf)) {
136  free(buf);
137  buf = NULL;
138  continue;
139  }
140  sha256_cur = xbps_file_hash(buf);
141  free(buf);
142  prop_dictionary_get_cstring_nocopy(obj, "sha256", &sha256_new);
143  if (sha256_cur == NULL) {
144  if (errno == ENOENT) {
145  /*
146  * File not installed, install new one.
147  */
148  xbps_dbg_printf(xhp, "%s-%s: conf_file %s not "
149  "installed\n", pkgname, version,
150  entry_pname);
151  rv = 1;
152  break;
153  } else {
154  rv = -1;
155  break;
156  }
157  }
158  /*
159  * Orig = X, Curr = X, New = X
160  *
161  * Keep file as is (no changes).
162  */
163  if ((strcmp(sha256_orig, sha256_cur) == 0) &&
164  (strcmp(sha256_orig, sha256_new) == 0) &&
165  (strcmp(sha256_cur, sha256_new) == 0)) {
166  xbps_dbg_printf(xhp, "%s-%s: conf_file %s orig = X, "
167  "cur = X, new = X\n", pkgname, version,
168  entry_pname);
169  rv = 0;
170  break;
171  /*
172  * Orig = X, Curr = X, New = Y
173  *
174  * Install new file (installed file hasn't been modified).
175  */
176  } else if ((strcmp(sha256_orig, sha256_cur) == 0) &&
177  (strcmp(sha256_orig, sha256_new)) &&
178  (strcmp(sha256_cur, sha256_new))) {
179  xbps_set_cb_state(xhp, XBPS_STATE_CONFIG_FILE,
180  0, pkgname, version,
181  "Updating configuration file `%s' provided "
182  "by version `%s'.", cffile, version);
183  rv = 1;
184  break;
185  /*
186  * Orig = X, Curr = Y, New = X
187  *
188  * Keep installed file as is because it has been modified,
189  * but new package doesn't contain new changes compared
190  * to the original version.
191  */
192  } else if ((strcmp(sha256_orig, sha256_new) == 0) &&
193  (strcmp(sha256_cur, sha256_new)) &&
194  (strcmp(sha256_orig, sha256_cur))) {
195  xbps_set_cb_state(xhp, XBPS_STATE_CONFIG_FILE,
196  0, pkgname, version,
197  "Keeping modified configuration file `%s'.",
198  cffile);
199  rv = 0;
200  break;
201  /*
202  * Orig = X, Curr = Y, New = Y
203  *
204  * Keep file as is because changes made are compatible
205  * with new version.
206  */
207  } else if ((strcmp(sha256_cur, sha256_new) == 0) &&
208  (strcmp(sha256_orig, sha256_new)) &&
209  (strcmp(sha256_orig, sha256_cur))) {
210  xbps_dbg_printf(xhp, "%s-%s: conf_file %s orig = X, "
211  "cur = Y, new = Y\n", pkgname, version,
212  entry_pname);
213  rv = 0;
214  break;
215  /*
216  * Orig = X, Curr = Y, New = Z
217  *
218  * Install new file as <file>.new-<version>
219  */
220  } else if ((strcmp(sha256_orig, sha256_cur)) &&
221  (strcmp(sha256_cur, sha256_new)) &&
222  (strcmp(sha256_orig, sha256_new))) {
223  buf = xbps_xasprintf(".%s.new-%s",
224  cffile, version);
225  xbps_set_cb_state(xhp, XBPS_STATE_CONFIG_FILE,
226  0, pkgname, version,
227  "Installing new configuration file to "
228  "`%s.new-%s'.", cffile, version);
229  archive_entry_set_pathname(entry, buf);
230  free(buf);
231  rv = 1;
232  break;
233  }
234  }
235 
236 out:
237  if (sha256_orig)
238  free(sha256_orig);
239  if (sha256_cur)
240  free(sha256_cur);
241 
242  prop_object_iterator_release(iter);
243 
244  xbps_dbg_printf(xhp, "%s-%s: conf_file %s returned %d\n",
245  pkgname, version, entry_pname, rv);
246 
247  return rv;
248 }