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