etc/protocols - sync with NetBSD-8
[minix.git] / external / bsd / pkg_install / dist / lib / pkg_io.c
blob3639e764cc0828e489861de61dfcb666cef2326a
1 /* $NetBSD: pkg_io.c,v 1.1.1.9 2010/04/23 20:54:11 joerg Exp $ */
2 /*-
3 * Copyright (c) 2008, 2009 Joerg Sonnenberger <joerg@NetBSD.org>.
4 * All rights reserved.
6 * Redistribution and use in source and binary forms, with or without
7 * modification, are permitted provided that the following conditions
8 * are met:
10 * 1. Redistributions of source code must retain the above copyright
11 * notice, this list of conditions and the following disclaimer.
12 * 2. Redistributions in binary form must reproduce the above copyright
13 * notice, this list of conditions and the following disclaimer in
14 * the documentation and/or other materials provided with the
15 * distribution.
17 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
18 * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
19 * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS
20 * FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE
21 * COPYRIGHT HOLDERS OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT,
22 * INCIDENTAL, SPECIAL, EXEMPLARY OR CONSEQUENTIAL DAMAGES (INCLUDING,
23 * BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
24 * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED
25 * AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
26 * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT
27 * OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
28 * SUCH DAMAGE.
31 #if HAVE_CONFIG_H
32 #include "config.h"
33 #endif
34 #include <nbcompat.h>
35 #if HAVE_SYS_CDEFS_H
36 #include <sys/cdefs.h>
37 #endif
39 __RCSID("$NetBSD: pkg_io.c,v 1.1.1.9 2010/04/23 20:54:11 joerg Exp $");
41 #include <archive.h>
42 #include <archive_entry.h>
43 #if HAVE_ERR_H
44 #include <err.h>
45 #endif
46 #if HAVE_ERRNO_H
47 #include <errno.h>
48 #endif
49 #include <fetch.h>
50 #include <stdlib.h>
52 #include "lib.h"
54 struct pkg_path {
55 TAILQ_ENTRY(pkg_path) pl_link;
56 char *pl_path;
59 static char *orig_cwd, *last_toplevel;
60 static TAILQ_HEAD(, pkg_path) pkg_path = TAILQ_HEAD_INITIALIZER(pkg_path);
62 struct fetch_archive {
63 struct url *url;
64 fetchIO *fetch;
65 char buffer[32768];
66 off_t size;
67 int restart;
70 static int
71 fetch_archive_open(struct archive *a, void *client_data)
73 struct fetch_archive *f = client_data;
74 struct url_stat us;
76 f->fetch = fetchXGet(f->url, &us, fetch_flags);
77 if (f->fetch == NULL)
78 return ENOENT;
79 f->size = us.size;
80 f->restart = 1;
81 f->url->offset = 0;
82 return 0;
85 static ssize_t
86 fetch_archive_read(struct archive *a, void *client_data,
87 const void **buffer)
89 struct fetch_archive *f = client_data;
90 struct url_stat us;
91 ssize_t rv;
93 *buffer = f->buffer;
94 rv = fetchIO_read(f->fetch, f->buffer, sizeof(f->buffer));
95 if (rv > 0) {
96 f->url->offset += rv;
97 return rv;
99 if (f->restart == 0)
100 return rv;
101 if (rv == 0) {
102 if (f->size == -1)
103 return 0;
104 if (f->url->offset == f->size)
105 return 0;
107 f->restart = 0;
108 if (1) {
109 char *url = fetchStringifyURL(f->url);
110 fprintf(stderr, "Trying to reconnect %s\n", url);
111 free(url);
113 fetchIO_close(f->fetch);
114 f->fetch = fetchXGet(f->url, &us, fetch_flags);
115 if (f->fetch == NULL)
116 return -1;
117 if (us.size != f->size)
118 return -1;
119 rv = fetchIO_read(f->fetch, f->buffer, sizeof(f->buffer));
120 if (rv > 0)
121 f->url->offset += rv;
122 return rv;
125 static int
126 fetch_archive_close(struct archive *a, void *client_data)
128 struct fetch_archive *f = client_data;
130 if (f->fetch != NULL)
131 fetchIO_close(f->fetch);
132 fetchFreeURL(f->url);
133 free(f);
134 return 0;
137 static struct archive *
138 open_archive_by_url(struct url *url, char **archive_name)
140 struct fetch_archive *f;
141 struct archive *a;
143 f = xmalloc(sizeof(*f));
144 f->url = fetchCopyURL(url);
146 *archive_name = fetchStringifyURL(url);
148 a = archive_read_new();
149 archive_read_support_compression_all(a);
150 archive_read_support_format_all(a);
151 if (archive_read_open(a, f, fetch_archive_open, fetch_archive_read,
152 fetch_archive_close)) {
153 free(*archive_name);
154 *archive_name = NULL;
155 archive_read_finish(a);
156 return NULL;
159 return a;
162 struct archive *
163 open_archive(const char *url, char **archive_name)
165 struct url *u;
166 struct archive *a;
168 *archive_name = NULL;
170 if (!IS_URL(url)) {
171 a = archive_read_new();
172 archive_read_support_compression_all(a);
173 archive_read_support_format_all(a);
174 if (archive_read_open_filename(a, url, 1024)) {
175 archive_read_close(a);
176 return NULL;
178 *archive_name = xstrdup(url);
179 return a;
182 if ((u = fetchParseURL(url)) == NULL)
183 return NULL;
185 a = open_archive_by_url(u, archive_name);
187 fetchFreeURL(u);
188 return a;
191 static int
192 strip_suffix(char *filename)
194 size_t len;
196 len = strlen(filename);
197 if (len <= 4)
198 return 0;
199 if (strcmp(filename + len - 4, ".tgz") == 0 ||
200 strcmp(filename + len - 4, ".tbz") == 0) {
201 filename[len - 4] = '\0';
202 return 1;
203 } else
204 return 0;
207 static int
208 find_best_package_int(struct url *url, const char *pattern,
209 struct url **best_url)
211 char *cur_match, *url_pattern, *best_match = NULL;
212 struct url_list ue;
213 size_t i;
215 if (*best_url) {
216 if ((best_match = fetchUnquoteFilename(*best_url)) == NULL)
217 return -1;
218 } else
219 best_match = NULL;
221 if (best_match && strip_suffix(best_match) == 0) {
222 free(best_match);
223 return -1;
226 for (i = 0; pattern[i] != '\0'; ++i) {
227 if (!isalnum((unsigned char)(pattern[i])) &&
228 (pattern[i]) != '-')
229 break;
231 url_pattern = xasprintf("%*.*s*", (int)i, (int)i, pattern);
233 fetchInitURLList(&ue);
234 if (fetchList(&ue, url, url_pattern, fetch_flags)) {
235 char *base_url;
236 base_url = fetchStringifyURL(url);
237 warnx("Can't process %s/%s: %s", base_url, url_pattern,
238 fetchLastErrString);
239 free(base_url);
240 free(url_pattern);
241 fetchFreeURLList(&ue);
242 return -1;
244 free(url_pattern);
246 for (i = 0; i < ue.length; ++i) {
247 cur_match = fetchUnquoteFilename(ue.urls + i);
249 if (cur_match == NULL) {
250 free(best_match);
251 fetchFreeURLList(&ue);
252 return -1;
254 if (strip_suffix(cur_match) == 0) {
255 free(cur_match);
256 continue;
258 if (pkg_order(pattern, cur_match, best_match) == 1) {
259 if (*best_url)
260 fetchFreeURL(*best_url);
261 *best_url = fetchCopyURL(ue.urls + i);
262 free(best_match);
263 best_match = cur_match;
264 cur_match = NULL;
265 if (*best_url == NULL) {
266 free(best_match);
267 return -1;
270 free(cur_match);
272 free(best_match);
273 fetchFreeURLList(&ue);
274 return 0;
277 void
278 process_pkg_path(void)
280 char cwd[PATH_MAX];
281 int relative_path;
282 struct pkg_path *pl;
283 const char *start, *next;
284 size_t len;
286 if (getcwd(cwd, sizeof(cwd)) == NULL)
287 errx(EXIT_FAILURE, "getcwd failed");
289 orig_cwd = xstrdup(cwd);
291 if (config_pkg_path == NULL)
292 return;
294 for (start = config_pkg_path; *start; start = next) {
295 len = strcspn(start, ";");
296 if (*(next = start + len) != '\0')
297 ++next;
299 relative_path = !IS_FULLPATH(start) && !IS_URL(start);
300 pl = xmalloc(sizeof(*pl));
301 pl->pl_path = xasprintf("%s%s%*.*s",
302 relative_path ? cwd : "", len && relative_path ? "/" : "",
303 (int)len, (int)len, start);
304 TAILQ_INSERT_TAIL(&pkg_path, pl, pl_link);
308 struct url *
309 find_best_package(const char *toplevel, const char *pattern, int do_path)
311 struct url *url, *best_match = NULL;
312 struct pkg_path *pl;
314 if (toplevel) {
315 url = fetchParseURL(last_toplevel);
316 if (url != NULL) {
317 find_best_package_int(url, pattern, &best_match);
318 /* XXX Check return value and complain */
319 fetchFreeURL(url);
322 if (!do_path)
323 return best_match;
325 TAILQ_FOREACH(pl, &pkg_path, pl_link) {
326 url = fetchParseURL(pl->pl_path);
327 if (url != NULL) {
328 find_best_package_int(url, pattern, &best_match);
329 /* XXX Check return value and complain */
330 fetchFreeURL(url);
334 return best_match;
337 struct archive *
338 find_archive(const char *fname, int top_level, char **archive_name)
340 struct archive *a;
341 struct url *best_match;
342 char *full_fname, *last_slash;
343 int search_path;
345 search_path = 0;
346 if (IS_FULLPATH(fname) || IS_URL(fname)) {
347 full_fname = xstrdup(fname);
348 } else {
349 if (strchr(fname, '/') == NULL)
350 search_path = 1;
351 full_fname = xasprintf("%s/%s", orig_cwd, fname);
354 last_slash = strrchr(full_fname, '/');
355 if (top_level) {
356 free(last_toplevel);
357 *last_slash = '\0';
358 last_toplevel = xstrdup(full_fname);
359 *last_slash = '/';
362 a = open_archive(full_fname, archive_name);
363 if (a != NULL) {
364 free(full_fname);
365 return a;
368 fname = last_slash + 1;
369 *last_slash = '\0';
371 best_match = find_best_package(full_fname, fname, 0);
373 if (search_path && best_match == NULL)
374 best_match = find_best_package(last_toplevel, fname, 1);
376 free(full_fname);
378 if (best_match == NULL)
379 return NULL;
380 a = open_archive_by_url(best_match, archive_name);
381 fetchFreeURL(best_match);
382 return a;