XBPS Library API  0.19
The X Binary Package System
util.c
1 /*-
2  * Copyright (c) 2008-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 #ifdef HAVE_VASPRINTF
27 # define _GNU_SOURCE /* for vasprintf(3) */
28 #endif
29 
30 #include <stdio.h>
31 #include <stdbool.h>
32 #include <stdlib.h>
33 #include <stdarg.h>
34 #include <string.h>
35 #include <errno.h>
36 #include <fnmatch.h>
37 #include <sys/utsname.h>
38 
39 #ifdef HAVE_CONFIG_H
40 #include "config.h"
41 #endif
42 #include "xbps_api_impl.h"
43 
44 /**
45  * @file lib/util.c
46  * @brief Utility routines
47  * @defgroup util Utility functions
48  */
49 bool
50 xbps_repository_is_remote(const char *uri)
51 {
52  assert(uri != NULL);
53 
54  if ((strncmp(uri, "https://", 8) == 0) ||
55  (strncmp(uri, "http://", 7) == 0) ||
56  (strncmp(uri, "ftp://", 6) == 0))
57  return true;
58 
59  return false;
60 }
61 
62 int
63 xbps_pkg_is_installed(struct xbps_handle *xhp, const char *pkg)
64 {
65  prop_dictionary_t dict;
66  pkg_state_t state;
67 
68  assert(xhp);
69  assert(pkg);
70 
71  if (((dict = xbps_pkgdb_get_virtualpkg(xhp, pkg)) == NULL) &&
72  ((dict = xbps_pkgdb_get_pkg(xhp, pkg)) == NULL))
73  return 0; /* not installed */
74  /*
75  * Check that package state is fully installed, not
76  * unpacked or something else.
77  */
78  if (xbps_pkg_state_dictionary(dict, &state) != 0)
79  return -1; /* error */
80  if (state != XBPS_PKG_STATE_INSTALLED)
81  return 0; /* not fully installed */
82 
83  return 1;
84 }
85 
86 const char *
87 xbps_pkg_version(const char *pkg)
88 {
89  const char *p;
90 
91  if ((p = strrchr(pkg, '-')) == NULL)
92  return NULL;
93 
94  if (strrchr(p, '_') == NULL)
95  return NULL;
96 
97  return p + 1; /* skip first '_' */
98 }
99 
100 const char *
101 xbps_pkg_revision(const char *pkg)
102 {
103  const char *p;
104 
105  assert(pkg != NULL);
106 
107  /* Get the required revision */
108  if ((p = strrchr(pkg, '_')) == NULL)
109  return NULL;
110 
111  return p + 1; /* skip first '_' */
112 }
113 
114 char *
115 xbps_pkg_name(const char *pkg)
116 {
117  const char *p;
118  char *buf;
119  size_t len;
120 
121  if ((p = strrchr(pkg, '-')) == NULL)
122  return NULL;
123 
124  if (strrchr(p, '_') == NULL)
125  return NULL;
126 
127  len = strlen(pkg) - strlen(p) + 1;
128  buf = malloc(len);
129  assert(buf != NULL);
130 
131  memcpy(buf, pkg, len-1);
132  buf[len-1] = '\0';
133 
134  return buf;
135 }
136 
137 char *
138 xbps_pkgpattern_name(const char *pkg)
139 {
140  char *res, *pkgname;
141  size_t len;
142 
143  assert(pkg != NULL);
144 
145  if ((res = strpbrk(pkg, "><*?[]")) == NULL)
146  return NULL;
147 
148  len = strlen(pkg) - strlen(res) + 1;
149  if (pkg[len-2] == '-')
150  len--;
151 
152  pkgname = malloc(len);
153  assert(pkgname != NULL);
154 
155  memcpy(pkgname, pkg, len-1);
156  pkgname[len-1] = '\0';
157 
158  return pkgname;
159 }
160 
161 const char *
162 xbps_pkgpattern_version(const char *pkg)
163 {
164  assert(pkg != NULL);
165 
166  return strpbrk(pkg, "><*?[]");
167 }
168 
169 static char *
170 get_pkg_index_remote_plist(struct xbps_handle *xhp,
171  const char *uri,
172  const char *plistf)
173 {
174  char *uri_fixed, *repodir;
175 
176  assert(uri != NULL);
177 
178  uri_fixed = xbps_get_remote_repo_string(uri);
179  if (uri_fixed == NULL)
180  return NULL;
181 
182  repodir = xbps_xasprintf("%s/%s/%s-%s", xhp->metadir,
183  uri_fixed, xhp->un_machine, plistf);
184  free(uri_fixed);
185  return repodir;
186 }
187 
188 char *
189 xbps_pkg_index_plist(struct xbps_handle *xhp, const char *uri)
190 {
191  assert(xhp);
192  assert(uri != NULL);
193 
194  if (xbps_repository_is_remote(uri))
195  return get_pkg_index_remote_plist(xhp, uri, XBPS_PKGINDEX);
196 
197  return xbps_xasprintf("%s/%s-%s", uri, xhp->un_machine, XBPS_PKGINDEX);
198 }
199 
200 char *
201 xbps_pkg_index_files_plist(struct xbps_handle *xhp, const char *uri)
202 {
203  assert(xhp);
204  assert(uri != NULL);
205 
206  if (xbps_repository_is_remote(uri))
207  return get_pkg_index_remote_plist(xhp, uri, XBPS_PKGINDEX_FILES);
208 
209  return xbps_xasprintf("%s/%s-%s", uri,
210  xhp->un_machine, XBPS_PKGINDEX_FILES);
211 }
212 
213 char HIDDEN *
214 xbps_repository_pkg_path(struct xbps_handle *xhp, prop_dictionary_t pkg_repod)
215 {
216  const char *filen, *repoloc;
217  char *lbinpkg = NULL;
218 
219  assert(xhp);
220  assert(prop_object_type(pkg_repod) == PROP_TYPE_DICTIONARY);
221 
222  if (!prop_dictionary_get_cstring_nocopy(pkg_repod,
223  "filename", &filen))
224  return NULL;
225  if (!prop_dictionary_get_cstring_nocopy(pkg_repod,
226  "repository", &repoloc))
227  return NULL;
228 
229  if (xbps_repository_is_remote(repoloc)) {
230  /*
231  * First check if binpkg is available in cachedir.
232  */
233  lbinpkg = xbps_xasprintf("%s/%s", xhp->cachedir, filen);
234  if (access(lbinpkg, R_OK) == 0)
235  return lbinpkg;
236 
237  free(lbinpkg);
238  }
239  /*
240  * Local and remote repositories use the same path.
241  */
242  return xbps_xasprintf("%s/%s", repoloc, filen);
243 }
244 
245 bool
246 xbps_pkg_has_rundeps(prop_dictionary_t pkgd)
247 {
248  prop_array_t array;
249 
250  assert(prop_object_type(pkgd) == PROP_TYPE_DICTIONARY);
251 
252  array = prop_dictionary_get(pkgd, "run_depends");
253  if ((prop_object_type(array) == PROP_TYPE_ARRAY) &&
254  prop_array_count(array) > 0)
255  return true;
256 
257  return false;
258 }
259 
260 bool
262  const char *orig,
263  const char *target)
264 {
265  if (target == NULL) {
266  if ((strcmp(orig, "noarch") == 0) ||
267  (strcmp(orig, xhp->un_machine) == 0))
268  return true;
269  } else {
270  if ((strcmp(orig, "noarch") == 0) ||
271  (strcmp(orig, target) == 0))
272  return true;
273  }
274  return false;
275 }
276 
277 char *
278 xbps_xasprintf(const char *fmt, ...)
279 {
280  va_list ap;
281  char *buf = NULL;
282 
283  va_start(ap, fmt);
284  if (vasprintf(&buf, fmt, ap) == -1) {
285  va_end(ap);
286  assert(buf);
287  }
288  va_end(ap);
289  assert(buf);
290 
291  return buf;
292 }
293 
294 /*
295  * Match pkg against pattern, return 1 if matching, 0 otherwise or -1 on error.
296  */
297 int
298 xbps_pkgpattern_match(const char *pkg, const char *pattern)
299 {
300  /* simple match on "pkg" against "pattern" */
301  if (strcmp(pattern, pkg) == 0)
302  return 1;
303 
304  /* perform relational dewey match on version number */
305  if (strpbrk(pattern, "<>") != NULL)
306  return dewey_match(pattern, pkg);
307 
308  /* glob match */
309  if (strpbrk(pattern, "*?[]") != NULL)
310  if (fnmatch(pattern, pkg, FNM_PERIOD) == 0)
311  return 1;
312 
313  /* no match */
314  return 0;
315 }
316 
317 /*
318  * Small wrapper for NetBSD's humanize_number(3) with some
319  * defaults set that we care about.
320  */
321 int
322 xbps_humanize_number(char *buf, int64_t bytes)
323 {
324  assert(buf != NULL);
325 
326  return humanize_number(buf, 7, bytes, "B",
327  HN_AUTOSCALE, HN_DECIMAL|HN_NOSPACE);
328 }