Branch data Line data Source code
1 : : /*
2 : : * Copyright (c) 2011-2021 Baptiste Daroussin <bapt@FreeBSD.org>
3 : : * Copyright (c) 2011-2012 Julien Laffaye <jlaffaye@FreeBSD.org>
4 : : * Copyright (c) 2014 Matthew Seaman <matthew@FreeBSD.org>
5 : : * Copyright (c) 2016 Vsevolod Stakhov <vsevolod@FreeBSD.org>
6 : : * All rights reserved.
7 : : *
8 : : * Redistribution and use in source and binary forms, with or without
9 : : * modification, are permitted provided that the following conditions
10 : : * are met:
11 : : * 1. Redistributions of source code must retain the above copyright
12 : : * notice, this list of conditions and the following disclaimer
13 : : * in this position and unchanged.
14 : : * 2. Redistributions in binary form must reproduce the above copyright
15 : : * notice, this list of conditions and the following disclaimer in the
16 : : * documentation and/or other materials provided with the distribution.
17 : : *
18 : : * THIS SOFTWARE IS PROVIDED BY THE AUTHOR(S) ``AS IS'' AND ANY EXPRESS OR
19 : : * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
20 : : * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
21 : : * IN NO EVENT SHALL THE AUTHOR(S) BE LIABLE FOR ANY DIRECT, INDIRECT,
22 : : * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
23 : : * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
24 : : * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
25 : : * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
26 : : * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
27 : : * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
28 : : */
29 : :
30 : : #include "pkg_config.h"
31 : :
32 : : #include <assert.h>
33 : : #include <sys/socket.h>
34 : : #include <sys/un.h>
35 : : #include <ctype.h>
36 : : #include <dirent.h>
37 : : #include <dlfcn.h>
38 : : #include <errno.h>
39 : : #include <fcntl.h>
40 : : #ifdef HAVE_OSRELDATE_H
41 : : #include <osreldate.h>
42 : : #endif
43 : : #include <ucl.h>
44 : :
45 : : #include "pkg.h"
46 : : #include "private/pkg.h"
47 : : #include "private/event.h"
48 : : #include "pkg_repos.h"
49 : :
50 : : #ifndef PORTSDIR
51 : : #define PORTSDIR "/usr/ports"
52 : : #endif
53 : : #ifndef DEFAULT_VULNXML_URL
54 : : #define DEFAULT_VULNXML_URL "http://vuxml.freebsd.org/freebsd/vuln.xml.xz"
55 : : #endif
56 : :
57 : : #ifdef OSMAJOR
58 : : #define STRINGIFY(X) TEXT(X)
59 : : #define TEXT(X) #X
60 : : #define INDEXFILE "INDEX-" STRINGIFY(OSMAJOR)
61 : : #else
62 : : #define INDEXFILE "INDEX"
63 : : #endif
64 : :
65 : : struct pkg_ctx ctx = {
66 : : .eventpipe = -1,
67 : : .debug_level = 0,
68 : : .developer_mode = false,
69 : : .pkg_rootdir = NULL,
70 : : .dbdir = NULL,
71 : : .cachedir = NULL,
72 : : .rootfd = -1,
73 : : .cachedirfd = -1,
74 : : .pkg_dbdirfd = -1,
75 : : .osversion = 0,
76 : : .backup_libraries = false,
77 : : .triggers = true,
78 : : .compression_level = -1,
79 : : .defer_triggers = false,
80 : : };
81 : :
82 : : struct config_entry {
83 : : uint8_t type;
84 : : const char *key;
85 : : const char *def;
86 : : const char *desc;
87 : : };
88 : :
89 : : static char myabi[BUFSIZ], myabi_legacy[BUFSIZ];
90 : : #ifdef __FreeBSD__
91 : : static char myosversion[BUFSIZ];
92 : : #endif
93 : : static struct pkg_repo *repos = NULL;
94 : : ucl_object_t *config = NULL;
95 : :
96 : : static struct config_entry c[] = {
97 : : {
98 : : PKG_STRING,
99 : : "PKG_DBDIR",
100 : : "/var/db/pkg",
101 : : "Where the package databases are stored",
102 : : },
103 : : {
104 : : PKG_STRING,
105 : : "PKG_CACHEDIR",
106 : : "/var/cache/pkg",
107 : : "Directory containing cache of downloaded packages",
108 : : },
109 : : {
110 : : PKG_STRING,
111 : : "PORTSDIR",
112 : : "/usr/ports",
113 : : "Location of the ports collection",
114 : : },
115 : : {
116 : : PKG_STRING,
117 : : "INDEXDIR",
118 : : NULL, /* Default to PORTSDIR unless defined */
119 : : "Location of the ports INDEX",
120 : : },
121 : : {
122 : : PKG_STRING,
123 : : "INDEXFILE",
124 : : INDEXFILE,
125 : : "Filename of the ports INDEX",
126 : : },
127 : : {
128 : : PKG_BOOL,
129 : : "HANDLE_RC_SCRIPTS",
130 : : "NO",
131 : : "Automatically handle restarting services",
132 : : },
133 : : {
134 : : PKG_BOOL,
135 : : "DEFAULT_ALWAYS_YES",
136 : : "NO",
137 : : "Default to 'yes' for all pkg(8) questions",
138 : : },
139 : : {
140 : : PKG_BOOL,
141 : : "ASSUME_ALWAYS_YES",
142 : : "NO",
143 : : "Answer 'yes' to all pkg(8) questions",
144 : : },
145 : : {
146 : : PKG_ARRAY,
147 : : "REPOS_DIR",
148 : : "/etc/pkg/,"PREFIX"/etc/pkg/repos/",
149 : : "Location of the repository configuration files"
150 : : },
151 : : {
152 : : PKG_STRING,
153 : : "PLIST_KEYWORDS_DIR",
154 : : NULL,
155 : : "Directory containing definitions of plist keywords",
156 : : },
157 : : {
158 : : PKG_BOOL,
159 : : "SYSLOG",
160 : : "YES",
161 : : "Log pkg(8) operations via syslog(3)",
162 : : },
163 : : {
164 : : PKG_STRING,
165 : : "ABI",
166 : : myabi,
167 : : "Override the automatically detected ABI",
168 : : },
169 : : {
170 : : PKG_STRING,
171 : : "ALTABI",
172 : : myabi_legacy,
173 : : "Override the automatically detected old-form ABI",
174 : : },
175 : : {
176 : : PKG_BOOL,
177 : : "DEVELOPER_MODE",
178 : : "NO",
179 : : "Add extra strict, pedantic warnings as an aid to package maintainers",
180 : : },
181 : : {
182 : : PKG_STRING,
183 : : "VULNXML_SITE",
184 : : DEFAULT_VULNXML_URL,
185 : : "URL giving location of the vulnxml database",
186 : : },
187 : : {
188 : : PKG_INT,
189 : : "FETCH_RETRY",
190 : : "3",
191 : : "How many times to retry fetching files",
192 : : },
193 : : {
194 : : PKG_STRING,
195 : : "PKG_PLUGINS_DIR",
196 : : PREFIX"/lib/pkg/",
197 : : "Directory which pkg(8) will load plugins from",
198 : : },
199 : : {
200 : : PKG_BOOL,
201 : : "PKG_ENABLE_PLUGINS",
202 : : "YES",
203 : : "Activate plugin support",
204 : : },
205 : : {
206 : : PKG_ARRAY,
207 : : "PLUGINS",
208 : : NULL,
209 : : "List of plugins that pkg(8) should load",
210 : : },
211 : : {
212 : : PKG_BOOL,
213 : : "DEBUG_SCRIPTS",
214 : : "NO",
215 : : "Run shell scripts in verbose mode to facilitate debugging",
216 : : },
217 : : {
218 : : PKG_STRING,
219 : : "PLUGINS_CONF_DIR",
220 : : PREFIX"/etc/pkg/",
221 : : "Directory containing plugin configuration data",
222 : : },
223 : : {
224 : : PKG_BOOL,
225 : : "PERMISSIVE",
226 : : "NO",
227 : : "Permit package installation despite presence of conflicting packages",
228 : : },
229 : : {
230 : : PKG_BOOL,
231 : : "REPO_AUTOUPDATE",
232 : : "YES",
233 : : "Automatically update repository catalogues prior to package updates",
234 : : },
235 : : {
236 : : PKG_STRING,
237 : : "NAMESERVER",
238 : : NULL,
239 : : "Use this nameserver when looking up addresses",
240 : : },
241 : : {
242 : : PKG_STRING,
243 : : "HTTP_USER_AGENT",
244 : : "pkg/"PKGVERSION,
245 : : "HTTP User-Agent",
246 : : },
247 : : {
248 : : PKG_STRING,
249 : : "EVENT_PIPE",
250 : : NULL,
251 : : "Send all events to the specified fifo or Unix socket",
252 : : },
253 : : {
254 : : PKG_INT,
255 : : "FETCH_TIMEOUT",
256 : : "30",
257 : : "Number of seconds before fetch(3) times out",
258 : : },
259 : : {
260 : : PKG_BOOL,
261 : : "UNSET_TIMESTAMP",
262 : : "NO",
263 : : "Do not include timestamps in the package",
264 : : },
265 : : {
266 : : PKG_STRING,
267 : : "SSH_RESTRICT_DIR",
268 : : NULL,
269 : : "Directory the ssh subsystem will be restricted to",
270 : : },
271 : : {
272 : : PKG_OBJECT,
273 : : "PKG_ENV",
274 : : NULL,
275 : : "Environment variables pkg will use",
276 : : },
277 : : {
278 : : PKG_STRING,
279 : : "PKG_SSH_ARGS",
280 : : NULL,
281 : : "Extras arguments to pass to ssh(1)",
282 : : },
283 : : {
284 : : PKG_INT,
285 : : "DEBUG_LEVEL",
286 : : "0",
287 : : "Level for debug messages",
288 : : },
289 : : {
290 : : PKG_OBJECT,
291 : : "ALIAS",
292 : : NULL,
293 : : "Command aliases",
294 : : },
295 : : {
296 : : PKG_STRING,
297 : : "CUDF_SOLVER",
298 : : NULL,
299 : : "Experimental: tells pkg to use an external CUDF solver",
300 : : },
301 : : {
302 : : PKG_STRING,
303 : : "SAT_SOLVER",
304 : : NULL,
305 : : "Experimental: tells pkg to use an external SAT solver",
306 : : },
307 : : {
308 : : PKG_BOOL,
309 : : "RUN_SCRIPTS",
310 : : "YES",
311 : : "Run post/pre actions scripts",
312 : : },
313 : : {
314 : : PKG_BOOL,
315 : : "CASE_SENSITIVE_MATCH",
316 : : "NO",
317 : : "Match package names case sensitively",
318 : : },
319 : : {
320 : : PKG_INT,
321 : : "LOCK_WAIT",
322 : : "1",
323 : : "Wait time to regain a lock if it is not available"
324 : : },
325 : : {
326 : : PKG_INT,
327 : : "LOCK_RETRIES",
328 : : "5",
329 : : "Retries performed to obtain a lock"
330 : : },
331 : : {
332 : : PKG_BOOL,
333 : : "SQLITE_PROFILE",
334 : : "NO",
335 : : "Profile sqlite queries"
336 : : },
337 : : {
338 : : PKG_INT,
339 : : "WORKERS_COUNT",
340 : : "0",
341 : : "How many workers are used for pkg-repo (hw.ncpu if 0)"
342 : : },
343 : : {
344 : : PKG_BOOL,
345 : : "READ_LOCK",
346 : : "NO",
347 : : "Use read locking for query database"
348 : : },
349 : : {
350 : : PKG_BOOL,
351 : : "PLIST_ACCEPT_DIRECTORIES",
352 : : "NO",
353 : : "Accept directories listed like plain files in plist"
354 : : },
355 : : {
356 : : PKG_INT,
357 : : "IP_VERSION",
358 : : "0",
359 : : "Restrict network access to IPv4 or IPv6 only"
360 : : },
361 : : {
362 : : PKG_BOOL,
363 : : "AUTOMERGE",
364 : : "YES",
365 : : "Automatically merge configuration files"
366 : : },
367 : : {
368 : : PKG_STRING,
369 : : "VERSION_SOURCE",
370 : : NULL,
371 : : "Version source for pkg-version (I, P, R), default is auto detect"
372 : : },
373 : : {
374 : : PKG_BOOL,
375 : : "CONSERVATIVE_UPGRADE",
376 : : "YES",
377 : : "Prefer repos with higher priority during upgrade"
378 : : },
379 : : {
380 : : PKG_BOOL,
381 : : "PKG_CREATE_VERBOSE",
382 : : "NO",
383 : : "Enable verbose mode for 'pkg create'",
384 : : },
385 : : {
386 : : PKG_BOOL,
387 : : "AUTOCLEAN",
388 : : "NO",
389 : : "Always cleanup the cache directory after install/upgrade",
390 : : },
391 : : {
392 : : PKG_STRING,
393 : : "DOT_FILE",
394 : : NULL,
395 : : "Save SAT problem to the specified dot file"
396 : : },
397 : : {
398 : : PKG_OBJECT,
399 : : "REPOSITORIES",
400 : : NULL,
401 : : "Repository config in pkg.conf"
402 : : },
403 : : {
404 : : PKG_ARRAY,
405 : : "VALID_URL_SCHEME",
406 : : "pkg+http,pkg+https,https,http,file,ssh,ftp,ftps,pkg+ssh,pkg+ftp,pkg+ftps",
407 : : },
408 : : {
409 : : PKG_BOOL,
410 : : "ALLOW_BASE_SHLIBS",
411 : : "NO",
412 : : "Enable base libraries analysis",
413 : : },
414 : : {
415 : : PKG_INT,
416 : : "WARN_SIZE_LIMIT",
417 : : "1048576", /* 1 meg */
418 : : "Ask user when performing changes for more than this limit"
419 : : },
420 : : {
421 : : PKG_STRING,
422 : : "METALOG",
423 : : NULL,
424 : : "Write out the METALOG to the specified file",
425 : : },
426 : : #ifdef __FreeBSD__
427 : : {
428 : : PKG_INT,
429 : : "OSVERSION",
430 : : myosversion,
431 : : "FreeBSD OS version",
432 : : },
433 : : {
434 : : PKG_BOOL,
435 : : "IGNORE_OSVERSION",
436 : : "NO",
437 : : "Ignore FreeBSD OS version check",
438 : : },
439 : : #endif
440 : : {
441 : : PKG_BOOL,
442 : : "BACKUP_LIBRARIES",
443 : : "NO",
444 : : "Backup old versions of libraries during an upgrade",
445 : : },
446 : : {
447 : : PKG_STRING,
448 : : "BACKUP_LIBRARY_PATH",
449 : : PREFIX "/lib/compat/pkg",
450 : : "Path where pkg will backup libraries",
451 : : },
452 : : {
453 : : PKG_STRING,
454 : : "PKG_TRIGGERS_DIR",
455 : : PREFIX "/share/pkg/triggers",
456 : : "Path where the triggers should be installed",
457 : : },
458 : : {
459 : : PKG_BOOL,
460 : : "PKG_TRIGGERS_ENABLE",
461 : : "YES",
462 : : "Disable triggers",
463 : : },
464 : : {
465 : : PKG_ARRAY,
466 : : "AUDIT_IGNORE_GLOB",
467 : : NULL,
468 : : "List of glob to ignore while autiditing for vulnerabilities",
469 : : },
470 : : {
471 : : PKG_ARRAY,
472 : : "AUDIT_IGNORE_REGEX",
473 : : "NULL",
474 : : "List of regex to ignore while autiditing for vulnerabilities",
475 : : },
476 : : {
477 : : PKG_INT,
478 : : "COMPRESSION_LEVEL",
479 : : "-1",
480 : : "Set the default compression level",
481 : : },
482 : : {
483 : : PKG_BOOL,
484 : : "ARCHIVE_SYMLINK",
485 : : "FALSE",
486 : : "Create a symlink to legacy extension for backward compatibility",
487 : : },
488 : : {
489 : : PKG_BOOL,
490 : : "REPO_ACCEPT_LEGACY_PKG",
491 : : "FALSE",
492 : : "Accept legacy package extensions when creating the repository",
493 : : },
494 : : {
495 : : PKG_ARRAY,
496 : : "FILES_IGNORE_GLOB",
497 : : "NULL",
498 : : "patterns of files to not extract from the package",
499 : : },
500 : : {
501 : : PKG_ARRAY,
502 : : "FILES_IGNORE_REGEX",
503 : : "NULL",
504 : : "patterns of files to not extract from the package",
505 : : },
506 : : };
507 : :
508 : : static bool parsed = false;
509 : : static size_t c_size = NELEM(c);
510 : :
511 : : static struct pkg_repo* pkg_repo_new(const char *name,
512 : : const char *url, const char *type);
513 : : static void pkg_repo_overwrite(struct pkg_repo*, const char *name,
514 : : const char *url, const char *type);
515 : : static void pkg_repo_free(struct pkg_repo *r);
516 : :
517 : : static void
518 : 0 : connect_evpipe(const char *evpipe) {
519 : : struct stat st;
520 : : struct sockaddr_un sock;
521 : 0 : int flag = O_WRONLY;
522 : :
523 [ # # ]: 0 : if (stat(evpipe, &st) != 0) {
524 : 0 : pkg_emit_error("No such event pipe: %s", evpipe);
525 : 0 : return;
526 : : }
527 : :
528 [ # # # # ]: 0 : if (!S_ISFIFO(st.st_mode) && !S_ISSOCK(st.st_mode)) {
529 : 0 : pkg_emit_error("%s is not a fifo or socket", evpipe);
530 : 0 : return;
531 : : }
532 : :
533 [ # # ]: 0 : if (S_ISFIFO(st.st_mode)) {
534 : 0 : flag |= O_NONBLOCK;
535 [ # # ]: 0 : if ((ctx.eventpipe = open(evpipe, flag)) == -1)
536 : 0 : pkg_emit_errno("open event pipe", evpipe);
537 : 0 : return;
538 : : }
539 : :
540 [ # # ]: 0 : if (S_ISSOCK(st.st_mode)) {
541 [ # # ]: 0 : if ((ctx.eventpipe = socket(AF_UNIX, SOCK_STREAM, 0)) == -1) {
542 : 0 : pkg_emit_errno("Open event pipe", evpipe);
543 : 0 : return;
544 : : }
545 : 0 : memset(&sock, 0, sizeof(struct sockaddr_un));
546 : 0 : sock.sun_family = AF_UNIX;
547 [ # # ]: 0 : if (strlcpy(sock.sun_path, evpipe, sizeof(sock.sun_path)) >=
548 : : sizeof(sock.sun_path)) {
549 : 0 : pkg_emit_error("Socket path too long: %s", evpipe);
550 : 0 : close(ctx.eventpipe);
551 : 0 : ctx.eventpipe = -1;
552 : 0 : return;
553 : : }
554 : :
555 [ # # ]: 0 : if (connect(ctx.eventpipe, (struct sockaddr *)&sock, SUN_LEN(&sock)) == -1) {
556 : 0 : pkg_emit_errno("Connect event pipe", evpipe);
557 : 0 : close(ctx.eventpipe);
558 : 0 : ctx.eventpipe = -1;
559 : 0 : return;
560 : : }
561 : 0 : }
562 : :
563 : 0 : }
564 : :
565 : : int
566 : 303 : pkg_initialized(void)
567 : : {
568 : 303 : return (parsed);
569 : : }
570 : :
571 : : const pkg_object *
572 : 135471 : pkg_config_get(const char *key) {
573 : 135471 : return (ucl_object_find_key(config, key));
574 : : }
575 : :
576 : : char *
577 : 34 : pkg_config_dump(void)
578 : : {
579 : 34 : return (pkg_object_dump(config));
580 : : }
581 : :
582 : : static void
583 : 3501 : disable_plugins_if_static(void)
584 : : {
585 : : void *dlh;
586 : :
587 : 3501 : dlh = dlopen(0, RTLD_NOW);
588 : :
589 : : /* if dlh is NULL then we are in static binary */
590 [ - + ]: 3501 : if (dlh == NULL)
591 : 0 : ucl_object_replace_key(config, ucl_object_frombool(false), "PKG_ENABLE_PLUGINS", 18, false);
592 : : else
593 : 3501 : dlclose(dlh);
594 : :
595 : 3501 : return;
596 : : }
597 : :
598 : : static void
599 : 3370 : add_repo(const ucl_object_t *obj, struct pkg_repo *r, const char *rname, pkg_init_flags flags)
600 : : {
601 : : const ucl_object_t *cur, *enabled, *env;
602 : 3370 : ucl_object_iter_t it = NULL;
603 : : struct pkg_kv *kv;
604 : 3370 : bool enable = true;
605 : 3370 : const char *url = NULL, *pubkey = NULL, *mirror_type = NULL;
606 : 3370 : const char *signature_type = NULL, *fingerprints = NULL;
607 : : const char *key;
608 : 3370 : const char *type = NULL;
609 : 3370 : int use_ipvx = 0;
610 : 3370 : int priority = 0;
611 : :
612 : 3370 : pkg_debug(1, "PkgConfig: parsing repository object %s", rname);
613 : :
614 : 3370 : env = NULL;
615 : 3370 : enabled = ucl_object_find_key(obj, "enabled");
616 [ + + ]: 3370 : if (enabled == NULL)
617 : 280 : enabled = ucl_object_find_key(obj, "ENABLED");
618 [ + + ]: 3370 : if (enabled != NULL) {
619 : 3090 : enable = ucl_object_toboolean(enabled);
620 [ - + # # ]: 3090 : if (!enable && r != NULL) {
621 : : /*
622 : : * We basically want to remove the existing repo r and
623 : : * forget all stuff parsed
624 : : */
625 : 0 : pkg_debug(1, "PkgConfig: disabling repo %s", rname);
626 [ # # # # : 0 : LL_DELETE(repos, r);
# # # # ]
627 : 0 : pkg_repo_free(r);
628 : 0 : return;
629 : : }
630 : 3090 : }
631 : :
632 [ + + ]: 18284 : while ((cur = ucl_iterate_object(obj, &it, true))) {
633 : 14914 : key = ucl_object_key(cur);
634 [ + - ]: 14914 : if (key == NULL)
635 : 0 : continue;
636 : :
637 [ + + ]: 14914 : if (strcasecmp(key, "url") == 0) {
638 [ + - ]: 3370 : if (cur->type != UCL_STRING) {
639 : 0 : pkg_emit_error("Expecting a string for the "
640 : : "'%s' key of the '%s' repo",
641 : 0 : key, rname);
642 : 0 : return;
643 : : }
644 : 3370 : url = ucl_object_tostring(cur);
645 [ + + ]: 14914 : } else if (strcasecmp(key, "pubkey") == 0) {
646 [ + - ]: 8 : if (cur->type != UCL_STRING) {
647 : 0 : pkg_emit_error("Expecting a string for the "
648 : : "'%s' key of the '%s' repo",
649 : 0 : key, rname);
650 : 0 : return;
651 : : }
652 : 8 : pubkey = ucl_object_tostring(cur);
653 [ + + ]: 11544 : } else if (strcasecmp(key, "mirror_type") == 0) {
654 [ + - ]: 2802 : if (cur->type != UCL_STRING) {
655 : 0 : pkg_emit_error("Expecting a string for the "
656 : : "'%s' key of the '%s' repo",
657 : 0 : key, rname);
658 : 0 : return;
659 : : }
660 : 2802 : mirror_type = ucl_object_tostring(cur);
661 [ + + ]: 11536 : } else if (strcasecmp(key, "signature_type") == 0) {
662 [ + - ]: 2818 : if (cur->type != UCL_STRING) {
663 : 0 : pkg_emit_error("Expecting a string for the "
664 : : "'%s' key of the '%s' repo",
665 : 0 : key, rname);
666 : 0 : return;
667 : : }
668 : 2818 : signature_type = ucl_object_tostring(cur);
669 [ + + ]: 8734 : } else if (strcasecmp(key, "fingerprints") == 0) {
670 [ + - ]: 2810 : if (cur->type != UCL_STRING) {
671 : 0 : pkg_emit_error("Expecting a string for the "
672 : : "'%s' key of the '%s' repo",
673 : 0 : key, rname);
674 : 0 : return;
675 : : }
676 : 2810 : fingerprints = ucl_object_tostring(cur);
677 [ + - ]: 5916 : } else if (strcasecmp(key, "type") == 0) {
678 [ # # ]: 0 : if (cur->type != UCL_STRING) {
679 : 0 : pkg_emit_error("Expecting a string for the "
680 : : "'%s' key of the '%s' repo",
681 : 0 : key, rname);
682 : 0 : return;
683 : : }
684 : 0 : type = ucl_object_tostring(cur);
685 [ + - ]: 3106 : } else if (strcasecmp(key, "ip_version") == 0) {
686 [ # # ]: 0 : if (cur->type != UCL_INT) {
687 : 0 : pkg_emit_error("Expecting a integer for the "
688 : : "'%s' key of the '%s' repo",
689 : 0 : key, rname);
690 : 0 : return;
691 : : }
692 : 0 : use_ipvx = ucl_object_toint(cur);
693 [ # # # # ]: 0 : if (use_ipvx != 4 && use_ipvx != 6)
694 : 0 : use_ipvx = 0;
695 [ + + ]: 3106 : } else if (strcasecmp(key, "priority") == 0) {
696 [ + - ]: 16 : if (cur->type != UCL_INT) {
697 : 0 : pkg_emit_error("Expecting a integer for the "
698 : : "'%s' key of the '%s' repo",
699 : 0 : key, rname);
700 : 0 : return;
701 : : }
702 : 16 : priority = ucl_object_toint(cur);
703 [ - + ]: 3106 : } else if (strcasecmp(key, "env") == 0) {
704 [ # # ]: 0 : if (cur->type != UCL_OBJECT) {
705 : 0 : pkg_emit_error("Expecting an object for the "
706 : : "'%s' key of the '%s' repo",
707 : 0 : key, rname);
708 : 0 : }
709 : 0 : env = cur;
710 : 0 : }
711 : : }
712 : :
713 [ + + - + ]: 3370 : if (r == NULL && url == NULL) {
714 : 0 : pkg_debug(1, "No repo and no url for %s", rname);
715 : 0 : return;
716 : : }
717 : :
718 [ + + ]: 3370 : if (r == NULL)
719 : 3350 : r = pkg_repo_new(rname, url, type);
720 : : else
721 : 20 : pkg_repo_overwrite(r, rname, url, type);
722 : :
723 [ + + ]: 3370 : if (signature_type != NULL) {
724 [ + + ]: 2818 : if (strcasecmp(signature_type, "pubkey") == 0)
725 : 8 : r->signature_type = SIG_PUBKEY;
726 [ + - ]: 2810 : else if (strcasecmp(signature_type, "fingerprints") == 0)
727 : 2810 : r->signature_type = SIG_FINGERPRINT;
728 : : else
729 : 0 : r->signature_type = SIG_NONE;
730 : 2818 : }
731 : :
732 : :
733 [ + + ]: 3370 : if (fingerprints != NULL) {
734 : 2810 : free(r->fingerprints);
735 : 2810 : r->fingerprints = xstrdup(fingerprints);
736 : 2810 : }
737 : :
738 [ + + ]: 3370 : if (pubkey != NULL) {
739 : 8 : free(r->pubkey);
740 : 8 : r->pubkey = xstrdup(pubkey);
741 : 8 : }
742 : :
743 : 3370 : r->enable = enable;
744 : 3370 : r->priority = priority;
745 : :
746 [ + + ]: 3370 : if (mirror_type != NULL) {
747 [ - + ]: 2802 : if (strcasecmp(mirror_type, "srv") == 0)
748 : 2802 : r->mirror_type = SRV;
749 [ # # ]: 0 : else if (strcasecmp(mirror_type, "http") == 0)
750 : 0 : r->mirror_type = HTTP;
751 : : else
752 : 0 : r->mirror_type = NOMIRROR;
753 : 2802 : }
754 : :
755 [ - + ]: 3370 : if ((flags & PKG_INIT_FLAG_USE_IPV4) == PKG_INIT_FLAG_USE_IPV4)
756 : 0 : use_ipvx = 4;
757 [ + - ]: 3370 : else if ((flags & PKG_INIT_FLAG_USE_IPV6) == PKG_INIT_FLAG_USE_IPV6)
758 : 0 : use_ipvx = 6;
759 : :
760 [ + - - + ]: 3370 : if (use_ipvx != 4 && use_ipvx != 6)
761 : 3370 : use_ipvx = pkg_object_int(pkg_config_get("IP_VERSION"));
762 : :
763 [ - + ]: 3370 : if (use_ipvx == 4)
764 : 0 : r->flags = REPO_FLAGS_USE_IPV4;
765 [ + - ]: 3370 : else if (use_ipvx == 6)
766 : 0 : r->flags = REPO_FLAGS_USE_IPV6;
767 : :
768 [ - + ]: 3370 : if (env != NULL) {
769 : 0 : it = NULL;
770 [ # # ]: 0 : while ((cur = ucl_iterate_object(env, &it, true))) {
771 : 0 : kv = pkg_kv_new(ucl_object_key(cur),
772 : 0 : ucl_object_tostring_forced(cur));
773 [ # # ]: 0 : DL_APPEND(r->env, kv);
774 : : }
775 : 0 : }
776 : 3370 : }
777 : :
778 : : static void
779 : 189 : add_repo_obj(const ucl_object_t *obj, const char *file, pkg_init_flags flags)
780 : : {
781 : : struct pkg_repo *r;
782 : : const char *key;
783 : :
784 : 189 : key = ucl_object_key(obj);
785 : 189 : pkg_debug(1, "PkgConfig: parsing repo key '%s' in file '%s'", key, file);
786 : 189 : r = pkg_repo_find(key);
787 [ + + ]: 189 : if (r != NULL)
788 : 20 : pkg_debug(1, "PkgConfig: overwriting repository %s", key);
789 : 189 : add_repo(obj, r, key, flags);
790 : 189 : }
791 : :
792 : : static void
793 : 5939 : walk_repo_obj(const ucl_object_t *obj, const char *file, pkg_init_flags flags)
794 : : {
795 : : const ucl_object_t *cur;
796 : 5939 : ucl_object_iter_t it = NULL;
797 : : struct pkg_repo *r;
798 : : const char *key;
799 : :
800 [ + + ]: 9120 : while ((cur = ucl_iterate_object(obj, &it, true))) {
801 : 3181 : key = ucl_object_key(cur);
802 : 3181 : pkg_debug(1, "PkgConfig: parsing key '%s'", key);
803 : 3181 : r = pkg_repo_find(key);
804 [ + - ]: 3181 : if (r != NULL)
805 : 0 : pkg_debug(1, "PkgConfig: overwriting repository %s", key);
806 [ - + ]: 3181 : if (cur->type == UCL_OBJECT)
807 : 3181 : add_repo(cur, r, key, flags);
808 : : else
809 : 0 : pkg_emit_error("Ignoring bad configuration entry in %s: %s",
810 : 0 : file, ucl_object_emit(cur, UCL_EMIT_YAML));
811 : : }
812 : 5939 : }
813 : :
814 : : static void
815 : 5939 : load_repo_file(int dfd, const char *repodir, const char *repofile,
816 : : pkg_init_flags flags, struct os_info *oi)
817 : : {
818 : : struct ucl_parser *p;
819 : 5939 : ucl_object_t *obj = NULL;
820 : 5939 : const char *myarch = NULL;
821 : 5939 : const char *myarch_legacy = NULL;
822 : : int fd;
823 : :
824 : 5939 : p = ucl_parser_new(0);
825 : :
826 : 5939 : myarch = pkg_object_string(pkg_config_get("ABI"));
827 : 5939 : ucl_parser_register_variable (p, "ABI", myarch);
828 : :
829 : 5939 : myarch_legacy = pkg_object_string(pkg_config_get("ALTABI"));
830 : 5939 : ucl_parser_register_variable (p, "ALTABI", myarch_legacy);
831 : : #ifdef __FreeBSD__
832 : 5939 : ucl_parser_register_variable(p, "OSVERSION", myosversion);
833 : : #endif
834 [ - + ]: 5939 : if (oi->name != NULL) {
835 : 5939 : ucl_parser_register_variable(p, "OSNAME", oi->name);
836 : 5939 : }
837 [ - + ]: 5939 : if (oi->version != NULL) {
838 : 5939 : ucl_parser_register_variable(p, "RELEASE", oi->version);
839 : 5939 : }
840 [ - + ]: 5939 : if (oi->version_major != NULL) {
841 : 5939 : ucl_parser_register_variable(p, "VERSION_MAJOR", oi->version_major);
842 : 5939 : }
843 [ - + ]: 5939 : if (oi->version_minor != NULL) {
844 : 5939 : ucl_parser_register_variable(p, "VERSION_MINOR", oi->version_minor);
845 : 5939 : }
846 [ - + ]: 5939 : if (oi->arch != NULL) {
847 : 5939 : ucl_parser_register_variable(p, "ARCH", oi->arch);
848 : 5939 : }
849 : :
850 : 5939 : errno = 0;
851 : 5939 : obj = NULL;
852 : :
853 : 5939 : pkg_debug(1, "PKgConfig: loading %s/%s", repodir, repofile);
854 : 5939 : fd = openat(dfd, repofile, O_RDONLY);
855 [ + - ]: 5939 : if (fd == -1) {
856 : 0 : pkg_errno("Unable to open '%s/%s'", repodir, repofile);
857 : 0 : return;
858 : : }
859 [ + - ]: 5939 : if (!ucl_parser_add_fd(p, fd)) {
860 : 0 : pkg_emit_error("Error parsing: '%s/%s': %s", repodir,
861 : 0 : repofile, ucl_parser_get_error(p));
862 : 0 : ucl_parser_free(p);
863 : 0 : close(fd);
864 : 0 : return;
865 : : }
866 : 5939 : close(fd);
867 : :
868 : 5939 : obj = ucl_parser_get_object(p);
869 [ + - ]: 5939 : if (obj == NULL) {
870 : 0 : ucl_parser_free(p);
871 : 0 : return;
872 : : }
873 : :
874 : 5939 : ucl_parser_free(p);
875 [ + - ]: 5939 : if (obj->type == UCL_OBJECT)
876 : 5939 : walk_repo_obj(obj, repofile, flags);
877 : :
878 : 5939 : ucl_object_unref(obj);
879 : 5939 : }
880 : :
881 : : static int
882 : 18097 : configfile(const struct dirent *dp)
883 : : {
884 : : const char *p;
885 : : size_t n;
886 : :
887 [ + + ]: 18097 : if (dp->d_name[0] == '.')
888 : 11794 : return (0);
889 : :
890 : 6303 : n = strlen(dp->d_name);
891 [ + + ]: 6303 : if (n <= 5)
892 : 56 : return (0);
893 : :
894 : 6247 : p = &dp->d_name[n - 5];
895 [ + + ]: 6247 : if (strcmp(p, ".conf") != 0)
896 : 308 : return (0);
897 : 5939 : return (1);
898 : 18097 : }
899 : :
900 : : static void
901 : 6166 : load_repo_files(const char *repodir, pkg_init_flags flags, struct os_info *oi)
902 : : {
903 : : struct dirent **ent;
904 : : int nents, i, fd;
905 : :
906 : 6166 : pkg_debug(1, "PkgConfig: loading repositories in %s", repodir);
907 [ + + ]: 6166 : if ((fd = open(repodir, O_DIRECTORY|O_CLOEXEC)) == -1)
908 : 269 : return;
909 : :
910 : 5897 : nents = scandir(repodir, &ent, configfile, alphasort);
911 [ + + ]: 11836 : for (i = 0; i < nents; i++) {
912 : 5939 : load_repo_file(fd, repodir, ent[i]->d_name, flags, oi);
913 : 5939 : free(ent[i]);
914 : 5939 : }
915 [ - + ]: 5897 : if (nents >= 0)
916 : 5897 : free(ent);
917 : 5897 : close(fd);
918 : 6166 : }
919 : :
920 : : static void
921 : 3501 : load_repositories(const char *repodir, pkg_init_flags flags, struct os_info *oi)
922 : : {
923 : : const pkg_object *reposlist, *cur;
924 : 3501 : pkg_iter it = NULL;
925 : :
926 [ + + ]: 3501 : if (repodir != NULL) {
927 : 21 : load_repo_files(repodir, flags, oi);
928 : 21 : return;
929 : : }
930 : :
931 : 3480 : reposlist = pkg_config_get("REPOS_DIR");
932 [ + + ]: 9625 : while ((cur = pkg_object_iterate(reposlist, &it)))
933 : 6145 : load_repo_files(pkg_object_string(cur), flags, oi);
934 : 3501 : }
935 : :
936 : : bool
937 : 3501 : pkg_compiled_for_same_os_major(void)
938 : : {
939 : : #ifdef OSMAJOR
940 : : const char *myabi;
941 : : int osmajor;
942 : :
943 [ + + ]: 3501 : if (getenv("IGNORE_OSMAJOR") != NULL)
944 : 4 : return (true);
945 : :
946 : 3497 : myabi = pkg_object_string(pkg_config_get("ABI"));
947 : 3497 : myabi = strchr(myabi,':');
948 [ - + ]: 3497 : if (myabi == NULL) {
949 : 0 : pkg_emit_error("Invalid ABI");
950 : 0 : return (false);
951 : : }
952 : 3497 : myabi++;
953 : :
954 : 3497 : osmajor = (int) strtol(myabi, NULL, 10);
955 : :
956 : 3497 : return (osmajor == OSMAJOR);
957 : : #else
958 : : return (true); /* Can't tell, so assume yes */
959 : : #endif
960 : 3501 : }
961 : :
962 : :
963 : : int
964 : 0 : pkg_init(const char *path, const char *reposdir)
965 : : {
966 : 0 : return (pkg_ini(path, reposdir, 0));
967 : : }
968 : :
969 : : static const char *
970 : 0 : type_to_string(int type)
971 : : {
972 [ # # ]: 0 : if (type == UCL_ARRAY)
973 : 0 : return ("array");
974 [ # # ]: 0 : if (type == UCL_OBJECT)
975 : 0 : return ("object");
976 [ # # ]: 0 : if (type == UCL_STRING)
977 : 0 : return ("string");
978 [ # # ]: 0 : if (type == UCL_INT)
979 : 0 : return ("integer");
980 [ # # ]: 0 : if (type == UCL_BOOLEAN)
981 : 0 : return ("boolean");
982 : 0 : return ("unknown");
983 : 0 : }
984 : : int
985 : 3501 : pkg_ini(const char *path, const char *reposdir, pkg_init_flags flags)
986 : : {
987 : 3501 : struct ucl_parser *p = NULL;
988 : : size_t i;
989 : 3501 : const char *val = NULL;
990 : : const char *buf, *walk, *value, *key, *k;
991 : 3501 : const char *evkey = NULL;
992 : 3501 : const char *nsname = NULL;
993 : 3501 : const char *metalog = NULL;
994 : 3501 : const char *useragent = NULL;
995 : 3501 : const char *evpipe = NULL;
996 : : const char *url;
997 : 3501 : struct pkg_repo *repo = NULL;
998 : : const ucl_object_t *cur, *object;
999 : 3501 : ucl_object_t *obj = NULL, *o, *ncfg;
1000 : 3501 : ucl_object_iter_t it = NULL;
1001 : 3501 : xstring *ukey = NULL;
1002 : 3501 : bool fatal_errors = false;
1003 : 3501 : int conffd = -1;
1004 : 3501 : char *tmp = NULL;
1005 : : struct os_info oi;
1006 : : size_t ukeylen;
1007 : 3501 : int err = EPKG_OK;
1008 : :
1009 : 3501 : k = NULL;
1010 : 3501 : o = NULL;
1011 [ + + + - ]: 3501 : if (ctx.rootfd == -1 && (ctx.rootfd = open("/", O_DIRECTORY|O_RDONLY|O_CLOEXEC)) < 0) {
1012 : 0 : pkg_emit_error("Impossible to open /");
1013 : : /* Note: Not goto out since oi.arch hasn't been initialized yet. */
1014 : 0 : return (EPKG_FATAL);
1015 : : }
1016 : :
1017 : 3501 : memset(&oi, 0, sizeof(oi));
1018 : 3501 : pkg_get_myarch(myabi, BUFSIZ, &oi);
1019 : 3501 : pkg_get_myarch_legacy(myabi_legacy, BUFSIZ);
1020 : : #ifdef __FreeBSD__
1021 : 3501 : ctx.osversion = oi.osversion;
1022 : 3501 : snprintf(myosversion, sizeof(myosversion), "%d", ctx.osversion);
1023 : : #endif
1024 [ - + ]: 3501 : if (parsed != false) {
1025 : 0 : pkg_emit_error("pkg_init() must only be called once");
1026 : 0 : err = EPKG_FATAL;
1027 : 0 : goto out;
1028 : : }
1029 : :
1030 [ - + # # ]: 3501 : if (((flags & PKG_INIT_FLAG_USE_IPV4) == PKG_INIT_FLAG_USE_IPV4) &&
1031 : 0 : ((flags & PKG_INIT_FLAG_USE_IPV6) == PKG_INIT_FLAG_USE_IPV6)) {
1032 : 0 : pkg_emit_error("Invalid flags for pkg_init()");
1033 : 0 : err = EPKG_FATAL;
1034 : 0 : goto out;
1035 : : }
1036 : :
1037 : 3501 : config = ucl_object_typed_new(UCL_OBJECT);
1038 : :
1039 [ + + ]: 241569 : for (i = 0; i < c_size; i++) {
1040 [ + + + + : 238068 : switch (c[i].type) {
- + ]
1041 : : case PKG_STRING:
1042 : 80523 : tmp = NULL;
1043 [ + + + + : 80523 : if (c[i].def != NULL && c[i].def[0] == '/' &&
+ + ]
1044 : 24507 : ctx.pkg_rootdir != NULL) {
1045 : 2121 : xasprintf(&tmp, "%s%s", ctx.pkg_rootdir, c[i].def);
1046 : 2121 : }
1047 : 80523 : obj = ucl_object_fromstring_common(
1048 [ + + + + ]: 80523 : c[i].def != NULL ? tmp != NULL ? tmp : c[i].def : "", 0, UCL_STRING_TRIM);
1049 : 80523 : free(tmp);
1050 : 161046 : ucl_object_insert_key(config, obj,
1051 : 80523 : c[i].key, strlen(c[i].key), false);
1052 : 80523 : break;
1053 : : case PKG_INT:
1054 : 70020 : ucl_object_insert_key(config,
1055 : 35010 : ucl_object_fromstring_common(c[i].def, 0, UCL_STRING_PARSE_INT),
1056 : 35010 : c[i].key, strlen(c[i].key), false);
1057 : 35010 : break;
1058 : : case PKG_BOOL:
1059 : 175050 : ucl_object_insert_key(config,
1060 : 87525 : ucl_object_fromstring_common(c[i].def, 0, UCL_STRING_PARSE_BOOLEAN),
1061 : 87525 : c[i].key, strlen(c[i].key), false);
1062 : 87525 : break;
1063 : : case PKG_OBJECT:
1064 : 10503 : obj = ucl_object_typed_new(UCL_OBJECT);
1065 [ + - ]: 10503 : if (c[i].def != NULL) {
1066 : 0 : walk = buf = c[i].def;
1067 [ # # ]: 0 : while ((buf = strchr(buf, ',')) != NULL) {
1068 : 0 : key = walk;
1069 : 0 : value = walk;
1070 [ # # ]: 0 : while (*value != ',') {
1071 [ # # ]: 0 : if (*value == '=')
1072 : 0 : break;
1073 : 0 : value++;
1074 : : }
1075 : 0 : ucl_object_insert_key(obj,
1076 : 0 : ucl_object_fromstring_common(value + 1, buf - value - 1, UCL_STRING_TRIM),
1077 : 0 : key, value - key, false);
1078 : 0 : buf++;
1079 : 0 : walk = buf;
1080 : : }
1081 : 0 : key = walk;
1082 : 0 : value = walk;
1083 [ # # ]: 0 : while (*value != ',') {
1084 [ # # ]: 0 : if (*value == '=')
1085 : 0 : break;
1086 : 0 : value++;
1087 : : }
1088 [ # # ]: 0 : if (o == NULL)
1089 : 0 : o = ucl_object_typed_new(UCL_OBJECT);
1090 : 0 : ucl_object_insert_key(o,
1091 : 0 : ucl_object_fromstring_common(value + 1, strlen(value + 1), UCL_STRING_TRIM),
1092 : 0 : key, value - key, false);
1093 : 0 : }
1094 : 21006 : ucl_object_insert_key(config, obj,
1095 : 10503 : c[i].key, strlen(c[i].key), false);
1096 : 10503 : break;
1097 : : case PKG_ARRAY:
1098 : 24507 : obj = ucl_object_typed_new(UCL_ARRAY);
1099 [ + + ]: 24507 : if (c[i].def != NULL) {
1100 : 17505 : walk = buf = c[i].def;
1101 [ + + ]: 56016 : while ((buf = strchr(buf, ',')) != NULL) {
1102 : 77022 : ucl_array_append(obj,
1103 : 38511 : ucl_object_fromstring_common(walk, buf - walk, UCL_STRING_TRIM));
1104 : 38511 : buf++;
1105 : 38511 : walk = buf;
1106 : : }
1107 : 35010 : ucl_array_append(obj,
1108 : 17505 : ucl_object_fromstring_common(walk, strlen(walk), UCL_STRING_TRIM));
1109 : 17505 : }
1110 : 49014 : ucl_object_insert_key(config, obj,
1111 : 24507 : c[i].key, strlen(c[i].key), false);
1112 : 24507 : break;
1113 : : }
1114 : 238068 : }
1115 : :
1116 [ + + ]: 3501 : if (path == NULL)
1117 : 3086 : conffd = openat(ctx.rootfd, &PREFIX"/etc/pkg.conf"[1], 0);
1118 : : else
1119 : 415 : conffd = open(path, O_RDONLY);
1120 [ + + + - ]: 3501 : if (conffd == -1 && errno != ENOENT) {
1121 [ # # ]: 0 : pkg_errno("Cannot open %s/%s",
1122 : : ctx.pkg_rootdir != NULL ? ctx.pkg_rootdir : "",
1123 : : path);
1124 : 0 : }
1125 : :
1126 : 3501 : p = ucl_parser_new(0);
1127 : 3501 : ucl_parser_register_variable (p, "ABI", myabi);
1128 : 3501 : ucl_parser_register_variable (p, "ALTABI", myabi_legacy);
1129 : : #ifdef __FreeBSD__
1130 : 3501 : ucl_parser_register_variable(p, "OSVERSION", myosversion);
1131 : : #endif
1132 [ - + ]: 3501 : if (oi.name != NULL) {
1133 : 3501 : ucl_parser_register_variable(p, "OSNAME", oi.name);
1134 : 3501 : }
1135 [ - + ]: 3501 : if (oi.version != NULL) {
1136 : 3501 : ucl_parser_register_variable(p, "RELEASE", oi.version);
1137 : 3501 : }
1138 [ - + ]: 3501 : if (oi.version_major != NULL) {
1139 : 3501 : ucl_parser_register_variable(p, "VERSION_MAJOR", oi.version_major);
1140 : 3501 : }
1141 [ - + ]: 3501 : if (oi.version_minor != NULL) {
1142 : 3501 : ucl_parser_register_variable(p, "VERSION_MINOR", oi.version_minor);
1143 : 3501 : }
1144 [ - + ]: 3501 : if (oi.arch != NULL) {
1145 : 3501 : ucl_parser_register_variable(p, "ARCH", oi.arch);
1146 : 3501 : }
1147 : :
1148 : 3501 : errno = 0;
1149 : 3501 : obj = NULL;
1150 [ + + ]: 3501 : if (conffd != -1) {
1151 [ + - ]: 3090 : if (!ucl_parser_add_fd(p, conffd)) {
1152 : 0 : pkg_emit_error("Invalid configuration file: %s", ucl_parser_get_error(p));
1153 : 0 : }
1154 : 3090 : close(conffd);
1155 : 3090 : }
1156 : :
1157 : 3501 : obj = ucl_parser_get_object(p);
1158 : 3501 : ncfg = NULL;
1159 : 3501 : ukey = NULL;
1160 [ + + + + ]: 6947 : while (obj != NULL && (cur = ucl_iterate_object(obj, &it, true))) {
1161 [ + + ]: 3446 : xstring_renew(ukey);
1162 : 3446 : key = ucl_object_key(cur);
1163 [ + + ]: 23775 : for (i = 0; key[i] != '\0'; i++)
1164 : 20329 : fputc(toupper(key[i]), ukey->fp);
1165 : 3446 : fflush(ukey->fp);
1166 : 3446 : ukeylen = strlen(ukey->buf);
1167 : 3446 : object = ucl_object_find_keyl(config, ukey->buf, ukeylen);
1168 : :
1169 [ + - - + ]: 6892 : if (strncasecmp(ukey->buf, "PACKAGESITE", ukeylen) == 0 ||
1170 [ + - ]: 3446 : strncasecmp(ukey->buf, "PUBKEY", ukeylen) == 0 ||
1171 : 3446 : strncasecmp(ukey->buf, "MIRROR_TYPE", ukeylen) == 0) {
1172 : 0 : pkg_emit_error("%s in pkg.conf is no longer "
1173 : : "supported. Convert to the new repository style."
1174 : 0 : " See pkg.conf(5)", ukey->buf);
1175 : 0 : fatal_errors = true;
1176 : 0 : continue;
1177 : : }
1178 : :
1179 : : /* ignore unknown keys */
1180 [ + - ]: 3446 : if (object == NULL)
1181 : 0 : continue;
1182 : :
1183 [ - + ]: 3446 : if (object->type != cur->type) {
1184 : 0 : pkg_emit_error("Malformed key %s, got '%s' expecting "
1185 : 0 : "'%s', ignoring", key,
1186 : 0 : type_to_string(cur->type),
1187 : 0 : type_to_string(object->type));
1188 : 0 : continue;
1189 : : }
1190 : :
1191 [ + + ]: 3446 : if (ncfg == NULL)
1192 : 3052 : ncfg = ucl_object_typed_new(UCL_OBJECT);
1193 : 6892 : ucl_object_insert_key(ncfg, ucl_object_copy(cur), ukey->buf,
1194 : 3446 : ukeylen, true);
1195 : : }
1196 : 3501 : xstring_free(ukey);
1197 : :
1198 [ - + ]: 3501 : if (fatal_errors) {
1199 : 0 : ucl_object_unref(ncfg);
1200 : 0 : ucl_parser_free(p);
1201 : 0 : err = EPKG_FATAL;
1202 : 0 : goto out;
1203 : : }
1204 : :
1205 [ + + ]: 3501 : if (ncfg != NULL) {
1206 : 3052 : it = NULL;
1207 [ + + ]: 6498 : while (( cur = ucl_iterate_object(ncfg, &it, true))) {
1208 : 3446 : key = ucl_object_key(cur);
1209 : 3446 : ucl_object_replace_key(config, ucl_object_ref(cur), key, strlen(key), true);
1210 : : }
1211 : 3052 : }
1212 : 3501 : ucl_object_unref(ncfg);
1213 : 3501 : ncfg = NULL;
1214 : 3501 : it = NULL;
1215 [ + + ]: 241569 : while ((cur = ucl_iterate_object(config, &it, true))) {
1216 : 238068 : o = NULL;
1217 : 238068 : key = ucl_object_key(cur);
1218 : 238068 : val = getenv(key);
1219 [ + + ]: 238068 : if (val == NULL)
1220 : 230379 : continue;
1221 [ - + - + : 7689 : switch (cur->type) {
+ + ]
1222 : : case UCL_STRING:
1223 : 3629 : o = ucl_object_fromstring_common(val, 0, UCL_STRING_TRIM);
1224 : 3629 : break;
1225 : : case UCL_INT:
1226 : 0 : o = ucl_object_fromstring_common(val, 0, UCL_STRING_PARSE_INT);
1227 [ # # ]: 0 : if (o->type != UCL_INT) {
1228 : 0 : pkg_emit_error("Invalid type for environment "
1229 : : "variable %s, got %s, while expecting an integer",
1230 : 0 : key, val);
1231 : 0 : ucl_object_unref(o);
1232 : 0 : continue;
1233 : : }
1234 : 0 : break;
1235 : : case UCL_BOOLEAN:
1236 : 3499 : o = ucl_object_fromstring_common(val, 0, UCL_STRING_PARSE_BOOLEAN);
1237 [ - + ]: 3499 : if (o->type != UCL_BOOLEAN) {
1238 : 0 : pkg_emit_error("Invalid type for environment "
1239 : : "variable %s, got %s, while expecting a boolean",
1240 : 0 : key, val);
1241 : 0 : ucl_object_unref(o);
1242 : 0 : continue;
1243 : : }
1244 : 3499 : break;
1245 : : case UCL_OBJECT:
1246 : 52 : o = ucl_object_typed_new(UCL_OBJECT);
1247 : 52 : walk = buf = val;
1248 [ + + ]: 104 : while ((buf = strchr(buf, ',')) != NULL) {
1249 : 52 : k = walk;
1250 : 52 : value = walk;
1251 [ - + ]: 624 : while (*value != ',') {
1252 [ + + ]: 624 : if (*value == '=')
1253 : 52 : break;
1254 : 572 : value++;
1255 : : }
1256 : 104 : ucl_object_insert_key(o,
1257 : 52 : ucl_object_fromstring_common(value + 1, buf - value - 1, UCL_STRING_TRIM),
1258 : 52 : k, value - k, false);
1259 : 52 : buf++;
1260 : 52 : walk = buf;
1261 : : }
1262 : 52 : k = walk;
1263 : 52 : value = walk;
1264 [ - + ]: 260 : while (*value != '\0') {
1265 [ + + ]: 260 : if (*value == '=')
1266 : 52 : break;
1267 : 208 : value++;
1268 : : }
1269 : 104 : ucl_object_insert_key(o,
1270 : 52 : ucl_object_fromstring_common(value + 1, strlen(value + 1), UCL_STRING_TRIM),
1271 : 52 : k, value - k, false);
1272 : 52 : break;
1273 : : case UCL_ARRAY:
1274 : 509 : o = ucl_object_typed_new(UCL_ARRAY);
1275 : 509 : walk = buf = val;
1276 [ - + ]: 509 : while ((buf = strchr(buf, ',')) != NULL) {
1277 : 0 : ucl_array_append(o,
1278 : 0 : ucl_object_fromstring_common(walk, buf - walk, UCL_STRING_TRIM));
1279 : 0 : buf++;
1280 : 0 : walk = buf;
1281 : : }
1282 : 1018 : ucl_array_append(o,
1283 : 509 : ucl_object_fromstring_common(walk, strlen(walk), UCL_STRING_TRIM));
1284 : 509 : break;
1285 : : default:
1286 : : /* ignore other types */
1287 : 0 : break;
1288 : : }
1289 [ - + ]: 7689 : if (o != NULL) {
1290 [ + + ]: 7689 : if (ncfg == NULL)
1291 : 3488 : ncfg = ucl_object_typed_new(UCL_OBJECT);
1292 : 7689 : ucl_object_insert_key(ncfg, o, key, strlen(key), true);
1293 : 7689 : }
1294 : : }
1295 : :
1296 [ + + ]: 3501 : if (ncfg != NULL) {
1297 : 3488 : it = NULL;
1298 [ + + ]: 11177 : while (( cur = ucl_iterate_object(ncfg, &it, true))) {
1299 : 7689 : key = ucl_object_key(cur);
1300 : 7689 : ucl_object_replace_key(config, ucl_object_ref(cur), key, strlen(key), true);
1301 : : }
1302 : 3488 : ucl_object_unref(ncfg);
1303 : 3488 : }
1304 : :
1305 : 3501 : disable_plugins_if_static();
1306 : :
1307 : 3501 : parsed = true;
1308 : 3501 : ucl_object_unref(obj);
1309 : 3501 : ucl_parser_free(p);
1310 : :
1311 [ + - - + ]: 3501 : if (pkg_object_string(pkg_config_get("ABI")) == NULL ||
1312 : 3501 : strcmp(pkg_object_string(pkg_config_get("ABI")), "unknown") == 0) {
1313 : 0 : pkg_emit_error("Unable to determine ABI");
1314 : 0 : err = EPKG_FATAL;
1315 : 0 : goto out;
1316 : : }
1317 : :
1318 : 3501 : pkg_debug(1, "%s", "pkg initialized");
1319 : :
1320 : : #ifdef __FreeBSD__
1321 : 3501 : ctx.osversion = pkg_object_int(pkg_config_get("OSVERSION"));
1322 : : #endif
1323 : : /* Start the event pipe */
1324 : 3501 : evpipe = pkg_object_string(pkg_config_get("EVENT_PIPE"));
1325 [ - + ]: 3501 : if (evpipe != NULL)
1326 : 0 : connect_evpipe(evpipe);
1327 : :
1328 : 3501 : ctx.debug_level = pkg_object_int(pkg_config_get("DEBUG_LEVEL"));
1329 : 3501 : ctx.developer_mode = pkg_object_bool(pkg_config_get("DEVELOPER_MODE"));
1330 : 3501 : ctx.dbdir = pkg_object_string(pkg_config_get("PKG_DBDIR"));
1331 : 3501 : ctx.cachedir = pkg_object_string(pkg_config_get("PKG_CACHEDIR"));
1332 : 3501 : ctx.backup_libraries = pkg_object_bool(pkg_config_get("BACKUP_LIBRARIES"));
1333 : 3501 : ctx.backup_library_path = pkg_object_string(pkg_config_get("BACKUP_LIBRARY_PATH"));
1334 : 3501 : ctx.triggers = pkg_object_bool(pkg_config_get("PKG_TRIGGERS_ENABLE"));
1335 : 3501 : ctx.triggers_path = pkg_object_string(pkg_config_get("PKG_TRIGGERS_DIR"));
1336 : 3501 : ctx.compression_level = pkg_object_int(pkg_config_get("COMPRESSION_LEVEL"));
1337 : 3501 : ctx.archive_symlink = pkg_object_bool(pkg_config_get("ARCHIVE_SYMLINK"));
1338 : 3501 : ctx.repo_accept_legacy_pkg = pkg_object_bool(pkg_config_get("REPO_ACCEPT_LEGACY_PKG"));
1339 : :
1340 : 3501 : it = NULL;
1341 : 3501 : object = ucl_object_find_key(config, "PKG_ENV");
1342 [ - + ]: 3501 : while ((cur = ucl_iterate_object(object, &it, true))) {
1343 : 0 : evkey = ucl_object_key(cur);
1344 : 0 : pkg_debug(1, "Setting env var: %s", evkey);
1345 [ # # # # ]: 0 : if (evkey != NULL && evkey[0] != '\0')
1346 : 0 : setenv(evkey, ucl_object_tostring_forced(cur), 1);
1347 : : }
1348 : :
1349 : : /* Set user-agent */
1350 : 3501 : useragent = pkg_object_string(pkg_config_get("HTTP_USER_AGENT"));
1351 [ + - ]: 3501 : if (useragent != NULL)
1352 : 3501 : setenv("HTTP_USER_AGENT", useragent, 1);
1353 : : else
1354 : 0 : setenv("HTTP_USER_AGENT", "pkg/"PKGVERSION, 1);
1355 : :
1356 : : /* load the repositories */
1357 : 3501 : load_repositories(reposdir, flags, &oi);
1358 : :
1359 : 3501 : object = ucl_object_find_key(config, "REPOSITORIES");
1360 [ + + ]: 3690 : while ((cur = ucl_iterate_object(object, &it, true))) {
1361 : 189 : add_repo_obj(cur, path, flags);
1362 : : }
1363 : :
1364 : : /* validate the different scheme */
1365 [ + + ]: 6851 : while (pkg_repos(&repo) == EPKG_OK) {
1366 : 3350 : object = ucl_object_find_key(config, "VALID_URL_SCHEME");
1367 : 3350 : url = pkg_repo_url(repo);
1368 : 3350 : buf = strstr(url, ":/");
1369 [ + - ]: 3350 : if (buf == NULL) {
1370 : 0 : pkg_emit_error("invalid url: %s", url);
1371 : 0 : err = EPKG_FATAL;
1372 : 0 : goto out;
1373 : : }
1374 : 3350 : fatal_errors = true;
1375 : 3350 : it = NULL;
1376 [ - + ]: 5526 : while ((cur = ucl_iterate_object(object, &it, true))) {
1377 [ + + + + : 16578 : if (strncmp(url, ucl_object_tostring_forced(cur),
+ + ]
1378 : 11052 : buf - url) == 0) {
1379 : 3350 : fatal_errors = false;
1380 : 3350 : break;
1381 : : }
1382 : : }
1383 : :
1384 [ + - ]: 3350 : if (fatal_errors) {
1385 : 0 : pkg_emit_error("invalid scheme %.*s", (int)(buf - url), url);
1386 : 0 : err = EPKG_FATAL;
1387 : 0 : goto out;
1388 : : }
1389 : : }
1390 : :
1391 : : /* bypass resolv.conf with specified NAMESERVER if any */
1392 : 3501 : nsname = pkg_object_string(pkg_config_get("NAMESERVER"));
1393 [ + + + + ]: 3501 : if (nsname != NULL && set_nameserver(nsname) != 0)
1394 : 8 : pkg_emit_error("Unable to set nameserver, ignoring");
1395 : :
1396 : : /* Open metalog */
1397 : 3501 : metalog = pkg_object_string(pkg_config_get("METALOG"));
1398 [ + + ]: 3505 : if (metalog != NULL) {
1399 [ + - ]: 4 : if(metalog_open(metalog) != EPKG_OK) {
1400 : 0 : err = EPKG_FATAL;
1401 : 0 : goto out;
1402 : : }
1403 : 4 : }
1404 : :
1405 : : out:
1406 : 3501 : free(oi.arch);
1407 : 3501 : free(oi.name);
1408 : 3501 : free(oi.version);
1409 : 3501 : free(oi.version_major);
1410 : 3501 : free(oi.version_minor);
1411 : 3501 : return err;
1412 : :
1413 : 3501 : }
1414 : :
1415 : : static struct pkg_repo_ops*
1416 : 6740 : pkg_repo_find_type(const char *type)
1417 : : {
1418 : 6740 : struct pkg_repo_ops *found = NULL, **cur;
1419 : :
1420 : : /* Default repo type */
1421 [ + + ]: 6740 : if (type == NULL)
1422 : 3370 : return (pkg_repo_find_type("binary"));
1423 : :
1424 : 3370 : cur = &repos_ops[0];
1425 [ + + ]: 6740 : while (*cur != NULL) {
1426 [ - + ]: 3370 : if (strcasecmp(type, (*cur)->type) == 0) {
1427 : 3370 : found = *cur;
1428 : 3370 : }
1429 : 3370 : cur ++;
1430 : : }
1431 : :
1432 [ - + ]: 3370 : if (found == NULL)
1433 : 0 : return (pkg_repo_find_type("binary"));
1434 : :
1435 : 3370 : return (found);
1436 : 6740 : }
1437 : :
1438 : : static struct pkg_repo *
1439 : 3350 : pkg_repo_new(const char *name, const char *url, const char *type)
1440 : : {
1441 : : struct pkg_repo *r;
1442 : :
1443 : 3350 : r = xcalloc(1, sizeof(struct pkg_repo));
1444 : 3350 : r->ops = pkg_repo_find_type(type);
1445 : 3350 : r->url = xstrdup(url);
1446 : 3350 : r->signature_type = SIG_NONE;
1447 : 3350 : r->mirror_type = NOMIRROR;
1448 : 3350 : r->enable = true;
1449 : 3350 : r->meta = pkg_repo_meta_default();
1450 : 3350 : r->name = xstrdup(name);
1451 [ + + ]: 3350 : DL_APPEND(repos, r);
1452 : :
1453 : 3350 : return (r);
1454 : : }
1455 : :
1456 : : static void
1457 : 20 : pkg_repo_overwrite(struct pkg_repo *r, const char *name, const char *url,
1458 : : const char *type)
1459 : : {
1460 : :
1461 : 20 : free(r->name);
1462 : 20 : r->name = xstrdup(name);
1463 [ + - ]: 20 : if (url != NULL) {
1464 : 20 : free(r->url);
1465 : 20 : r->url = xstrdup(url);
1466 : 20 : }
1467 : 20 : r->ops = pkg_repo_find_type(type);
1468 : 20 : }
1469 : :
1470 : : static void
1471 : 3350 : pkg_repo_free(struct pkg_repo *r)
1472 : : {
1473 : : struct pkg_kv *kv, *tmp;
1474 : :
1475 : 3350 : free(r->url);
1476 : 3350 : free(r->name);
1477 : 3350 : free(r->pubkey);
1478 : 3350 : free(r->fingerprints);
1479 : 3350 : pkg_repo_meta_free(r->meta);
1480 [ - + ]: 3350 : if (r->ssh != NULL) {
1481 : 0 : fprintf(r->ssh, "quit\n");
1482 : 0 : pclose(r->ssh);
1483 : 0 : }
1484 [ - + + - ]: 3350 : LL_FOREACH_SAFE(r->env, kv, tmp) {
1485 [ # # # # : 0 : LL_DELETE(r->env, kv);
# # # # ]
1486 : 0 : pkg_kv_free(kv);
1487 : 0 : }
1488 : 3350 : free(r);
1489 : 3350 : }
1490 : :
1491 : : void
1492 : 3501 : pkg_shutdown(void)
1493 : : {
1494 [ + - ]: 3501 : if (!parsed) {
1495 : 0 : pkg_emit_error("pkg_shutdown() must be called after pkg_init()");
1496 : 0 : _exit(EXIT_FAILURE);
1497 : : /* NOTREACHED */
1498 : : }
1499 : :
1500 : 3501 : metalog_close();
1501 : 3501 : ucl_object_unref(config);
1502 [ + + + + : 6851 : LL_FREE(repos, pkg_repo_free);
- + # # #
# # # ]
1503 : :
1504 [ - + ]: 3501 : if (ctx.rootfd != -1) {
1505 : 3501 : close(ctx.rootfd);
1506 : 3501 : ctx.rootfd = -1;
1507 : 3501 : }
1508 [ + + ]: 3501 : if (ctx.cachedirfd != -1) {
1509 : 4 : close(ctx.cachedirfd);
1510 : 4 : ctx.cachedirfd = -1;
1511 : 4 : }
1512 [ + + ]: 3501 : if (ctx.pkg_dbdirfd != -1) {
1513 : 1756 : close(ctx.pkg_dbdirfd);
1514 : 1756 : ctx.pkg_dbdirfd = -1;
1515 : 1756 : }
1516 : :
1517 : 3501 : parsed = false;
1518 : :
1519 : 3501 : return;
1520 : : }
1521 : :
1522 : : int
1523 : 1176 : pkg_repos_total_count(void)
1524 : : {
1525 : 1176 : int cnt = 0;
1526 : : struct pkg_repo *r;
1527 : :
1528 [ + + ]: 2291 : LL_COUNT(repos, r, cnt);
1529 : 1176 : return (cnt);
1530 : : }
1531 : :
1532 : : int
1533 : 506 : pkg_repos_activated_count(void)
1534 : : {
1535 : 506 : struct pkg_repo *r = NULL;
1536 : 506 : int count = 0;
1537 : :
1538 [ + + ]: 843 : LL_FOREACH(repos, r) {
1539 [ - + ]: 337 : if (r->enable)
1540 : 337 : count++;
1541 : 337 : }
1542 : :
1543 : 506 : return (count);
1544 : : }
1545 : :
1546 : : int
1547 : 10202 : pkg_repos(struct pkg_repo **r)
1548 : : {
1549 [ + + ]: 10202 : if (*r == NULL)
1550 : 5182 : *r = repos;
1551 : : else
1552 : 5020 : *r = (*r)->next;
1553 [ + + ]: 10202 : if (*r == NULL)
1554 : 5178 : return (EPKG_END);
1555 : 5024 : return (EPKG_OK);
1556 : 10202 : }
1557 : :
1558 : : const char *
1559 : 6580 : pkg_repo_url(struct pkg_repo *r)
1560 : : {
1561 : 6580 : return (r->url);
1562 : : }
1563 : :
1564 : : /* The basename of the sqlite DB file and the database name */
1565 : : const char *
1566 : 5556 : pkg_repo_name(struct pkg_repo *r)
1567 : : {
1568 : 5556 : return (r->name);
1569 : : }
1570 : :
1571 : : const char *
1572 : 71 : pkg_repo_key(struct pkg_repo *r)
1573 : : {
1574 : 71 : return (r->pubkey);
1575 : : }
1576 : :
1577 : : const char *
1578 : 71 : pkg_repo_fingerprints(struct pkg_repo *r)
1579 : : {
1580 : 71 : return (r->fingerprints);
1581 : : }
1582 : :
1583 : : signature_t
1584 : 1070 : pkg_repo_signature_type(struct pkg_repo *r)
1585 : : {
1586 : 1070 : return (r->signature_type);
1587 : : }
1588 : :
1589 : : bool
1590 : 1716 : pkg_repo_enabled(struct pkg_repo *r)
1591 : : {
1592 : 1716 : return (r->enable);
1593 : : }
1594 : :
1595 : : mirror_t
1596 : 110 : pkg_repo_mirror_type(struct pkg_repo *r)
1597 : : {
1598 : 110 : return (r->mirror_type);
1599 : : }
1600 : :
1601 : : unsigned int
1602 : 55 : pkg_repo_priority(struct pkg_repo *r)
1603 : : {
1604 : 55 : return (r->priority);
1605 : : }
1606 : :
1607 : : unsigned int
1608 : 55 : pkg_repo_ip_version(struct pkg_repo *r)
1609 : : {
1610 [ - + ]: 55 : if ((r->flags & PKG_INIT_FLAG_USE_IPV4) == PKG_INIT_FLAG_USE_IPV4)
1611 : 0 : return 4;
1612 [ - + ]: 55 : else if ((r->flags & PKG_INIT_FLAG_USE_IPV6) == PKG_INIT_FLAG_USE_IPV6)
1613 : 0 : return 6;
1614 : : else
1615 : 55 : return 0;
1616 : 55 : }
1617 : :
1618 : : /* Locate the repo by the file basename / database name */
1619 : : struct pkg_repo *
1620 : 3811 : pkg_repo_find(const char *reponame)
1621 : : {
1622 : : struct pkg_repo *r;
1623 : :
1624 [ + + ]: 4050 : LL_FOREACH(repos, r) {
1625 [ + + ]: 660 : if (strcmp(r->name, reponame) == 0)
1626 : 421 : return (r);
1627 : 239 : }
1628 : 3390 : return (NULL);
1629 : 3811 : }
1630 : :
1631 : : int64_t
1632 : 3496 : pkg_set_debug_level(int64_t new_debug_level) {
1633 : 3496 : int64_t old_debug_level = ctx.debug_level;
1634 : :
1635 : 3496 : ctx.debug_level = new_debug_level;
1636 : 3496 : return old_debug_level;
1637 : : }
1638 : :
1639 : : int
1640 : 303 : pkg_set_rootdir(const char *rootdir) {
1641 [ - + ]: 303 : if (pkg_initialized())
1642 : 0 : return (EPKG_FATAL);
1643 : :
1644 [ + - ]: 303 : if (ctx.rootfd != -1)
1645 : 0 : close(ctx.rootfd);
1646 : :
1647 [ - + ]: 303 : if ((ctx.rootfd = open(rootdir, O_DIRECTORY|O_RDONLY|O_CLOEXEC)) < 0) {
1648 : 0 : pkg_emit_error("Impossible to open %s", rootdir);
1649 : 0 : return (EPKG_FATAL);
1650 : : }
1651 : 303 : ctx.pkg_rootdir = rootdir;
1652 : 303 : ctx.defer_triggers = true;
1653 : :
1654 : 303 : return (EPKG_OK);
1655 : 303 : }
1656 : :
1657 : : const char *
1658 : 4 : pkg_get_cachedir(void)
1659 : : {
1660 : :
1661 : 4 : return (ctx.cachedir);
1662 : : }
1663 : :
1664 : : int
1665 : 4 : pkg_get_cachedirfd(void)
1666 : : {
1667 : :
1668 [ + - ]: 4 : if (ctx.cachedirfd == -1) {
1669 : : /*
1670 : : * do not check the value as if we cannot open it means
1671 : : * it has not been created yet
1672 : : */
1673 : 4 : ctx.cachedirfd = open(ctx.cachedir, O_DIRECTORY|O_CLOEXEC);
1674 : 4 : }
1675 : :
1676 : 4 : return (ctx.cachedirfd);
1677 : : }
1678 : :
1679 : : int
1680 : 157469 : pkg_get_dbdirfd(void)
1681 : : {
1682 : :
1683 [ + + ]: 157469 : if (ctx.pkg_dbdirfd == -1) {
1684 : : /*
1685 : : * do not check the value as if we cannot open it means
1686 : : * it has not been created yet
1687 : : */
1688 : 1790 : ctx.pkg_dbdirfd = open(ctx.dbdir, O_DIRECTORY|O_CLOEXEC);
1689 : 1790 : }
1690 : :
1691 : 157469 : return (ctx.pkg_dbdirfd);
1692 : : }
|