XBPS Library API  0.19
The X Binary Package System
transaction_dictionary.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 <stdbool.h>
28 #include <stdlib.h>
29 #include <string.h>
30 #include <errno.h>
31 
32 #include "xbps_api_impl.h"
33 
34 /**
35  * @file lib/transaction_dictionary.c
36  * @brief Transaction handling routines
37  * @defgroup transaction Transaction handling functions
38  *
39  * The following image shows off the full transaction dictionary returned
40  * by xbps_transaction_prepare().
41  *
42  * @image html images/xbps_transaction_dictionary.png
43  *
44  * Legend:
45  * - <b>Salmon bg box</b>: The transaction dictionary.
46  * - <b>White bg box</b>: mandatory objects.
47  * - <b>Grey bg box</b>: optional objects.
48  * - <b>Green bg box</b>: possible value set in the object, only one of them
49  * will be set.
50  *
51  * Text inside of white boxes are the key associated with the object, its
52  * data type is specified on its edge, i.e string, array, integer, dictionary.
53  */
54 
55 static int
56 compute_transaction_stats(struct xbps_handle *xhp)
57 {
58  prop_dictionary_t pkg_metad;
59  prop_object_iterator_t iter;
60  prop_object_t obj;
61  uint64_t tsize, dlsize, instsize, rmsize;
62  uint32_t inst_pkgcnt, up_pkgcnt, cf_pkgcnt, rm_pkgcnt;
63  int rv = 0;
64  const char *tract, *pkgname, *repo;
65 
66  inst_pkgcnt = up_pkgcnt = cf_pkgcnt = rm_pkgcnt = 0;
67  tsize = dlsize = instsize = rmsize = 0;
68 
69  iter = xbps_array_iter_from_dict(xhp->transd, "packages");
70  if (iter == NULL)
71  return EINVAL;
72 
73  while ((obj = prop_object_iterator_next(iter)) != NULL) {
74  /*
75  * Count number of pkgs to be removed, configured,
76  * installed and updated.
77  */
78  prop_dictionary_get_cstring_nocopy(obj, "pkgname", &pkgname);
79  prop_dictionary_get_cstring_nocopy(obj, "transaction", &tract);
80  prop_dictionary_get_cstring_nocopy(obj, "repository", &repo);
81 
82  if (strcmp(tract, "configure") == 0) {
83  cf_pkgcnt++;
84  continue;
85  } else if (strcmp(tract, "install") == 0) {
86  inst_pkgcnt++;
87  } else if (strcmp(tract, "update") == 0) {
88  up_pkgcnt++;
89  } else if (strcmp(tract, "remove") == 0) {
90  rm_pkgcnt++;
91  }
92 
93  tsize = 0;
94  /*
95  * If removing or updating a package, get installed_size
96  * from pkg's metadata dictionary.
97  */
98  if ((strcmp(tract, "remove") == 0) ||
99  (strcmp(tract, "update") == 0)) {
100  pkg_metad = xbps_pkgdb_get_pkg_metadata(xhp, pkgname);
101  if (pkg_metad == NULL)
102  continue;
103  prop_dictionary_get_uint64(pkg_metad,
104  "installed_size", &tsize);
105  rmsize += tsize;
106  }
107  if ((strcmp(tract, "install") == 0) ||
108  (strcmp(tract, "update") == 0)) {
109  prop_dictionary_get_uint64(obj,
110  "installed_size", &tsize);
111  instsize += tsize;
112  if (xbps_repository_is_remote(repo)) {
113  prop_dictionary_get_uint64(obj,
114  "filename-size", &tsize);
115  dlsize += tsize;
116  }
117  }
118  }
119 
120  if (inst_pkgcnt &&
121  !prop_dictionary_set_uint32(xhp->transd, "total-install-pkgs",
122  inst_pkgcnt)) {
123  rv = EINVAL;
124  goto out;
125  }
126  if (up_pkgcnt &&
127  !prop_dictionary_set_uint32(xhp->transd, "total-update-pkgs",
128  up_pkgcnt)) {
129  rv = EINVAL;
130  goto out;
131  }
132  if (cf_pkgcnt &&
133  !prop_dictionary_set_uint32(xhp->transd, "total-configure-pkgs",
134  cf_pkgcnt)) {
135  rv = EINVAL;
136  goto out;
137  }
138  if (rm_pkgcnt &&
139  !prop_dictionary_set_uint32(xhp->transd, "total-remove-pkgs",
140  rm_pkgcnt)) {
141  rv = EINVAL;
142  goto out;
143  }
144 
145  if (instsize > rmsize) {
146  instsize -= rmsize;
147  rmsize = 0;
148  } else if (rmsize > instsize) {
149  rmsize -= instsize;
150  instsize = 0;
151  } else
152  instsize = rmsize = 0;
153 
154  /*
155  * Add object in transaction dictionary with total installed
156  * size that it will take.
157  */
158  if (!prop_dictionary_set_uint64(xhp->transd,
159  "total-installed-size", instsize)) {
160  rv = EINVAL;
161  goto out;
162  }
163  /*
164  * Add object in transaction dictionary with total download
165  * size that needs to be sucked in.
166  */
167  if (!prop_dictionary_set_uint64(xhp->transd,
168  "total-download-size", dlsize)) {
169  rv = EINVAL;
170  goto out;
171  }
172  /*
173  * Add object in transaction dictionary with total size to be
174  * freed from packages to be removed.
175  */
176  if (!prop_dictionary_set_uint64(xhp->transd,
177  "total-removed-size", rmsize)) {
178  rv = EINVAL;
179  goto out;
180  }
181 out:
182  prop_object_iterator_release(iter);
183 
184  return rv;
185 }
186 
187 int HIDDEN
188 xbps_transaction_init(struct xbps_handle *xhp)
189 {
190  prop_array_t unsorted, mdeps, conflicts;
191 
192  if (xhp->transd != NULL)
193  return 0;
194 
195  if ((xhp->transd = prop_dictionary_create()) == NULL)
196  return ENOMEM;
197 
198  if ((unsorted = prop_array_create()) == NULL) {
199  prop_object_release(xhp->transd);
200  xhp->transd = NULL;
201  return ENOMEM;
202  }
203  if (!xbps_add_obj_to_dict(xhp->transd, unsorted, "unsorted_deps")) {
204  prop_object_release(xhp->transd);
205  xhp->transd = NULL;
206  return EINVAL;
207  }
208  if ((mdeps = prop_array_create()) == NULL) {
209  prop_object_release(xhp->transd);
210  xhp->transd = NULL;
211  return ENOMEM;
212  }
213  if (!xbps_add_obj_to_dict(xhp->transd, mdeps, "missing_deps")) {
214  prop_object_release(xhp->transd);
215  xhp->transd = NULL;
216  return EINVAL;
217  }
218  if ((conflicts = prop_array_create()) == NULL) {
219  prop_object_release(xhp->transd);
220  xhp->transd = NULL;
221  return ENOMEM;
222  }
223  if (!xbps_add_obj_to_dict(xhp->transd, conflicts, "conflicts")) {
224  prop_object_release(xhp->transd);
225  xhp->transd = NULL;
226  return EINVAL;
227  }
228 
229  return 0;
230 }
231 
232 int
234 {
235  prop_array_t mdeps, conflicts;
236  int rv = 0;
237 
238  if (xhp->transd == NULL)
239  return ENXIO;
240 
241  /*
242  * If there are missing deps bail out.
243  */
244  mdeps = prop_dictionary_get(xhp->transd, "missing_deps");
245  if (prop_array_count(mdeps) > 0)
246  return ENODEV;
247 
248  /*
249  * If there are package conflicts bail out.
250  */
251  conflicts = prop_dictionary_get(xhp->transd, "conflicts");
252  if (prop_array_count(conflicts) > 0)
253  return EAGAIN;
254 
255  /*
256  * Check for packages to be replaced.
257  */
258  if ((rv = xbps_transaction_package_replace(xhp)) != 0) {
259  prop_object_release(xhp->transd);
260  xhp->transd = NULL;
261  return rv;
262  }
263  /*
264  * Sort package dependencies if necessary.
265  */
266  if ((rv = xbps_transaction_sort(xhp)) != 0) {
267  prop_object_release(xhp->transd);
268  xhp->transd = NULL;
269  return rv;
270  }
271  /*
272  * Add transaction stats for total download/installed size,
273  * number of packages to be installed, updated, configured
274  * and removed to the transaction dictionary.
275  */
276  if ((rv = compute_transaction_stats(xhp)) != 0) {
277  prop_object_release(xhp->transd);
278  xhp->transd = NULL;
279  return rv;
280  }
281  /*
282  * The missing deps and conflicts arrays are not necessary anymore.
283  */
284  prop_dictionary_remove(xhp->transd, "missing_deps");
285  prop_dictionary_remove(xhp->transd, "conflicts");
286  prop_dictionary_make_immutable(xhp->transd);
287 
288  return 0;
289 }