Branch data Line data Source code
1 : : /*-
2 : : * Copyright (c) 2011-2020 Baptiste Daroussin <bapt@FreeBSD.org>
3 : : * Copyright (c) 2011-2012 Julien Laffaye <jlaffaye@FreeBSD.org>
4 : : * Copyright (c) 2014-2015 Matthew Seaman <matthew@FreeBSD.org>
5 : : * Copyright (c) 2014 Vsevolod Stakhov <vsevolod@FreeBSD.org>
6 : : * Copyright (c) 2023 Serenity Cyber Security, LLC
7 : : * Author: Gleb Popov <arrowd@FreeBSD.org>
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 : :
34 : : #include <errno.h>
35 : : #include <regex.h>
36 : : #include <fcntl.h>
37 : :
38 : : #include <bsd_compat.h>
39 : :
40 : : #include "pkg.h"
41 : : #include "private/event.h"
42 : : #include "private/pkg.h"
43 : : #include "private/pkg_abi.h"
44 : : #include "xmalloc.h"
45 : :
46 : : #define TICK 100
47 : :
48 : : static int load_metadata(struct pkg *pkg, const char *metadata, const char *plist,
49 : : const char *rootdir);
50 : : static void fixup_abi(struct pkg *pkg, const char *rootdir, bool testing);
51 : : static void counter_init(const char *what, int64_t max);
52 : : static void counter_count(void);
53 : : static void counter_end(void);
54 : :
55 : : extern struct pkg_ctx ctx;
56 : :
57 : : static int
58 : 264 : pkg_create_from_dir(struct pkg *pkg, const char *root,
59 : : struct pkg_create *pc, struct packing *pkg_archive)
60 : : {
61 : : char fpath[MAXPATHLEN];
62 : 264 : struct pkg_file *file = NULL;
63 : 264 : struct pkg_dir *dir = NULL;
64 : : int ret;
65 : : struct stat st;
66 : 264 : int64_t flatsize = 0;
67 : : int64_t nfiles;
68 : : const char *relocation;
69 : : char *manifest;
70 : : ucl_object_t *obj;
71 : : hardlinks_t hardlinks;
72 : :
73 : 264 : pkgvec_init(&hardlinks);
74 [ - + ]: 264 : if (pkg_is_valid(pkg) != EPKG_OK) {
75 : 0 : pkg_emit_error("the package is not valid");
76 : 0 : return (EPKG_FATAL);
77 : : }
78 : :
79 : 264 : relocation = pkg_kv_get(&pkg->annotations, "relocated");
80 [ - + ]: 264 : if (relocation == NULL)
81 : 264 : relocation = "";
82 [ + - ]: 264 : if (ctx.pkg_rootdir != NULL)
83 : 0 : relocation = ctx.pkg_rootdir;
84 : :
85 : : /*
86 : : * Get / compute size / checksum if not provided in the manifest
87 : : */
88 : :
89 : 264 : nfiles = pkghash_count(pkg->filehash);
90 : 264 : counter_init("file sizes/checksums", nfiles);
91 : :
92 [ + + ]: 477 : while (pkg_files(pkg, &file) == EPKG_OK) {
93 : :
94 [ + + ]: 214 : snprintf(fpath, sizeof(fpath), "%s%s%s", root ? root : "",
95 : 214 : relocation, file->path);
96 : :
97 [ - + ]: 214 : if (lstat(fpath, &st) == -1) {
98 : 0 : pkg_emit_error("file '%s' is missing", fpath);
99 [ # # ]: 0 : pkgvec_free_and_free(&hardlinks, free);
100 : 0 : return (EPKG_FATAL);
101 : : }
102 : :
103 [ + + + + ]: 214 : if (!(S_ISREG(st.st_mode) || S_ISLNK(st.st_mode))) {
104 : 1 : pkg_emit_error("file '%s' is not a regular file or symlink", fpath);
105 [ - + ]: 1 : pkgvec_free_and_free(&hardlinks, free);
106 : 1 : return (EPKG_FATAL);
107 : : }
108 : :
109 [ - + ]: 213 : if (file->size == 0)
110 : 213 : file->size = (int64_t)st.st_size;
111 : :
112 [ + + + + ]: 213 : if (st.st_nlink == 1 || !check_for_hardlink(&hardlinks, &st)) {
113 : 208 : flatsize += file->size;
114 : 208 : }
115 : :
116 : 213 : free(file->sum);
117 : 213 : file->sum = pkg_checksum_generate_file(fpath,
118 : : PKG_HASH_TYPE_SHA256_HEX);
119 [ + - ]: 213 : if (file->sum == NULL) {
120 [ # # ]: 0 : pkgvec_free_and_free(&hardlinks, free);
121 : 0 : return (EPKG_FATAL);
122 : : }
123 : :
124 : 213 : counter_count();
125 : : }
126 [ + + ]: 268 : pkgvec_free_and_free(&hardlinks, free);
127 : :
128 : 263 : counter_end();
129 : :
130 : 263 : pkg->flatsize = flatsize;
131 : :
132 [ - + ]: 263 : if (pkg->type == PKG_OLD_FILE) {
133 : 0 : pkg_emit_error("Cannot create an old format package");
134 : 0 : return (EPKG_FATAL);
135 : : }
136 : :
137 : 263 : obj = pkg_emit_object(pkg, PKG_MANIFEST_EMIT_COMPACT);
138 : 263 : manifest = ucl_object_emit(obj, UCL_EMIT_JSON_COMPACT);
139 : 263 : ucl_object_unref(obj);
140 : 263 : packing_append_buffer(pkg_archive, manifest, "+COMPACT_MANIFEST", strlen(manifest));
141 : 263 : free(manifest);
142 : 263 : obj = pkg_emit_object(pkg, 0);
143 [ - + ]: 263 : if (pc->expand_manifest) {
144 : 0 : manifest = ucl_object_emit(obj, UCL_EMIT_CONFIG);
145 : 0 : } else {
146 : 263 : manifest = ucl_object_emit(obj, UCL_EMIT_JSON_COMPACT);
147 : : }
148 : 263 : ucl_object_unref(obj);
149 : 263 : packing_append_buffer(pkg_archive, manifest, "+MANIFEST", strlen(manifest));
150 : 263 : free(manifest);
151 : :
152 : 263 : counter_init("packing files", nfiles);
153 : :
154 [ + + ]: 475 : while (pkg_files(pkg, &file) == EPKG_OK) {
155 : : char dpath[MAXPATHLEN];
156 : 212 : const char *dp = file->path;
157 : :
158 [ + + ]: 212 : if (pkg->oprefix != NULL) {
159 : 2 : size_t l = strlen(pkg->prefix);
160 [ - + + - ]: 4 : if (strncmp(file->path, pkg->prefix, l) == 0 &&
161 [ + - ]: 2 : (file->path[l] == '/' || l == 1)) {
162 : 4 : snprintf(dpath, sizeof(dpath), "%s%s%s",
163 : 2 : pkg->oprefix, l == 1 ? "/" : "", file->path + l);
164 : 2 : dp = dpath;
165 : 2 : }
166 : 2 : }
167 : :
168 [ + + ]: 212 : snprintf(fpath, sizeof(fpath), "%s%s%s", root ? root : "",
169 : 212 : relocation, file->path);
170 : :
171 : 424 : ret = packing_append_file_attr(pkg_archive, fpath, dp,
172 : 212 : file->uname, file->gname, file->perm, file->fflags);
173 [ - + # # ]: 212 : if (ctx.developer_mode && ret != EPKG_OK)
174 : 0 : return (ret);
175 : 212 : counter_count();
176 : : }
177 : :
178 : 263 : counter_end();
179 : :
180 : 263 : nfiles = pkghash_count(pkg->dirhash);
181 : 263 : counter_init("packing directories", nfiles);
182 : :
183 [ + + ]: 271 : while (pkg_dirs(pkg, &dir) == EPKG_OK) {
184 [ + + ]: 8 : snprintf(fpath, sizeof(fpath), "%s%s%s", root ? root : "",
185 : 8 : relocation, dir->path);
186 : :
187 : 16 : ret = packing_append_file_attr(pkg_archive, fpath, dir->path,
188 : 8 : dir->uname, dir->gname, dir->perm, dir->fflags);
189 [ - + # # ]: 8 : if (ctx.developer_mode && ret != EPKG_OK)
190 : 0 : return (ret);
191 : 8 : counter_count();
192 : : }
193 : :
194 : 263 : counter_end();
195 : :
196 : 263 : return (EPKG_OK);
197 : 264 : }
198 : :
199 : : static struct packing *
200 : 265 : pkg_create_archive(struct pkg *pkg, struct pkg_create *pc, unsigned required_flags)
201 : : {
202 : 265 : char *pkg_path = NULL;
203 : 265 : struct packing *pkg_archive = NULL;
204 : :
205 : : /*
206 : : * Ensure that we have all the information we need
207 : : */
208 [ - + ]: 265 : if (pkg->type != PKG_OLD_FILE)
209 [ + - ]: 265 : assert((pkg->flags & required_flags) == required_flags);
210 : :
211 [ - + ]: 265 : if (pkg_mkdirs(pc->outdir) != EPKG_OK)
212 : 0 : return NULL;
213 : :
214 [ + - ]: 265 : if (pkg_asprintf(&pkg_path, "%S/%n-%v", pc->outdir, pkg, pkg) == -1) {
215 : 0 : pkg_emit_errno("pkg_asprintf", "");
216 : 0 : return (NULL);
217 : : }
218 : :
219 [ + + + + : 795 : if (packing_init(&pkg_archive, pkg_path, pc->format,
+ + ]
220 : 530 : pc->compression_level, pc->compression_threads, pc->timestamp, pc->overwrite, false) != EPKG_OK) {
221 : 1 : pkg_archive = NULL;
222 : 1 : }
223 : :
224 : 265 : free(pkg_path);
225 : :
226 : 265 : return pkg_archive;
227 : 265 : }
228 : :
229 : : static const char * const scripts[] = {
230 : : "+INSTALL",
231 : : "+PRE_INSTALL",
232 : : "+POST_INSTALL",
233 : : "+POST_INSTALL",
234 : : "+DEINSTALL",
235 : : "+PRE_DEINSTALL",
236 : : "+POST_DEINSTALL",
237 : : "pkg-install",
238 : : "pkg-pre-install",
239 : : "pkg-post-install",
240 : : "pkg-deinstall",
241 : : "pkg-pre-deinstall",
242 : : "pkg-post-deinstall",
243 : : NULL
244 : : };
245 : :
246 : : static const char * const lua_scripts[] = {
247 : : "pkg-pre-install.lua",
248 : : "pkg-post-install.lua",
249 : : "pkg-pre-deinstall.lua",
250 : : "pkg-post-deinstall.lua",
251 : : NULL
252 : : };
253 : :
254 : : struct pkg_create *
255 : 281 : pkg_create_new(void)
256 : : {
257 : : struct pkg_create *pc;
258 : :
259 : 281 : pc = xcalloc(1, sizeof(*pc));
260 : 281 : pc->format = packing_format_from_string(ctx.compression_format);
261 : 281 : pc->compression_level = ctx.compression_level;
262 : 281 : pc->compression_threads = ctx.compression_threads;
263 : 281 : pc->timestamp = (time_t) -1;
264 : 281 : pc->overwrite = true;
265 : 281 : pc->expand_manifest = false;
266 : :
267 : 281 : return (pc);
268 : : }
269 : :
270 : : void
271 : 281 : pkg_create_free(struct pkg_create *pc)
272 : : {
273 : 281 : free(pc);
274 : 281 : }
275 : :
276 : : bool
277 : 3 : pkg_create_set_format(struct pkg_create *pc, const char *format)
278 : : {
279 [ + - ]: 3 : if (STREQ(format, "tzst"))
280 : 0 : pc->format = TZS;
281 [ + + ]: 3 : else if (STREQ(format, "txz"))
282 : 2 : pc->format = TXZ;
283 [ + - ]: 1 : else if (STREQ(format, "tbz"))
284 : 0 : pc->format = TBZ;
285 [ + - ]: 1 : else if (STREQ(format, "tgz"))
286 : 0 : pc->format = TGZ;
287 [ - + ]: 1 : else if (STREQ(format, "tar"))
288 : 1 : pc->format = TAR;
289 : : else
290 : 0 : return (false);
291 : 3 : return (true);
292 : 3 : }
293 : :
294 : : void
295 : 0 : pkg_create_set_compression_level(struct pkg_create *pc, int clevel)
296 : : {
297 : 0 : pc->compression_level = clevel;
298 : 0 : }
299 : :
300 : : void
301 : 0 : pkg_create_set_compression_threads(struct pkg_create *pc, int threads)
302 : : {
303 : 0 : pc->compression_threads = threads;
304 : 0 : }
305 : :
306 : : void
307 : 281 : pkg_create_set_expand_manifest(struct pkg_create *pc, bool expand)
308 : : {
309 : 281 : pc->expand_manifest = expand;
310 : 281 : }
311 : :
312 : : void
313 : 281 : pkg_create_set_rootdir(struct pkg_create *pc, const char *rootdir)
314 : : {
315 : 281 : pc->rootdir = rootdir;
316 : 281 : }
317 : :
318 : : void
319 : 281 : pkg_create_set_output_dir(struct pkg_create *pc, const char *outdir)
320 : : {
321 : 281 : pc->outdir = outdir;
322 : 281 : }
323 : :
324 : : void
325 : 2 : pkg_create_set_timestamp(struct pkg_create *pc, time_t timestamp)
326 : : {
327 : 2 : pc->timestamp = timestamp;
328 : 2 : }
329 : :
330 : : void
331 : 281 : pkg_create_set_overwrite(struct pkg_create *pc, bool overwrite)
332 : : {
333 : 281 : pc->overwrite = overwrite;
334 : 281 : }
335 : :
336 : : static int
337 : 1 : hash_file(struct pkg *pkg)
338 : : {
339 : : char hash_dest[MAXPATHLEN];
340 : : char filename[MAXPATHLEN];
341 : :
342 : : /* Find the hash and rename the file and create a symlink */
343 : 2 : pkg_snprintf(filename, sizeof(filename), "%n-%v.pkg",
344 : 1 : pkg, pkg);
345 : 1 : pkg->sum = pkg_checksum_file(filename,
346 : : PKG_HASH_TYPE_SHA256_HEX);
347 : 2 : pkg_snprintf(hash_dest, sizeof(hash_dest), "%n-%v-%z.pkg",
348 : 1 : pkg, pkg, pkg);
349 : :
350 : 1 : pkg_debug(1, "Rename the pkg file from: %s to: %s",
351 : 1 : filename, hash_dest);
352 [ + - ]: 1 : if (rename(filename, hash_dest) == -1) {
353 : 0 : pkg_emit_errno("rename", hash_dest);
354 : 0 : unlink(hash_dest);
355 : 0 : return (EPKG_FATAL);
356 : : }
357 [ + - ]: 1 : if (symlink(hash_dest, filename) == -1) {
358 : 0 : pkg_emit_errno("symlink", hash_dest);
359 : 0 : return (EPKG_FATAL);
360 : : }
361 : 1 : return (EPKG_OK);
362 : 1 : }
363 : :
364 : : int
365 : 0 : pkg_create_i(struct pkg_create *pc, struct pkg *pkg, bool hash)
366 : : {
367 : 0 : struct packing *pkg_archive = NULL;
368 : : int ret;
369 : :
370 : 0 : unsigned required_flags = PKG_LOAD_DEPS | PKG_LOAD_FILES |
371 : : PKG_LOAD_CATEGORIES | PKG_LOAD_DIRS | PKG_LOAD_SCRIPTS |
372 : : PKG_LOAD_OPTIONS | PKG_LOAD_LICENSES | PKG_LOAD_LUA_SCRIPTS;
373 : :
374 [ # # # # ]: 0 : assert(pkg->type == PKG_INSTALLED || pkg->type == PKG_OLD_FILE);
375 : :
376 : 0 : pkg_archive = pkg_create_archive(pkg, pc, required_flags);
377 [ # # ]: 0 : if (pkg_archive == NULL) {
378 [ # # ]: 0 : if (errno == EEXIST)
379 : 0 : return (EPKG_EXIST);
380 : 0 : pkg_emit_error("unable to create archive");
381 : 0 : return (EPKG_FATAL);
382 : : }
383 : :
384 [ # # ]: 0 : if ((ret = pkg_create_from_dir(pkg, NULL, pc, pkg_archive)) != EPKG_OK) {
385 : 0 : pkg_emit_error("package creation failed");
386 : 0 : }
387 : 0 : packing_finish(pkg_archive);
388 : :
389 [ # # # # ]: 0 : if (hash && ret == EPKG_OK)
390 : 0 : ret = hash_file(pkg);
391 : :
392 : 0 : return (ret);
393 : 0 : }
394 : :
395 : : int
396 : 281 : pkg_create(struct pkg_create *pc, const char *metadata, const char *plist,
397 : : bool hash)
398 : : {
399 : 281 : struct pkg *pkg = NULL;
400 : 281 : struct packing *pkg_archive = NULL;
401 : 281 : int ret = ENOMEM;
402 : :
403 : 281 : pkg_debug(1, "Creating package");
404 [ - + ]: 281 : if (pkg_new(&pkg, PKG_FILE) != EPKG_OK) {
405 : 0 : return (EPKG_FATAL);
406 : : }
407 : :
408 [ + + ]: 281 : if (load_metadata(pkg, metadata, plist, pc->rootdir) != EPKG_OK) {
409 : 16 : pkg_free(pkg);
410 : 16 : return (EPKG_FATAL);
411 : : }
412 : 265 : fixup_abi(pkg, pc->rootdir, false);
413 : :
414 : 265 : pkg_archive = pkg_create_archive(pkg, pc, 0);
415 [ + + ]: 265 : if (pkg_archive == NULL) {
416 [ + - ]: 1 : if (errno == EEXIST) {
417 : 1 : pkg_emit_notice("%s-%s already packaged, skipping...\n",
418 : 1 : pkg->name, pkg->version);
419 : 1 : pkg_free(pkg);
420 : 1 : return (EPKG_EXIST);
421 : : }
422 : 0 : pkg_free(pkg);
423 : 0 : return (EPKG_FATAL);
424 : : }
425 : :
426 [ + + ]: 264 : if ((ret = pkg_create_from_dir(pkg, pc->rootdir, pc, pkg_archive)) != EPKG_OK)
427 : 1 : pkg_emit_error("package creation failed");
428 : :
429 : 264 : packing_finish(pkg_archive);
430 [ + + - + ]: 264 : if (hash && ret == EPKG_OK)
431 : 1 : ret = hash_file(pkg);
432 : :
433 : 264 : pkg_free(pkg);
434 : 264 : return (ret);
435 : 281 : }
436 : :
437 : : static int
438 : 36 : pkg_load_message_from_file(int fd, struct pkg *pkg, const char *path)
439 : : {
440 : 36 : char *buf = NULL;
441 : 36 : off_t size = 0;
442 : : int ret;
443 : : ucl_object_t *obj;
444 : :
445 [ + - ]: 36 : assert(pkg != NULL);
446 [ + - ]: 36 : assert(path != NULL);
447 : :
448 [ + + ]: 36 : if (faccessat(fd, path, F_OK, 0) == -1) {
449 : 31 : return (EPKG_FATAL);
450 : : }
451 : :
452 : 5 : pkg_debug(1, "Reading message: '%s'", path);
453 [ - + ]: 5 : if ((ret = file_to_bufferat(fd, path, &buf, &size)) != EPKG_OK) {
454 : 0 : return (ret);
455 : : }
456 : :
457 [ + + ]: 5 : if (*buf == '[') {
458 : 2 : ret = pkg_message_from_str(pkg, buf, size);
459 : 2 : free(buf);
460 : 2 : return (ret);
461 : : }
462 : 3 : obj = ucl_object_fromstring_common(buf, size,
463 : : UCL_STRING_RAW|UCL_STRING_TRIM);
464 : 3 : ret = pkg_message_from_ucl(pkg, obj);
465 : 3 : ucl_object_unref(obj);
466 : 3 : free(buf);
467 : :
468 : 3 : return (ret);
469 : 36 : }
470 : :
471 : : /* TODO use file descriptor for rootdir */
472 : : static int
473 : 322 : load_manifest(struct pkg *pkg, const char *metadata, const char *plist,
474 : : const char *rootdir)
475 : : {
476 : : int ret;
477 : :
478 : 322 : ret = pkg_parse_manifest_file(pkg, metadata);
479 : :
480 [ + + + + ]: 322 : if (ret == EPKG_OK && plist != NULL)
481 : 44 : ret = ports_parse_plist(pkg, plist, rootdir);
482 : 322 : return (ret);
483 : : }
484 : :
485 : : /* TODO use file descriptor for rootdir */
486 : : static int
487 : 359 : load_metadata(struct pkg *pkg, const char *metadata, const char *plist,
488 : : const char *rootdir)
489 : : {
490 : : regex_t preg;
491 : : regmatch_t pmatch[2];
492 : : size_t size;
493 : : int fd, i;
494 : :
495 : : /* Let's see if we have a directory or a manifest */
496 [ + + ]: 359 : if ((fd = open(metadata, O_DIRECTORY|O_CLOEXEC)) == -1) {
497 [ + - ]: 322 : if (errno == ENOTDIR)
498 : 322 : return (load_manifest(pkg, metadata, plist, rootdir));
499 : 0 : pkg_emit_errno("open", metadata);
500 : 0 : return (EPKG_FATAL);
501 : : }
502 : :
503 [ + + ]: 37 : if ((pkg_parse_manifest_fileat(fd, pkg, "+MANIFEST")) != EPKG_OK) {
504 : 1 : close(fd);
505 : 1 : return (EPKG_FATAL);
506 : : }
507 : :
508 : 36 : pkg_load_message_from_file(fd, pkg, "+DISPLAY");
509 [ + - ]: 36 : if (pkg->desc == NULL)
510 : 0 : pkg_set_from_fileat(fd, pkg, PKG_ATTR_DESC, "+DESC", false);
511 : :
512 [ + + ]: 504 : for (i = 0; scripts[i] != NULL; i++) {
513 [ + - ]: 468 : if (faccessat(fd, scripts[i], F_OK, 0) == 0)
514 : 0 : pkg_addscript_fileat(fd, pkg, scripts[i]);
515 : 468 : }
516 : :
517 [ + + ]: 180 : for (i = 0; lua_scripts[i] != NULL; i++) {
518 [ + - ]: 144 : if (faccessat(fd, lua_scripts[i], F_OK, 0) == 0)
519 : 0 : pkg_addluascript_fileat(fd, pkg, lua_scripts[i]);
520 : 144 : }
521 : :
522 [ + + + + ]: 36 : if (plist != NULL && ports_parse_plist(pkg, plist, rootdir) != EPKG_OK) {
523 : 13 : return (EPKG_FATAL);
524 : : }
525 : 23 : close(fd);
526 : :
527 [ + - ]: 23 : if (pkg->www == NULL) {
528 [ # # ]: 0 : if (pkg->desc == NULL) {
529 : 0 : pkg_emit_error("No www or desc defined in manifest");
530 : 0 : return (EPKG_FATAL);
531 : : }
532 : 0 : regcomp(&preg, "^WWW:[[:space:]]*(.*)$",
533 : : REG_EXTENDED|REG_ICASE|REG_NEWLINE);
534 [ # # ]: 0 : if (regexec(&preg, pkg->desc, 2, pmatch, 0) == 0) {
535 : 0 : size = pmatch[1].rm_eo - pmatch[1].rm_so;
536 : 0 : pkg->www = xstrndup(&pkg->desc[pmatch[1].rm_so], size);
537 : 0 : } else {
538 : 0 : pkg->www = xstrdup("UNKNOWN");
539 : : }
540 : 0 : regfree(&preg);
541 : 0 : }
542 : :
543 : 23 : return (EPKG_OK);
544 : 359 : }
545 : :
546 : : static void
547 : 342 : fixup_abi(struct pkg *pkg, const char *rootdir, bool testing)
548 : : {
549 : 342 : bool defaultarch = false;
550 : :
551 : : /* if no arch autodetermine it */
552 [ + + ]: 342 : if (pkg->abi == NULL) {
553 [ + + ]: 222 : if (ctx.abi.os == PKG_OS_FREEBSD) {
554 : : char *str_osversion;
555 : 211 : xasprintf(&str_osversion, "%d", pkg_abi_get_freebsd_osversion(&ctx.abi));
556 : 211 : pkg_kv_add(&pkg->annotations, "FreeBSD_version", str_osversion, "annotation");
557 : 211 : }
558 : 222 : pkg->abi = pkg_abi_to_string(&ctx.abi);
559 : 222 : defaultarch = true;
560 : 222 : }
561 : :
562 [ + + ]: 342 : if (!testing)
563 : 330 : pkg_analyse_files(NULL, pkg, rootdir);
564 : :
565 [ + - ]: 342 : if (ctx.developer_mode)
566 : 0 : suggest_arch(pkg, defaultarch);
567 : 342 : }
568 : :
569 : : int
570 : 78 : pkg_load_metadata(struct pkg *pkg, const char *mfile, const char *md_dir,
571 : : const char *plist, const char *rootdir, bool testing)
572 : : {
573 : : int ret;
574 : :
575 [ + + ]: 78 : ret = load_metadata(pkg, md_dir != NULL ? md_dir: mfile, plist, rootdir);
576 [ + + ]: 78 : if (ret != EPKG_OK)
577 : 1 : return (ret);
578 : :
579 : 77 : fixup_abi(pkg, rootdir, testing);
580 : 77 : return (ret);
581 : 78 : }
582 : :
583 : : static int64_t count;
584 : : static int64_t maxcount;
585 : : static const char *what;
586 : :
587 : 790 : static int magnitude(int64_t num)
588 : : {
589 : : int oom;
590 : :
591 [ + + ]: 790 : if (num == 0)
592 : 436 : return (1);
593 [ + - ]: 354 : if (num < 0)
594 : 0 : num = -num;
595 : :
596 [ - + ]: 354 : for (oom = 1; num >= 10; oom++)
597 : 0 : num /= 10;
598 : :
599 : 354 : return (oom);
600 : 790 : }
601 : :
602 : : static void
603 : 790 : counter_init(const char *count_what, int64_t max)
604 : : {
605 : 790 : count = 0;
606 : 790 : what = count_what;
607 : 790 : maxcount = max;
608 : 1580 : pkg_emit_progress_start("%-20s%*s[%jd]", what,
609 : 790 : 6 - magnitude(maxcount), " ", (intmax_t)maxcount);
610 : :
611 : 790 : return;
612 : : }
613 : :
614 : : static void
615 : 433 : counter_count(void)
616 : : {
617 : 433 : count++;
618 : :
619 [ + - ]: 433 : if (count % TICK == 0)
620 : 0 : pkg_emit_progress_tick(count, maxcount);
621 : :
622 : 433 : return;
623 : : }
624 : :
625 : : static void
626 : 789 : counter_end(void)
627 : : {
628 : 789 : pkg_emit_progress_tick(count, maxcount);
629 : 789 : return;
630 : : }
|