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/dports"
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/dports",
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
496 static bool parsed = false;
497 static size_t c_size = NELEM(c);
498
499 static struct pkg_repo* pkg_repo_new(const char *name,
500 const char *url, const char *type);
501 static void pkg_repo_overwrite(struct pkg_repo*, const char *name,
502 const char *url, const char *type);
503 static void pkg_repo_free(struct pkg_repo *r);
504
505 static void
connect_evpipe(const char * evpipe)506 connect_evpipe(const char *evpipe) {
507 struct stat st;
508 struct sockaddr_un sock;
509 int flag = O_WRONLY;
510
511 if (stat(evpipe, &st) != 0) {
512 pkg_emit_error("No such event pipe: %s", evpipe);
513 return;
514 }
515
516 if (!S_ISFIFO(st.st_mode) && !S_ISSOCK(st.st_mode)) {
517 pkg_emit_error("%s is not a fifo or socket", evpipe);
518 return;
519 }
520
521 if (S_ISFIFO(st.st_mode)) {
522 flag |= O_NONBLOCK;
523 if ((ctx.eventpipe = open(evpipe, flag)) == -1)
524 pkg_emit_errno("open event pipe", evpipe);
525 return;
526 }
527
528 if (S_ISSOCK(st.st_mode)) {
529 if ((ctx.eventpipe = socket(AF_UNIX, SOCK_STREAM, 0)) == -1) {
530 pkg_emit_errno("Open event pipe", evpipe);
531 return;
532 }
533 memset(&sock, 0, sizeof(struct sockaddr_un));
534 sock.sun_family = AF_UNIX;
535 if (strlcpy(sock.sun_path, evpipe, sizeof(sock.sun_path)) >=
536 sizeof(sock.sun_path)) {
537 pkg_emit_error("Socket path too long: %s", evpipe);
538 close(ctx.eventpipe);
539 ctx.eventpipe = -1;
540 return;
541 }
542
543 if (connect(ctx.eventpipe, (struct sockaddr *)&sock, SUN_LEN(&sock)) == -1) {
544 pkg_emit_errno("Connect event pipe", evpipe);
545 close(ctx.eventpipe);
546 ctx.eventpipe = -1;
547 return;
548 }
549 }
550
551 }
552
553 int
pkg_initialized(void)554 pkg_initialized(void)
555 {
556 return (parsed);
557 }
558
559 const pkg_object *
pkg_config_get(const char * key)560 pkg_config_get(const char *key) {
561 return (ucl_object_find_key(config, key));
562 }
563
564 char *
pkg_config_dump(void)565 pkg_config_dump(void)
566 {
567 return (pkg_object_dump(config));
568 }
569
570 static void
disable_plugins_if_static(void)571 disable_plugins_if_static(void)
572 {
573 void *dlh;
574
575 dlh = dlopen(0, RTLD_NOW);
576
577 /* if dlh is NULL then we are in static binary */
578 if (dlh == NULL)
579 ucl_object_replace_key(config, ucl_object_frombool(false), "PKG_ENABLE_PLUGINS", 18, false);
580 else
581 dlclose(dlh);
582
583 return;
584 }
585
586 static void
add_repo(const ucl_object_t * obj,struct pkg_repo * r,const char * rname,pkg_init_flags flags)587 add_repo(const ucl_object_t *obj, struct pkg_repo *r, const char *rname, pkg_init_flags flags)
588 {
589 const ucl_object_t *cur, *enabled, *env;
590 ucl_object_iter_t it = NULL;
591 struct pkg_kv *kv;
592 bool enable = true;
593 const char *url = NULL, *pubkey = NULL, *mirror_type = NULL;
594 const char *signature_type = NULL, *fingerprints = NULL;
595 const char *key;
596 const char *type = NULL;
597 int use_ipvx = 0;
598 int priority = 0;
599
600 pkg_debug(1, "PkgConfig: parsing repository object %s", rname);
601
602 env = NULL;
603 enabled = ucl_object_find_key(obj, "enabled");
604 if (enabled == NULL)
605 enabled = ucl_object_find_key(obj, "ENABLED");
606 if (enabled != NULL) {
607 enable = ucl_object_toboolean(enabled);
608 if (!enable && r != NULL) {
609 /*
610 * We basically want to remove the existing repo r and
611 * forget all stuff parsed
612 */
613 pkg_debug(1, "PkgConfig: disabling repo %s", rname);
614 HASH_DEL(repos, r);
615 pkg_repo_free(r);
616 return;
617 }
618 }
619
620 while ((cur = ucl_iterate_object(obj, &it, true))) {
621 key = ucl_object_key(cur);
622 if (key == NULL)
623 continue;
624
625 if (strcasecmp(key, "url") == 0) {
626 if (cur->type != UCL_STRING) {
627 pkg_emit_error("Expecting a string for the "
628 "'%s' key of the '%s' repo",
629 key, rname);
630 return;
631 }
632 url = ucl_object_tostring(cur);
633 } else if (strcasecmp(key, "pubkey") == 0) {
634 if (cur->type != UCL_STRING) {
635 pkg_emit_error("Expecting a string for the "
636 "'%s' key of the '%s' repo",
637 key, rname);
638 return;
639 }
640 pubkey = ucl_object_tostring(cur);
641 } else if (strcasecmp(key, "mirror_type") == 0) {
642 if (cur->type != UCL_STRING) {
643 pkg_emit_error("Expecting a string for the "
644 "'%s' key of the '%s' repo",
645 key, rname);
646 return;
647 }
648 mirror_type = ucl_object_tostring(cur);
649 } else if (strcasecmp(key, "signature_type") == 0) {
650 if (cur->type != UCL_STRING) {
651 pkg_emit_error("Expecting a string for the "
652 "'%s' key of the '%s' repo",
653 key, rname);
654 return;
655 }
656 signature_type = ucl_object_tostring(cur);
657 } else if (strcasecmp(key, "fingerprints") == 0) {
658 if (cur->type != UCL_STRING) {
659 pkg_emit_error("Expecting a string for the "
660 "'%s' key of the '%s' repo",
661 key, rname);
662 return;
663 }
664 fingerprints = ucl_object_tostring(cur);
665 } else if (strcasecmp(key, "type") == 0) {
666 if (cur->type != UCL_STRING) {
667 pkg_emit_error("Expecting a string for the "
668 "'%s' key of the '%s' repo",
669 key, rname);
670 return;
671 }
672 type = ucl_object_tostring(cur);
673 } else if (strcasecmp(key, "ip_version") == 0) {
674 if (cur->type != UCL_INT) {
675 pkg_emit_error("Expecting a integer for the "
676 "'%s' key of the '%s' repo",
677 key, rname);
678 return;
679 }
680 use_ipvx = ucl_object_toint(cur);
681 if (use_ipvx != 4 && use_ipvx != 6)
682 use_ipvx = 0;
683 } else if (strcasecmp(key, "priority") == 0) {
684 if (cur->type != UCL_INT) {
685 pkg_emit_error("Expecting a integer for the "
686 "'%s' key of the '%s' repo",
687 key, rname);
688 return;
689 }
690 priority = ucl_object_toint(cur);
691 } else if (strcasecmp(key, "env") == 0) {
692 if (cur->type != UCL_OBJECT) {
693 pkg_emit_error("Expecting an object for the "
694 "'%s' key of the '%s' repo",
695 key, rname);
696 }
697 env = cur;
698 }
699 }
700
701 if (r == NULL && url == NULL) {
702 pkg_debug(1, "No repo and no url for %s", rname);
703 return;
704 }
705
706 if (r == NULL)
707 r = pkg_repo_new(rname, url, type);
708 else
709 pkg_repo_overwrite(r, rname, url, type);
710
711 if (signature_type != NULL) {
712 if (strcasecmp(signature_type, "pubkey") == 0)
713 r->signature_type = SIG_PUBKEY;
714 else if (strcasecmp(signature_type, "fingerprints") == 0)
715 r->signature_type = SIG_FINGERPRINT;
716 else
717 r->signature_type = SIG_NONE;
718 }
719
720
721 if (fingerprints != NULL) {
722 free(r->fingerprints);
723 r->fingerprints = xstrdup(fingerprints);
724 }
725
726 if (pubkey != NULL) {
727 free(r->pubkey);
728 r->pubkey = xstrdup(pubkey);
729 }
730
731 r->enable = enable;
732 r->priority = priority;
733
734 if (mirror_type != NULL) {
735 if (strcasecmp(mirror_type, "srv") == 0)
736 r->mirror_type = SRV;
737 else if (strcasecmp(mirror_type, "http") == 0)
738 r->mirror_type = HTTP;
739 else
740 r->mirror_type = NOMIRROR;
741 }
742
743 if ((flags & PKG_INIT_FLAG_USE_IPV4) == PKG_INIT_FLAG_USE_IPV4)
744 use_ipvx = 4;
745 else if ((flags & PKG_INIT_FLAG_USE_IPV6) == PKG_INIT_FLAG_USE_IPV6)
746 use_ipvx = 6;
747
748 if (use_ipvx != 4 && use_ipvx != 6)
749 use_ipvx = pkg_object_int(pkg_config_get("IP_VERSION"));
750
751 if (use_ipvx == 4)
752 r->flags = REPO_FLAGS_USE_IPV4;
753 else if (use_ipvx == 6)
754 r->flags = REPO_FLAGS_USE_IPV6;
755
756 if (env != NULL) {
757 it = NULL;
758 while ((cur = ucl_iterate_object(env, &it, true))) {
759 kv = pkg_kv_new(ucl_object_key(cur),
760 ucl_object_tostring_forced(cur));
761 DL_APPEND(r->env, kv);
762 }
763 }
764 }
765
766 static void
add_repo_obj(const ucl_object_t * obj,const char * file,pkg_init_flags flags)767 add_repo_obj(const ucl_object_t *obj, const char *file, pkg_init_flags flags)
768 {
769 struct pkg_repo *r;
770 const char *key;
771
772 key = ucl_object_key(obj);
773 pkg_debug(1, "PkgConfig: parsing repo key '%s' in file '%s'", key, file);
774 r = pkg_repo_find(key);
775 if (r != NULL)
776 pkg_debug(1, "PkgConfig: overwriting repository %s", key);
777 add_repo(obj, r, key, flags);
778 }
779
780 static void
walk_repo_obj(const ucl_object_t * obj,const char * file,pkg_init_flags flags)781 walk_repo_obj(const ucl_object_t *obj, const char *file, pkg_init_flags flags)
782 {
783 const ucl_object_t *cur;
784 ucl_object_iter_t it = NULL;
785 struct pkg_repo *r;
786 const char *key;
787
788 while ((cur = ucl_iterate_object(obj, &it, true))) {
789 key = ucl_object_key(cur);
790 pkg_debug(1, "PkgConfig: parsing key '%s'", key);
791 r = pkg_repo_find(key);
792 if (r != NULL)
793 pkg_debug(1, "PkgConfig: overwriting repository %s", key);
794 if (cur->type == UCL_OBJECT)
795 add_repo(cur, r, key, flags);
796 else
797 pkg_emit_error("Ignoring bad configuration entry in %s: %s",
798 file, ucl_object_emit(cur, UCL_EMIT_YAML));
799 }
800 }
801
802 static void
load_repo_file(int dfd,const char * repodir,const char * repofile,pkg_init_flags flags,struct os_info * oi)803 load_repo_file(int dfd, const char *repodir, const char *repofile,
804 pkg_init_flags flags, struct os_info *oi)
805 {
806 struct ucl_parser *p;
807 ucl_object_t *obj = NULL;
808 const char *myarch = NULL;
809 const char *myarch_legacy = NULL;
810 int fd;
811
812 p = ucl_parser_new(0);
813
814 myarch = pkg_object_string(pkg_config_get("ABI"));
815 ucl_parser_register_variable (p, "ABI", myarch);
816
817 myarch_legacy = pkg_object_string(pkg_config_get("ALTABI"));
818 ucl_parser_register_variable (p, "ALTABI", myarch_legacy);
819 #ifdef __FreeBSD__
820 ucl_parser_register_variable(p, "OSVERSION", myosversion);
821 #endif
822 if (oi->name != NULL) {
823 ucl_parser_register_variable(p, "OSNAME", oi->name);
824 }
825 if (oi->version != NULL) {
826 ucl_parser_register_variable(p, "RELEASE", oi->version);
827 }
828 if (oi->version_major != NULL) {
829 ucl_parser_register_variable(p, "VERSION_MAJOR", oi->version_major);
830 }
831 if (oi->version_minor != NULL) {
832 ucl_parser_register_variable(p, "VERSION_MINOR", oi->version_minor);
833 }
834 if (oi->arch != NULL) {
835 ucl_parser_register_variable(p, "ARCH", oi->arch);
836 }
837
838 errno = 0;
839 obj = NULL;
840
841 pkg_debug(1, "PKgConfig: loading %s/%s", repodir, repofile);
842 fd = openat(dfd, repofile, O_RDONLY);
843 if (fd == -1) {
844 pkg_errno("Unable to open '%s/%s'", repodir, repofile);
845 return;
846 }
847 if (!ucl_parser_add_fd(p, fd)) {
848 pkg_emit_error("Error parsing: '%s/%s': %s", repodir,
849 repofile, ucl_parser_get_error(p));
850 ucl_parser_free(p);
851 close(fd);
852 return;
853 }
854 close(fd);
855
856 obj = ucl_parser_get_object(p);
857 if (obj == NULL)
858 return;
859
860 if (obj->type == UCL_OBJECT)
861 walk_repo_obj(obj, repofile, flags);
862
863 ucl_object_unref(obj);
864 }
865
866 static int
configfile(const struct dirent * dp)867 configfile(const struct dirent *dp)
868 {
869 const char *p;
870 size_t n;
871
872 if (dp->d_name[0] == '.')
873 return (0);
874
875 n = strlen(dp->d_name);
876 if (n <= 5)
877 return (0);
878
879 p = &dp->d_name[n - 5];
880 if (strcmp(p, ".conf") != 0)
881 return (0);
882 return (1);
883 }
884
885 static void
load_repo_files(const char * repodir,pkg_init_flags flags,struct os_info * oi)886 load_repo_files(const char *repodir, pkg_init_flags flags, struct os_info *oi)
887 {
888 struct dirent **ent;
889 int nents, i, fd;
890
891 pkg_debug(1, "PkgConfig: loading repositories in %s", repodir);
892 if ((fd = open(repodir, O_DIRECTORY|O_CLOEXEC)) == -1)
893 return;
894
895 nents = scandir(repodir, &ent, configfile, alphasort);
896 for (i = 0; i < nents; i++) {
897 load_repo_file(fd, repodir, ent[i]->d_name, flags, oi);
898 free(ent[i]);
899 }
900 if (nents >= 0)
901 free(ent);
902 close(fd);
903 }
904
905 static void
load_repositories(const char * repodir,pkg_init_flags flags,struct os_info * oi)906 load_repositories(const char *repodir, pkg_init_flags flags, struct os_info *oi)
907 {
908 const pkg_object *reposlist, *cur;
909 pkg_iter it = NULL;
910
911 if (repodir != NULL) {
912 load_repo_files(repodir, flags, oi);
913 return;
914 }
915
916 reposlist = pkg_config_get("REPOS_DIR");
917 while ((cur = pkg_object_iterate(reposlist, &it)))
918 load_repo_files(pkg_object_string(cur), flags, oi);
919 }
920
921 bool
pkg_compiled_for_same_os_major(void)922 pkg_compiled_for_same_os_major(void)
923 {
924 #ifdef OSMAJOR
925 const char *myabi;
926 int osmajor;
927
928 if (getenv("IGNORE_OSMAJOR") != NULL)
929 return (true);
930
931 myabi = pkg_object_string(pkg_config_get("ABI"));
932 myabi = strchr(myabi,':');
933 if (myabi == NULL) {
934 pkg_emit_error("Invalid ABI");
935 return (false);
936 }
937 myabi++;
938
939 osmajor = (int) strtol(myabi, NULL, 10);
940
941 return (osmajor == OSMAJOR);
942 #else
943 return (true); /* Can't tell, so assume yes */
944 #endif
945 }
946
947
948 int
pkg_init(const char * path,const char * reposdir)949 pkg_init(const char *path, const char *reposdir)
950 {
951 return (pkg_ini(path, reposdir, 0));
952 }
953
954 static const char *
type_to_string(int type)955 type_to_string(int type)
956 {
957 if (type == UCL_ARRAY)
958 return ("array");
959 if (type == UCL_OBJECT)
960 return ("object");
961 if (type == UCL_STRING)
962 return ("string");
963 if (type == UCL_INT)
964 return ("integer");
965 if (type == UCL_BOOLEAN)
966 return ("boolean");
967 return ("unknown");
968 }
969 int
pkg_ini(const char * path,const char * reposdir,pkg_init_flags flags)970 pkg_ini(const char *path, const char *reposdir, pkg_init_flags flags)
971 {
972 struct ucl_parser *p = NULL;
973 size_t i;
974 const char *val = NULL;
975 const char *buf, *walk, *value, *key, *k;
976 const char *evkey = NULL;
977 const char *nsname = NULL;
978 const char *metalog = NULL;
979 const char *useragent = NULL;
980 const char *evpipe = NULL;
981 const char *url;
982 struct pkg_repo *repo = NULL;
983 const ucl_object_t *cur, *object;
984 ucl_object_t *obj = NULL, *o, *ncfg;
985 ucl_object_iter_t it = NULL;
986 xstring *ukey = NULL;
987 bool fatal_errors = false;
988 int conffd = -1;
989 char *tmp = NULL;
990 struct os_info oi;
991 size_t ukeylen;
992 int err = EPKG_OK;
993
994 k = NULL;
995 o = NULL;
996 if (ctx.rootfd == -1 && (ctx.rootfd = open("/", O_DIRECTORY|O_RDONLY|O_CLOEXEC)) < 0) {
997 pkg_emit_error("Impossible to open /");
998 /* Note: Not goto out since oi.arch hasn't been initialized yet. */
999 return (EPKG_FATAL);
1000 }
1001
1002 memset(&oi, 0, sizeof(oi));
1003 pkg_get_myarch(myabi, BUFSIZ, &oi);
1004 pkg_get_myarch_legacy(myabi_legacy, BUFSIZ);
1005 #ifdef __FreeBSD__
1006 ctx.osversion = oi.osversion;
1007 snprintf(myosversion, sizeof(myosversion), "%d", ctx.osversion);
1008 #endif
1009 if (parsed != false) {
1010 pkg_emit_error("pkg_init() must only be called once");
1011 err = EPKG_FATAL;
1012 goto out;
1013 }
1014
1015 if (((flags & PKG_INIT_FLAG_USE_IPV4) == PKG_INIT_FLAG_USE_IPV4) &&
1016 ((flags & PKG_INIT_FLAG_USE_IPV6) == PKG_INIT_FLAG_USE_IPV6)) {
1017 pkg_emit_error("Invalid flags for pkg_init()");
1018 err = EPKG_FATAL;
1019 goto out;
1020 }
1021
1022 config = ucl_object_typed_new(UCL_OBJECT);
1023
1024 for (i = 0; i < c_size; i++) {
1025 switch (c[i].type) {
1026 case PKG_STRING:
1027 tmp = NULL;
1028 if (c[i].def != NULL && c[i].def[0] == '/' &&
1029 ctx.pkg_rootdir != NULL) {
1030 xasprintf(&tmp, "%s%s", ctx.pkg_rootdir, c[i].def);
1031 }
1032 obj = ucl_object_fromstring_common(
1033 c[i].def != NULL ? tmp != NULL ? tmp : c[i].def : "", 0, UCL_STRING_TRIM);
1034 free(tmp);
1035 ucl_object_insert_key(config, obj,
1036 c[i].key, strlen(c[i].key), false);
1037 break;
1038 case PKG_INT:
1039 ucl_object_insert_key(config,
1040 ucl_object_fromstring_common(c[i].def, 0, UCL_STRING_PARSE_INT),
1041 c[i].key, strlen(c[i].key), false);
1042 break;
1043 case PKG_BOOL:
1044 ucl_object_insert_key(config,
1045 ucl_object_fromstring_common(c[i].def, 0, UCL_STRING_PARSE_BOOLEAN),
1046 c[i].key, strlen(c[i].key), false);
1047 break;
1048 case PKG_OBJECT:
1049 obj = ucl_object_typed_new(UCL_OBJECT);
1050 if (c[i].def != NULL) {
1051 walk = buf = c[i].def;
1052 while ((buf = strchr(buf, ',')) != NULL) {
1053 key = walk;
1054 value = walk;
1055 while (*value != ',') {
1056 if (*value == '=')
1057 break;
1058 value++;
1059 }
1060 ucl_object_insert_key(obj,
1061 ucl_object_fromstring_common(value + 1, buf - value - 1, UCL_STRING_TRIM),
1062 key, value - key, false);
1063 buf++;
1064 walk = buf;
1065 }
1066 key = walk;
1067 value = walk;
1068 while (*value != ',') {
1069 if (*value == '=')
1070 break;
1071 value++;
1072 }
1073 if (o == NULL)
1074 o = ucl_object_typed_new(UCL_OBJECT);
1075 ucl_object_insert_key(o,
1076 ucl_object_fromstring_common(value + 1, strlen(value + 1), UCL_STRING_TRIM),
1077 key, value - key, false);
1078 }
1079 ucl_object_insert_key(config, obj,
1080 c[i].key, strlen(c[i].key), false);
1081 break;
1082 case PKG_ARRAY:
1083 obj = ucl_object_typed_new(UCL_ARRAY);
1084 if (c[i].def != NULL) {
1085 walk = buf = c[i].def;
1086 while ((buf = strchr(buf, ',')) != NULL) {
1087 ucl_array_append(obj,
1088 ucl_object_fromstring_common(walk, buf - walk, UCL_STRING_TRIM));
1089 buf++;
1090 walk = buf;
1091 }
1092 ucl_array_append(obj,
1093 ucl_object_fromstring_common(walk, strlen(walk), UCL_STRING_TRIM));
1094 }
1095 ucl_object_insert_key(config, obj,
1096 c[i].key, strlen(c[i].key), false);
1097 break;
1098 }
1099 }
1100
1101 if (path == NULL)
1102 conffd = openat(ctx.rootfd, &PREFIX"/etc/pkg.conf"[1], 0);
1103 else
1104 conffd = open(path, O_RDONLY);
1105 if (conffd == -1 && errno != ENOENT) {
1106 pkg_errno("Cannot open %s/%s",
1107 ctx.pkg_rootdir != NULL ? ctx.pkg_rootdir : "",
1108 path);
1109 }
1110
1111 p = ucl_parser_new(0);
1112 ucl_parser_register_variable (p, "ABI", myabi);
1113 ucl_parser_register_variable (p, "ALTABI", myabi_legacy);
1114 #ifdef __FreeBSD__
1115 ucl_parser_register_variable(p, "OSVERSION", myosversion);
1116 #endif
1117 if (oi.name != NULL) {
1118 ucl_parser_register_variable(p, "OSNAME", oi.name);
1119 }
1120 if (oi.version != NULL) {
1121 ucl_parser_register_variable(p, "RELEASE", oi.version);
1122 }
1123 if (oi.version_major != NULL) {
1124 ucl_parser_register_variable(p, "VERSION_MAJOR", oi.version_major);
1125 }
1126 if (oi.version_minor != NULL) {
1127 ucl_parser_register_variable(p, "VERSION_MINOR", oi.version_minor);
1128 }
1129 if (oi.arch != NULL) {
1130 ucl_parser_register_variable(p, "ARCH", oi.arch);
1131 }
1132
1133 errno = 0;
1134 obj = NULL;
1135 if (conffd != -1) {
1136 if (!ucl_parser_add_fd(p, conffd)) {
1137 pkg_emit_error("Invalid configuration file: %s", ucl_parser_get_error(p));
1138 }
1139 close(conffd);
1140 }
1141
1142 obj = ucl_parser_get_object(p);
1143 ncfg = NULL;
1144 ukey = NULL;
1145 while (obj != NULL && (cur = ucl_iterate_object(obj, &it, true))) {
1146 xstring_renew(ukey);
1147 key = ucl_object_key(cur);
1148 for (i = 0; key[i] != '\0'; i++)
1149 fputc(toupper(key[i]), ukey->fp);
1150 fflush(ukey->fp);
1151 ukeylen = strlen(ukey->buf);
1152 object = ucl_object_find_keyl(config, ukey->buf, ukeylen);
1153
1154 if (strncasecmp(ukey->buf, "PACKAGESITE", ukeylen) == 0 ||
1155 strncasecmp(ukey->buf, "PUBKEY", ukeylen) == 0 ||
1156 strncasecmp(ukey->buf, "MIRROR_TYPE", ukeylen) == 0) {
1157 pkg_emit_error("%s in pkg.conf is no longer "
1158 "supported. Convert to the new repository style."
1159 " See pkg.conf(5)", ukey->buf);
1160 fatal_errors = true;
1161 continue;
1162 }
1163
1164 /* ignore unknown keys */
1165 if (object == NULL)
1166 continue;
1167
1168 if (object->type != cur->type) {
1169 pkg_emit_error("Malformed key %s, got '%s' expecting "
1170 "'%s', ignoring", key,
1171 type_to_string(cur->type),
1172 type_to_string(object->type));
1173 continue;
1174 }
1175
1176 if (ncfg == NULL)
1177 ncfg = ucl_object_typed_new(UCL_OBJECT);
1178 ucl_object_insert_key(ncfg, ucl_object_copy(cur), ukey->buf,
1179 ukeylen, true);
1180 }
1181 xstring_free(ukey);
1182
1183 if (fatal_errors) {
1184 ucl_object_unref(ncfg);
1185 ucl_parser_free(p);
1186 err = EPKG_FATAL;
1187 goto out;
1188 }
1189
1190 if (ncfg != NULL) {
1191 it = NULL;
1192 while (( cur = ucl_iterate_object(ncfg, &it, true))) {
1193 key = ucl_object_key(cur);
1194 ucl_object_replace_key(config, ucl_object_ref(cur), key, strlen(key), true);
1195 }
1196 }
1197
1198 ncfg = NULL;
1199 it = NULL;
1200 while ((cur = ucl_iterate_object(config, &it, true))) {
1201 o = NULL;
1202 key = ucl_object_key(cur);
1203 val = getenv(key);
1204 if (val == NULL)
1205 continue;
1206 switch (cur->type) {
1207 case UCL_STRING:
1208 o = ucl_object_fromstring_common(val, 0, UCL_STRING_TRIM);
1209 break;
1210 case UCL_INT:
1211 o = ucl_object_fromstring_common(val, 0, UCL_STRING_PARSE_INT);
1212 if (o->type != UCL_INT) {
1213 pkg_emit_error("Invalid type for environment "
1214 "variable %s, got %s, while expecting an integer",
1215 key, val);
1216 ucl_object_unref(o);
1217 continue;
1218 }
1219 break;
1220 case UCL_BOOLEAN:
1221 o = ucl_object_fromstring_common(val, 0, UCL_STRING_PARSE_BOOLEAN);
1222 if (o->type != UCL_BOOLEAN) {
1223 pkg_emit_error("Invalid type for environment "
1224 "variable %s, got %s, while expecting a boolean",
1225 key, val);
1226 ucl_object_unref(o);
1227 continue;
1228 }
1229 break;
1230 case UCL_OBJECT:
1231 o = ucl_object_typed_new(UCL_OBJECT);
1232 walk = buf = val;
1233 while ((buf = strchr(buf, ',')) != NULL) {
1234 k = walk;
1235 value = walk;
1236 while (*value != ',') {
1237 if (*value == '=')
1238 break;
1239 value++;
1240 }
1241 ucl_object_insert_key(o,
1242 ucl_object_fromstring_common(value + 1, buf - value - 1, UCL_STRING_TRIM),
1243 k, value - k, false);
1244 buf++;
1245 walk = buf;
1246 }
1247 k = walk;
1248 value = walk;
1249 while (*value != '\0') {
1250 if (*value == '=')
1251 break;
1252 value++;
1253 }
1254 ucl_object_insert_key(o,
1255 ucl_object_fromstring_common(value + 1, strlen(value + 1), UCL_STRING_TRIM),
1256 k, value - k, false);
1257 break;
1258 case UCL_ARRAY:
1259 o = ucl_object_typed_new(UCL_ARRAY);
1260 walk = buf = val;
1261 while ((buf = strchr(buf, ',')) != NULL) {
1262 ucl_array_append(o,
1263 ucl_object_fromstring_common(walk, buf - walk, UCL_STRING_TRIM));
1264 buf++;
1265 walk = buf;
1266 }
1267 ucl_array_append(o,
1268 ucl_object_fromstring_common(walk, strlen(walk), UCL_STRING_TRIM));
1269 break;
1270 default:
1271 /* ignore other types */
1272 break;
1273 }
1274 if (o != NULL) {
1275 if (ncfg == NULL)
1276 ncfg = ucl_object_typed_new(UCL_OBJECT);
1277 ucl_object_insert_key(ncfg, o, key, strlen(key), true);
1278 }
1279 }
1280
1281 if (ncfg != NULL) {
1282 it = NULL;
1283 while (( cur = ucl_iterate_object(ncfg, &it, true))) {
1284 key = ucl_object_key(cur);
1285 ucl_object_replace_key(config, ucl_object_ref(cur), key, strlen(key), true);
1286 }
1287 ucl_object_unref(ncfg);
1288 }
1289
1290 disable_plugins_if_static();
1291
1292 parsed = true;
1293 ucl_object_unref(obj);
1294 ucl_parser_free(p);
1295
1296 if (pkg_object_string(pkg_config_get("ABI")) == NULL ||
1297 strcmp(pkg_object_string(pkg_config_get("ABI")), "unknown") == 0) {
1298 pkg_emit_error("Unable to determine ABI");
1299 err = EPKG_FATAL;
1300 goto out;
1301 }
1302
1303 pkg_debug(1, "%s", "pkg initialized");
1304
1305 #ifdef __FreeBSD__
1306 ctx.osversion = pkg_object_int(pkg_config_get("OSVERSION"));
1307 #endif
1308 /* Start the event pipe */
1309 evpipe = pkg_object_string(pkg_config_get("EVENT_PIPE"));
1310 if (evpipe != NULL)
1311 connect_evpipe(evpipe);
1312
1313 ctx.debug_level = pkg_object_int(pkg_config_get("DEBUG_LEVEL"));
1314 ctx.developer_mode = pkg_object_bool(pkg_config_get("DEVELOPER_MODE"));
1315 ctx.dbdir = pkg_object_string(pkg_config_get("PKG_DBDIR"));
1316 ctx.cachedir = pkg_object_string(pkg_config_get("PKG_CACHEDIR"));
1317 ctx.backup_libraries = pkg_object_bool(pkg_config_get("BACKUP_LIBRARIES"));
1318 ctx.backup_library_path = pkg_object_string(pkg_config_get("BACKUP_LIBRARY_PATH"));
1319 ctx.triggers = pkg_object_bool(pkg_config_get("PKG_TRIGGERS_ENABLE"));
1320 ctx.triggers_path = pkg_object_string(pkg_config_get("PKG_TRIGGERS_DIR"));
1321 ctx.compression_level = pkg_object_int(pkg_config_get("COMPRESSION_LEVEL"));
1322 ctx.archive_symlink = pkg_object_bool(pkg_config_get("ARCHIVE_SYMLINK"));
1323 ctx.repo_accept_legacy_pkg = pkg_object_bool(pkg_config_get("REPO_ACCEPT_LEGACY_PKG"));
1324
1325 it = NULL;
1326 object = ucl_object_find_key(config, "PKG_ENV");
1327 while ((cur = ucl_iterate_object(object, &it, true))) {
1328 evkey = ucl_object_key(cur);
1329 pkg_debug(1, "Setting env var: %s", evkey);
1330 if (evkey != NULL && evkey[0] != '\0')
1331 setenv(evkey, ucl_object_tostring_forced(cur), 1);
1332 }
1333
1334 /* Set user-agent */
1335 useragent = pkg_object_string(pkg_config_get("HTTP_USER_AGENT"));
1336 if (useragent != NULL)
1337 setenv("HTTP_USER_AGENT", useragent, 1);
1338 else
1339 setenv("HTTP_USER_AGENT", "pkg/"PKGVERSION, 1);
1340
1341 /* load the repositories */
1342 load_repositories(reposdir, flags, &oi);
1343
1344 object = ucl_object_find_key(config, "REPOSITORIES");
1345 while ((cur = ucl_iterate_object(object, &it, true))) {
1346 add_repo_obj(cur, path, flags);
1347 }
1348
1349 /* validate the different scheme */
1350 while (pkg_repos(&repo) == EPKG_OK) {
1351 object = ucl_object_find_key(config, "VALID_URL_SCHEME");
1352 url = pkg_repo_url(repo);
1353 buf = strstr(url, ":/");
1354 if (buf == NULL) {
1355 pkg_emit_error("invalid url: %s", url);
1356 err = EPKG_FATAL;
1357 goto out;
1358 }
1359 fatal_errors = true;
1360 it = NULL;
1361 while ((cur = ucl_iterate_object(object, &it, true))) {
1362 if (strncmp(url, ucl_object_tostring_forced(cur),
1363 buf - url) == 0) {
1364 fatal_errors = false;
1365 break;
1366 }
1367 }
1368
1369 if (fatal_errors) {
1370 pkg_emit_error("invalid scheme %.*s", (int)(buf - url), url);
1371 err = EPKG_FATAL;
1372 goto out;
1373 }
1374 }
1375
1376 /* bypass resolv.conf with specified NAMESERVER if any */
1377 nsname = pkg_object_string(pkg_config_get("NAMESERVER"));
1378 if (nsname != NULL && set_nameserver(nsname) != 0)
1379 pkg_emit_error("Unable to set nameserver, ignoring");
1380
1381 /* Open metalog */
1382 metalog = pkg_object_string(pkg_config_get("METALOG"));
1383 if (metalog != NULL) {
1384 if(metalog_open(metalog) != EPKG_OK) {
1385 err = EPKG_FATAL;
1386 goto out;
1387 }
1388 }
1389
1390 out:
1391 free(oi.arch);
1392 free(oi.name);
1393 return err;
1394
1395 }
1396
1397 static struct pkg_repo_ops*
pkg_repo_find_type(const char * type)1398 pkg_repo_find_type(const char *type)
1399 {
1400 struct pkg_repo_ops *found = NULL, **cur;
1401
1402 /* Default repo type */
1403 if (type == NULL)
1404 return (pkg_repo_find_type("binary"));
1405
1406 cur = &repos_ops[0];
1407 while (*cur != NULL) {
1408 if (strcasecmp(type, (*cur)->type) == 0) {
1409 found = *cur;
1410 }
1411 cur ++;
1412 }
1413
1414 if (found == NULL)
1415 return (pkg_repo_find_type("binary"));
1416
1417 return (found);
1418 }
1419
1420 static struct pkg_repo *
pkg_repo_new(const char * name,const char * url,const char * type)1421 pkg_repo_new(const char *name, const char *url, const char *type)
1422 {
1423 struct pkg_repo *r;
1424
1425 r = xcalloc(1, sizeof(struct pkg_repo));
1426 r->ops = pkg_repo_find_type(type);
1427 r->url = xstrdup(url);
1428 r->signature_type = SIG_NONE;
1429 r->mirror_type = NOMIRROR;
1430 r->enable = true;
1431 r->meta = pkg_repo_meta_default();
1432 r->name = xstrdup(name);
1433 HASH_ADD_KEYPTR(hh, repos, r->name, strlen(r->name), r);
1434
1435 return (r);
1436 }
1437
1438 static void
pkg_repo_overwrite(struct pkg_repo * r,const char * name,const char * url,const char * type)1439 pkg_repo_overwrite(struct pkg_repo *r, const char *name, const char *url,
1440 const char *type)
1441 {
1442
1443 free(r->name);
1444 r->name = xstrdup(name);
1445 if (url != NULL) {
1446 free(r->url);
1447 r->url = xstrdup(url);
1448 }
1449 r->ops = pkg_repo_find_type(type);
1450 HASH_DEL(repos, r);
1451 HASH_ADD_KEYPTR(hh, repos, r->name, strlen(r->name), r);
1452 }
1453
1454 static void
pkg_repo_free(struct pkg_repo * r)1455 pkg_repo_free(struct pkg_repo *r)
1456 {
1457 struct pkg_kv *kv, *tmp;
1458
1459 free(r->url);
1460 free(r->name);
1461 free(r->pubkey);
1462 free(r->meta);
1463 if (r->ssh != NULL) {
1464 fprintf(r->ssh, "quit\n");
1465 pclose(r->ssh);
1466 }
1467 LL_FOREACH_SAFE(r->env, kv, tmp) {
1468 LL_DELETE(r->env, kv);
1469 pkg_kv_free(kv);
1470 }
1471 free(r);
1472 }
1473
1474 void
pkg_shutdown(void)1475 pkg_shutdown(void)
1476 {
1477 if (!parsed) {
1478 pkg_emit_error("pkg_shutdown() must be called after pkg_init()");
1479 _exit(EXIT_FAILURE);
1480 /* NOTREACHED */
1481 }
1482
1483 metalog_close();
1484 ucl_object_unref(config);
1485 HASH_FREE(repos, pkg_repo_free);
1486
1487 if (ctx.rootfd != -1) {
1488 close(ctx.rootfd);
1489 ctx.rootfd = -1;
1490 }
1491 if (ctx.cachedirfd != -1) {
1492 close(ctx.cachedirfd);
1493 ctx.cachedirfd = -1;
1494 }
1495 if (ctx.pkg_dbdirfd != -1) {
1496 close(ctx.pkg_dbdirfd);
1497 ctx.pkg_dbdirfd = -1;
1498 }
1499
1500 parsed = false;
1501
1502 return;
1503 }
1504
1505 int
pkg_repos_total_count(void)1506 pkg_repos_total_count(void)
1507 {
1508
1509 return (HASH_COUNT(repos));
1510 }
1511
1512 int
pkg_repos_activated_count(void)1513 pkg_repos_activated_count(void)
1514 {
1515 struct pkg_repo *r = NULL;
1516 int count = 0;
1517
1518 for (r = repos; r != NULL; r = r->hh.next) {
1519 if (r->enable)
1520 count++;
1521 }
1522
1523 return (count);
1524 }
1525
1526 int
pkg_repos(struct pkg_repo ** r)1527 pkg_repos(struct pkg_repo **r)
1528 {
1529 HASH_NEXT(repos, (*r));
1530 }
1531
1532 const char *
pkg_repo_url(struct pkg_repo * r)1533 pkg_repo_url(struct pkg_repo *r)
1534 {
1535 return (r->url);
1536 }
1537
1538 /* The basename of the sqlite DB file and the database name */
1539 const char *
pkg_repo_name(struct pkg_repo * r)1540 pkg_repo_name(struct pkg_repo *r)
1541 {
1542 return (r->name);
1543 }
1544
1545 const char *
pkg_repo_key(struct pkg_repo * r)1546 pkg_repo_key(struct pkg_repo *r)
1547 {
1548 return (r->pubkey);
1549 }
1550
1551 const char *
pkg_repo_fingerprints(struct pkg_repo * r)1552 pkg_repo_fingerprints(struct pkg_repo *r)
1553 {
1554 return (r->fingerprints);
1555 }
1556
1557 signature_t
pkg_repo_signature_type(struct pkg_repo * r)1558 pkg_repo_signature_type(struct pkg_repo *r)
1559 {
1560 return (r->signature_type);
1561 }
1562
1563 bool
pkg_repo_enabled(struct pkg_repo * r)1564 pkg_repo_enabled(struct pkg_repo *r)
1565 {
1566 return (r->enable);
1567 }
1568
1569 mirror_t
pkg_repo_mirror_type(struct pkg_repo * r)1570 pkg_repo_mirror_type(struct pkg_repo *r)
1571 {
1572 return (r->mirror_type);
1573 }
1574
1575 unsigned int
pkg_repo_priority(struct pkg_repo * r)1576 pkg_repo_priority(struct pkg_repo *r)
1577 {
1578 return (r->priority);
1579 }
1580
1581 unsigned int
pkg_repo_ip_version(struct pkg_repo * r)1582 pkg_repo_ip_version(struct pkg_repo *r)
1583 {
1584 if ((r->flags & PKG_INIT_FLAG_USE_IPV4) == PKG_INIT_FLAG_USE_IPV4)
1585 return 4;
1586 else if ((r->flags & PKG_INIT_FLAG_USE_IPV6) == PKG_INIT_FLAG_USE_IPV6)
1587 return 6;
1588 else
1589 return 0;
1590 }
1591
1592 /* Locate the repo by the file basename / database name */
1593 struct pkg_repo *
pkg_repo_find(const char * reponame)1594 pkg_repo_find(const char *reponame)
1595 {
1596 struct pkg_repo *r;
1597
1598 HASH_FIND_STR(repos, reponame, r);
1599 return (r);
1600 }
1601
1602 int64_t
pkg_set_debug_level(int64_t new_debug_level)1603 pkg_set_debug_level(int64_t new_debug_level) {
1604 int64_t old_debug_level = ctx.debug_level;
1605
1606 ctx.debug_level = new_debug_level;
1607 return old_debug_level;
1608 }
1609
1610 int
pkg_set_rootdir(const char * rootdir)1611 pkg_set_rootdir(const char *rootdir) {
1612 if (pkg_initialized())
1613 return (EPKG_FATAL);
1614
1615 if (ctx.rootfd != -1)
1616 close(ctx.rootfd);
1617
1618 if ((ctx.rootfd = open(rootdir, O_DIRECTORY|O_RDONLY|O_CLOEXEC)) < 0) {
1619 pkg_emit_error("Impossible to open %s", rootdir);
1620 return (EPKG_FATAL);
1621 }
1622 ctx.pkg_rootdir = rootdir;
1623 ctx.defer_triggers = true;
1624
1625 return (EPKG_OK);
1626 }
1627
1628 const char *
pkg_get_cachedir(void)1629 pkg_get_cachedir(void)
1630 {
1631
1632 return (ctx.cachedir);
1633 }
1634
1635 int
pkg_get_cachedirfd(void)1636 pkg_get_cachedirfd(void)
1637 {
1638
1639 if (ctx.cachedirfd == -1) {
1640 /*
1641 * do not check the value as if we cannot open it means
1642 * it has not been created yet
1643 */
1644 ctx.cachedirfd = open(ctx.cachedir, O_DIRECTORY|O_CLOEXEC);
1645 }
1646
1647 return (ctx.cachedirfd);
1648 }
1649
1650 int
pkg_get_dbdirfd(void)1651 pkg_get_dbdirfd(void)
1652 {
1653
1654 if (ctx.pkg_dbdirfd == -1) {
1655 /*
1656 * do not check the value as if we cannot open it means
1657 * it has not been created yet
1658 */
1659 ctx.pkg_dbdirfd = open(ctx.dbdir, O_DIRECTORY|O_CLOEXEC);
1660 }
1661
1662 return (ctx.pkg_dbdirfd);
1663 }
1664