Line data Source code
1 : /*-
2 : * Copyright (c) 2011-2013 Baptiste Daroussin <bapt@FreeBSD.org>
3 : * Copyright (c) 2011-2012 Julien Laffaye <jlaffaye@FreeBSD.org>
4 : * Copyright (c) 2011-2012 Marin Atanasov Nikolov <dnaeon@gmail.com>
5 : * Copyright (c) 2012-2013 Matthew Seaman <matthew@FreeBSD.org>
6 : * Copyright (c) 2014 Vsevolod Stakhov <vsevolod@FreeBSD.org>
7 : *
8 : * All rights reserved.
9 : *
10 : * Redistribution and use in source and binary forms, with or without
11 : * modification, are permitted provided that the following conditions
12 : * are met:
13 : * 1. Redistributions of source code must retain the above copyright
14 : * notice, this list of conditions and the following disclaimer
15 : * in this position and unchanged.
16 : * 2. Redistributions in binary form must reproduce the above copyright
17 : * notice, this list of conditions and the following disclaimer in the
18 : * documentation and/or other materials provided with the distribution.
19 : *
20 : * THIS SOFTWARE IS PROVIDED BY THE AUTHOR(S) ``AS IS'' AND ANY EXPRESS OR
21 : * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
22 : * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
23 : * IN NO EVENT SHALL THE AUTHOR(S) BE LIABLE FOR ANY DIRECT, INDIRECT,
24 : * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
25 : * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
26 : * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
27 : * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
28 : * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
29 : * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
30 : */
31 :
32 : #include <sys/stat.h>
33 : #include <sys/param.h>
34 : #include <sys/mman.h>
35 :
36 : #define _WITH_GETLINE
37 : #include <stdio.h>
38 : #include <stdlib.h>
39 : #include <string.h>
40 : #include <unistd.h>
41 : #include <errno.h>
42 : #include <limits.h>
43 :
44 : #include <libgen.h>
45 :
46 : #include "pkg.h"
47 : #include "private/event.h"
48 : #include "private/utils.h"
49 : #include "private/pkgdb.h"
50 : #include "private/pkg.h"
51 : #include "binary.h"
52 :
53 : int
54 64 : pkg_repo_binary_get_cached_name(struct pkg_repo *repo, struct pkg *pkg,
55 : char *dest, size_t destlen)
56 : {
57 64 : const char *ext = NULL;
58 64 : const char *cachedir = NULL;
59 : const char *packagesite;
60 : struct stat st;
61 :
62 64 : cachedir = pkg_object_string(pkg_config_get("PKG_CACHEDIR"));
63 :
64 64 : packagesite = pkg_repo_url(repo);
65 :
66 64 : if (strncmp(packagesite, "file://", 7) == 0) {
67 64 : snprintf(dest, destlen, "%s/%s", packagesite + 7,
68 : pkg->repopath);
69 64 : return (EPKG_OK);
70 : }
71 :
72 0 : if (pkg->repopath != NULL)
73 0 : ext = strrchr(pkg->repopath, '.');
74 :
75 0 : if (ext != NULL) {
76 : /*
77 : * The real naming scheme:
78 : * <cachedir>/<name>-<version>-<checksum>.txz
79 : */
80 0 : pkg_snprintf(dest, destlen, "%S/%n-%v-%z%S",
81 : cachedir, pkg, pkg, pkg, ext);
82 0 : if (stat (dest, &st) == -1 || pkg->pkgsize != st.st_size)
83 0 : return (EPKG_FATAL);
84 :
85 : }
86 : else {
87 0 : pkg_snprintf(dest, destlen, "%S/%n-%v-%z",
88 : cachedir, pkg, pkg, pkg);
89 : }
90 :
91 0 : return (EPKG_OK);
92 : }
93 :
94 : static int
95 0 : pkg_repo_binary_create_symlink(struct pkg *pkg, const char *fname,
96 : const char *dir)
97 : {
98 : const char *ext, *dest_fname;
99 : char link_dest_tmp[MAXPATHLEN], link_dest[MAXPATHLEN];
100 :
101 : /* Create symlink from full pkgname */
102 0 : ext = strrchr(fname, '.');
103 0 : pkg_snprintf(link_dest, sizeof(link_dest), "%S/%n-%v%S",
104 : dir, pkg, pkg, ext ? ext : "");
105 0 : snprintf(link_dest_tmp, sizeof(link_dest_tmp), "%s.new", link_dest);
106 :
107 : /* Ignore errors here */
108 0 : (void)unlink(link_dest_tmp);
109 :
110 : /* Trim the path to just the filename. */
111 0 : if ((dest_fname = strrchr(fname, '/')) != NULL)
112 0 : ++dest_fname;
113 0 : if (symlink(dest_fname, link_dest_tmp) == -1) {
114 0 : pkg_emit_errno("symlink", link_dest);
115 0 : return (EPKG_FATAL);
116 : }
117 :
118 0 : if (rename(link_dest_tmp, link_dest) == -1) {
119 0 : pkg_emit_errno("rename", link_dest);
120 0 : unlink(link_dest_tmp);
121 0 : return (EPKG_FATAL);
122 : }
123 :
124 0 : return (EPKG_OK);
125 : }
126 :
127 : static int
128 0 : pkg_repo_binary_try_fetch(struct pkg_repo *repo, struct pkg *pkg,
129 : bool already_tried, bool mirror, const char *destdir)
130 : {
131 : char dest[MAXPATHLEN];
132 : char url[MAXPATHLEN];
133 0 : char *dir = NULL;
134 0 : bool fetched = false;
135 : struct stat st;
136 0 : char *path = NULL;
137 0 : const char *packagesite = NULL;
138 0 : ssize_t offset = -1;
139 :
140 0 : int retcode = EPKG_OK;
141 :
142 0 : assert((pkg->type & PKG_REMOTE) == PKG_REMOTE);
143 :
144 0 : if (mirror) {
145 : const char *cachedir;
146 :
147 0 : if (destdir != NULL)
148 0 : cachedir = destdir;
149 : else
150 0 : cachedir = pkg_object_string(pkg_config_get("PKG_CACHEDIR"));
151 :
152 0 : snprintf(dest, sizeof(dest), "%s/%s", cachedir, pkg->repopath);
153 : }
154 : else
155 0 : pkg_repo_binary_get_cached_name(repo, pkg, dest, sizeof(dest));
156 :
157 : /* If it is already in the local cachedir, dont bother to
158 : * download it */
159 0 : if (stat(dest, &st) == 0) {
160 : /* try to resume */
161 0 : if (pkg->pkgsize > st.st_size) {
162 0 : offset = st.st_size;
163 0 : pkg_debug(1, "Resuming fetch");
164 : } else {
165 0 : goto checksum;
166 : }
167 : }
168 :
169 : /* Create the dirs in cachedir */
170 0 : dir = strdup(dest);
171 0 : if (dir == NULL || (path = dirname(dir)) == NULL) {
172 0 : pkg_emit_errno("dirname", dest);
173 0 : retcode = EPKG_FATAL;
174 0 : goto cleanup;
175 : }
176 :
177 0 : if ((retcode = mkdirs(path)) != EPKG_OK)
178 0 : goto cleanup;
179 :
180 : /*
181 : * In multi-repos the remote URL is stored in pkg[PKG_REPOURL]
182 : * For a single attached database the repository URL should be
183 : * defined by URL.
184 : */
185 0 : packagesite = pkg_repo_url(repo);
186 :
187 0 : if (packagesite == NULL || packagesite[0] == '\0') {
188 0 : pkg_emit_error("URL is not defined");
189 0 : retcode = 1;
190 0 : goto cleanup;
191 : }
192 :
193 0 : if (packagesite[strlen(packagesite) - 1] == '/')
194 0 : pkg_snprintf(url, sizeof(url), "%S%R", packagesite, pkg);
195 : else
196 0 : pkg_snprintf(url, sizeof(url), "%S/%R", packagesite, pkg);
197 :
198 0 : if (!mirror && strncasecmp(packagesite, "file://", 7) == 0) {
199 0 : free(dir);
200 0 : return (EPKG_OK);
201 : }
202 :
203 0 : retcode = pkg_fetch_file(repo, url, dest, 0, offset, pkg->pkgsize);
204 0 : fetched = true;
205 :
206 0 : if (retcode != EPKG_OK)
207 0 : goto cleanup;
208 :
209 : checksum:
210 : /* checksum calculation is expensive, if size does not
211 : match, skip it and assume failed checksum. */
212 0 : if (stat(dest, &st) == -1 || pkg->pkgsize != st.st_size) {
213 0 : if (already_tried) {
214 0 : pkg_emit_error("cached package %s-%s: "
215 : "size mismatch, cannot continue",
216 : pkg->name, pkg->version);
217 0 : retcode = EPKG_FATAL;
218 0 : goto cleanup;
219 : }
220 :
221 0 : unlink(dest);
222 0 : free(dir);
223 0 : pkg_emit_error("cached package %s-%s: "
224 : "size mismatch, fetching from remote",
225 : pkg->name, pkg->version);
226 0 : return (pkg_repo_binary_try_fetch(repo, pkg, true, mirror, destdir));
227 : }
228 0 : if (!pkg_checksum_validate_file(dest, pkg->sum)) {
229 0 : if (already_tried || fetched) {
230 0 : pkg_emit_error("%s-%s failed checksum "
231 : "from repository", pkg->name, pkg->version);
232 0 : retcode = EPKG_FATAL;
233 : } else {
234 0 : pkg_emit_error("cached package %s-%s: "
235 : "checksum mismatch, fetching from remote",
236 : pkg->name, pkg->version);
237 0 : unlink(dest);
238 0 : return (pkg_repo_binary_try_fetch(repo, pkg, true, mirror, destdir));
239 : }
240 : }
241 :
242 : cleanup:
243 :
244 0 : if (retcode != EPKG_OK)
245 0 : unlink(dest);
246 0 : else if (!mirror && path != NULL) {
247 0 : (void)pkg_repo_binary_create_symlink(pkg, dest, path);
248 : }
249 :
250 : /* allowed even if dir is NULL */
251 0 : free(dir);
252 :
253 0 : return (retcode);
254 : }
255 :
256 : int
257 0 : pkg_repo_binary_fetch(struct pkg_repo *repo, struct pkg *pkg)
258 : {
259 0 : return (pkg_repo_binary_try_fetch(repo, pkg, false, false, NULL));
260 : }
261 :
262 : int
263 0 : pkg_repo_binary_mirror(struct pkg_repo *repo, struct pkg *pkg,
264 : const char *destdir)
265 : {
266 0 : return (pkg_repo_binary_try_fetch(repo, pkg, false, true, destdir));
267 : }
|