static void load_repo_file(const char *repofile, pkg_init_flags flags) { struct ucl_parser *p; ucl_object_t *obj = NULL; const char *myarch = NULL; const char *myarch_legacy = NULL; p = ucl_parser_new(0); myarch = pkg_object_string(pkg_config_get("ABI")); ucl_parser_register_variable (p, "ABI", myarch); myarch_legacy = pkg_object_string(pkg_config_get("ALTABI")); ucl_parser_register_variable (p, "ALTABI", myarch_legacy); pkg_debug(1, "PKgConfig: loading %s", repofile); if (!ucl_parser_add_file(p, repofile)) { pkg_emit_error("Error parsing: %s: %s", repofile, ucl_parser_get_error(p)); ucl_parser_free(p); return; } obj = ucl_parser_get_object(p); if (obj == NULL) return; if (obj->type == UCL_OBJECT) walk_repo_obj(obj, repofile, flags); ucl_object_unref(obj); }
int pkg_delete_dirs(__unused struct pkgdb *db, struct pkg *pkg, bool force) { struct pkg_dir *dir = NULL; ucl_object_t *obj; char fpath[MAXPATHLEN]; while (pkg_dirs(pkg, &dir) == EPKG_OK) { if (dir->keep == 1) continue; obj = pkg_annotation_lookup(pkg, "relocated"); snprintf(fpath, sizeof(fpath), "%s%s", obj ? pkg_object_string(obj) : "" , pkg_dir_path(dir) ); if (pkg_dir_try(dir)) { if (rmdir(fpath) == -1 && errno != ENOTEMPTY && errno != EBUSY && !force) pkg_emit_errno("rmdir", fpath); } else { if (rmdir(fpath) == -1 && !force) pkg_emit_errno("rmdir", fpath); } } return (EPKG_OK); }
bool is_valid_abi(const char *arch, bool emit_error) { const char *myarch, *myarch_legacy; myarch = pkg_object_string(pkg_config_get("ABI")); myarch_legacy = pkg_object_string(pkg_config_get("ALTABI")); if (fnmatch(arch, myarch, FNM_CASEFOLD) == FNM_NOMATCH && strncasecmp(arch, myarch, strlen(myarch)) != 0 && strncasecmp(arch, myarch_legacy, strlen(myarch_legacy)) != 0) { if (emit_error) pkg_emit_error("wrong architecture: %s instead of %s", arch, myarch); return (false); } return (true); }
static int do_show(struct pkg *pkg, const char *tag) { const pkg_object *annotations, *note; pkg_iter it = NULL; int ret = EPKG_OK; pkg_get(pkg, PKG_ANNOTATIONS, &annotations); while ((note = pkg_object_iterate(annotations, &it)) != NULL) { if (strcmp(tag, pkg_object_key(note)) == 0) { if (quiet) printf("%s\n", pkg_object_string(note)); else pkg_printf("%n-%v: Tag: %S Value: %S\n", pkg, pkg, pkg_object_key(note), pkg_object_string(note)); } } return (ret); }
void pkg_cache_full_clean(void) { const char *cachedir; if (!pkg_object_bool(pkg_config_get("AUTOCLEAN"))) return; pkg_debug(1, "Cleaning up cachedir"); cachedir = pkg_object_string(pkg_config_get("PKG_CACHEDIR")); return (rm_rf(cachedir)); }
static void load_repositories(const char *repodir, pkg_init_flags flags) { const pkg_object *reposlist, *cur; pkg_iter it = NULL; if (repodir != NULL) { load_repo_files(repodir, flags); return; } reposlist = pkg_config_get( "REPOS_DIR"); while ((cur = pkg_object_iterate(reposlist, &it))) load_repo_files(pkg_object_string(cur), flags); }
int pkg_repo_binary_access(struct pkg_repo *repo, unsigned mode) { const pkg_object *o; const char *dbdir; int ret = EPKG_OK; o = pkg_config_get("PKG_DBDIR"); dbdir = pkg_object_string(o); ret = pkgdb_check_access(mode, dbdir, pkg_repo_binary_get_filename(pkg_repo_name(repo))); return (ret); }
static void load_repo_file(const char *repofile) { struct ucl_parser *p; ucl_object_t *obj = NULL; bool fallback = false; const char *myarch = NULL; p = ucl_parser_new(0); myarch = pkg_object_string(pkg_config_get("ABI")); ucl_parser_register_variable (p, "ABI", myarch); pkg_debug(1, "PKgConfig: loading %s", repofile); if (!ucl_parser_add_file(p, repofile)) { pkg_emit_error("Error parsing: %s: %s", repofile, ucl_parser_get_error(p)); if (errno == ENOENT) { ucl_parser_free(p); return; } fallback = true; } if (fallback) { obj = yaml_to_ucl(repofile, NULL, 0); if (obj == NULL) return; } if (fallback) { pkg_emit_error("%s file is using a deprecated format. " "Please replace it with the following:\n" "====== BEGIN %s ======\n" "%s" "\n====== END %s ======\n", repofile, repofile, ucl_object_emit(obj, UCL_EMIT_YAML), repofile); } obj = ucl_parser_get_object(p); if (obj->type == UCL_OBJECT) walk_repo_obj(obj, repofile); ucl_object_free(obj); }
int pkg_delete_files(struct pkg *pkg, unsigned force) /* force: 0 ... be careful and vocal about it. * 1 ... remove files without bothering about checksums. * 2 ... like 1, but remain silent if removal fails. */ { struct pkg_file *file = NULL; char sha256[SHA256_DIGEST_LENGTH * 2 + 1]; const char *path; char fpath[MAXPATHLEN]; while (pkg_files(pkg, &file) == EPKG_OK) { const char *sum = pkg_file_cksum(file); ucl_object_t *obj; if (file->keep == 1) continue; path = pkg_file_path(file); obj = pkg_annotation_lookup(pkg, "relocated"); snprintf(fpath, sizeof(fpath), "%s%s", obj ? pkg_object_string(obj) : "" , path ); /* Regular files and links */ /* check sha256 */ if (!force && sum[0] != '\0') { if (sha256_file(fpath, sha256) != EPKG_OK) continue; if (strcmp(sha256, sum)) { pkg_emit_error("%s fails original SHA256 " "checksum, not removing", path); continue; } } if (unlink(fpath) == -1) { if (force < 2) pkg_emit_errno("unlink", fpath); continue; } } return (EPKG_OK); }
bool pkg_compiled_for_same_os_major(void) { #ifdef OSMAJOR const char *myabi; int osmajor; myabi = pkg_object_string(pkg_config_get("ABI")); myabi = strchr(myabi,':'); myabi++; osmajor = (int) strtol(myabi, NULL, 10); return (osmajor == OSMAJOR); #else return (true); /* Can't tell, so assume yes */ #endif }
int pkg_repo_binary_get_cached_name(struct pkg_repo *repo, struct pkg *pkg, char *dest, size_t destlen) { const char *ext = NULL; const char *cachedir = NULL; const char *packagesite; struct stat st; cachedir = pkg_object_string(pkg_config_get("PKG_CACHEDIR")); packagesite = pkg_repo_url(repo); if (strncmp(packagesite, "file://", 7) == 0) { snprintf(dest, destlen, "%s/%s", packagesite + 7, pkg->repopath); return (EPKG_OK); } if (pkg->repopath != NULL) ext = strrchr(pkg->repopath, '.'); if (ext != NULL) { /* * The real naming scheme: * <cachedir>/<name>-<version>-<checksum>.txz */ pkg_snprintf(dest, destlen, "%S/%n-%v-%z%S", cachedir, pkg, pkg, pkg, ext); if (stat (dest, &st) == -1 || pkg->pkgsize != st.st_size) return (EPKG_FATAL); } else { pkg_snprintf(dest, destlen, "%S/%n-%v-%z", cachedir, pkg, pkg, pkg); } return (EPKG_OK); }
void pkg_repo_binary_get_cached_name(struct pkg_repo *repo, struct pkg *pkg, char *dest, size_t destlen) { const char *sum, *name, *version, *repourl, *ext = NULL; const char *cachedir = NULL; struct stat st; cachedir = pkg_object_string(pkg_config_get("PKG_CACHEDIR")); pkg_get(pkg, PKG_CKSUM, &sum, PKG_NAME, &name, PKG_VERSION, &version, PKG_REPOPATH, &repourl); if (repourl != NULL) ext = strrchr(repourl, '.'); if (ext != NULL) { /* * XXX: * This code tries to skip refetching but it should be removed as soon * as we transfer to new scheme. */ pkg_snprintf(dest, destlen, "%S/%n-%v-%z", cachedir, pkg, pkg, pkg); if (stat (dest, &st) != -1) return; /* * The real naming scheme: * <cachedir>/<name>-<version>-<checksum>.txz */ pkg_snprintf(dest, destlen, "%S/%n-%v-%z%S", cachedir, pkg, pkg, pkg, ext); } else { pkg_snprintf(dest, destlen, "%S/%n-%v-%z", cachedir, pkg, pkg, pkg); } }
int exec_audit(int argc, char **argv) { struct pkg_audit *audit; struct pkgdb *db = NULL; struct pkgdb_it *it = NULL; struct pkg *pkg = NULL; const char *db_dir; char *name; char *version; char audit_file_buf[MAXPATHLEN]; char *audit_file = audit_file_buf; unsigned int vuln = 0; bool fetch = false, recursive = false; int ch, i; int ret = EX_OK; const char *portaudit_site = NULL; struct sbuf *sb; kh_pkgs_t *check = NULL; db_dir = pkg_object_string(pkg_config_get("PKG_DBDIR")); snprintf(audit_file_buf, sizeof(audit_file_buf), "%s/vuln.xml", db_dir); struct option longopts[] = { { "fetch", no_argument, NULL, 'F' }, { "file", required_argument, NULL, 'f' }, { "recursive", no_argument, NULL, 'r' }, { "quiet", no_argument, NULL, 'q' }, { NULL, 0, NULL, 0 }, }; while ((ch = getopt_long(argc, argv, "+Ff:qr", longopts, NULL)) != -1) { switch (ch) { case 'F': fetch = true; break; case 'f': audit_file = optarg; break; case 'q': quiet = true; break; case 'r': recursive = true; break; default: usage_audit(); return(EX_USAGE); } } argc -= optind; argv += optind; audit = pkg_audit_new(); if (fetch == true) { portaudit_site = pkg_object_string(pkg_config_get("VULNXML_SITE")); if (pkg_audit_fetch(portaudit_site, audit_file) != EPKG_OK) { pkg_audit_free(audit); return (EX_IOERR); } } if (pkg_audit_load(audit, audit_file) != EPKG_OK) { if (errno == ENOENT) warnx("vulnxml file %s does not exist. " "Try running 'pkg audit -F' first", audit_file); else warn("unable to open vulnxml file %s", audit_file); pkg_audit_free(audit); return (EX_DATAERR); } check = kh_init_pkgs(); if (argc >= 1) { for (i = 0; i < argc; i ++) { name = argv[i]; version = strrchr(name, '-'); if (version != NULL) { version[0] = '\0'; version++; } if (pkg_new(&pkg, PKG_FILE) != EPKG_OK) err(EX_OSERR, "malloc"); if (version != NULL) pkg_set(pkg, PKG_NAME, name, PKG_VERSION, version); else pkg_set(pkg, PKG_NAME, name); /* Fake uniqueid */ pkg_set(pkg, PKG_UNIQUEID, name); add_to_check(check, pkg); pkg = NULL; } } else { /* * if the database doesn't exist it just means there are no * packages to audit. */ ret = pkgdb_access(PKGDB_MODE_READ, PKGDB_DB_LOCAL); if (ret == EPKG_ENODB) { pkg_audit_free(audit); kh_destroy_pkgs(check); return (EX_OK); } else if (ret == EPKG_ENOACCESS) { warnx("Insufficient privileges to read the package database"); pkg_audit_free(audit); kh_destroy_pkgs(check); return (EX_NOPERM); } else if (ret != EPKG_OK) { warnx("Error accessing the package database"); pkg_audit_free(audit); kh_destroy_pkgs(check); return (EX_IOERR); } if (pkgdb_open(&db, PKGDB_DEFAULT) != EPKG_OK) { pkg_audit_free(audit); kh_destroy_pkgs(check); return (EX_IOERR); } if (pkgdb_obtain_lock(db, PKGDB_LOCK_READONLY) != EPKG_OK) { pkgdb_close(db); pkg_audit_free(audit); kh_destroy_pkgs(check); warnx("Cannot get a read lock on a database, it is locked by another process"); return (EX_TEMPFAIL); } if ((it = pkgdb_query(db, NULL, MATCH_ALL)) == NULL) { warnx("Error accessing the package database"); ret = EX_IOERR; } else { while ((ret = pkgdb_it_next(it, &pkg, PKG_LOAD_BASIC|PKG_LOAD_RDEPS)) == EPKG_OK) { add_to_check(check, pkg); pkg = NULL; } ret = EX_OK; } if (db != NULL) { pkgdb_it_free(it); pkgdb_release_lock(db, PKGDB_LOCK_READONLY); pkgdb_close(db); } if (ret != EX_OK) { pkg_audit_free(audit); kh_destroy_pkgs(check); return (ret); } } /* Now we have vulnxml loaded and check list formed */ #ifdef HAVE_CAPSICUM if (cap_enter() < 0 && errno != ENOSYS) { warn("cap_enter() failed"); pkg_audit_free(audit); kh_destroy_pkgs(check); return (EPKG_FATAL); } #endif if (pkg_audit_process(audit) == EPKG_OK) { kh_foreach_value(check, pkg, { if (pkg_audit_is_vulnerable(audit, pkg, quiet, &sb)) { vuln ++; printf("%s", sbuf_data(sb)); if (recursive) { const char *name; kh_pkgs_t *seen = kh_init_pkgs(); pkg_get(pkg, PKG_NAME, &name); sbuf_clear(sb); sbuf_printf(sb, "Packages that depend on %s: ", name); print_recursive_rdeps(check, pkg , sb, seen, true); sbuf_finish(sb); printf("%s\n\n", sbuf_data(sb)); kh_destroy_pkgs(seen); } sbuf_delete(sb); } pkg_free(pkg); });
static int pkg_repo_binary_try_fetch(struct pkg_repo *repo, struct pkg *pkg, bool already_tried, bool mirror, const char *destdir) { char dest[MAXPATHLEN]; char url[MAXPATHLEN]; char *dir = NULL; int fetched = 0; char cksum[SHA256_DIGEST_LENGTH * 2 +1]; int64_t pkgsize; struct stat st; char *path = NULL; const char *packagesite = NULL, *repourl; int retcode = EPKG_OK; const char *name, *version, *sum; assert((pkg->type & PKG_REMOTE) == PKG_REMOTE); pkg_get(pkg, PKG_CKSUM, &sum, PKG_NAME, &name, PKG_VERSION, &version, PKG_PKGSIZE, &pkgsize, PKG_REPOPATH, &repourl); if (mirror) { const char *cachedir; if (destdir != NULL) cachedir = destdir; else cachedir = pkg_object_string(pkg_config_get("PKG_CACHEDIR")); snprintf(dest, sizeof(dest), "%s/%s", cachedir, repourl); } else pkg_repo_binary_get_cached_name(repo, pkg, dest, sizeof(dest)); /* If it is already in the local cachedir, dont bother to * download it */ if (access(dest, F_OK) == 0) goto checksum; /* Create the dirs in cachedir */ dir = strdup(dest); if (dir == NULL || (path = dirname(dir)) == NULL) { pkg_emit_errno("dirname", dest); retcode = EPKG_FATAL; goto cleanup; } if ((retcode = mkdirs(path)) != EPKG_OK) goto cleanup; /* * In multi-repos the remote URL is stored in pkg[PKG_REPOURL] * For a single attached database the repository URL should be * defined by PACKAGESITE. */ packagesite = pkg_repo_url(repo); if (packagesite == NULL || packagesite[0] == '\0') { pkg_emit_error("PACKAGESITE is not defined"); retcode = 1; goto cleanup; } if (packagesite[strlen(packagesite) - 1] == '/') pkg_snprintf(url, sizeof(url), "%S%R", packagesite, pkg); else pkg_snprintf(url, sizeof(url), "%S/%R", packagesite, pkg); if (!mirror && strncasecmp(packagesite, "file://", 7) == 0) { pkg_set(pkg, PKG_REPOPATH, url + 7); return (EPKG_OK); } retcode = pkg_fetch_file(repo, url, dest, 0); fetched = 1; if (retcode != EPKG_OK) goto cleanup; checksum: /* checksum calculation is expensive, if size does not match, skip it and assume failed checksum. */ if (stat(dest, &st) == -1 || pkgsize != st.st_size) { if (already_tried) { pkg_emit_error("cached package %s-%s: " "size mismatch, cannot continue", name, version); retcode = EPKG_FATAL; goto cleanup; } unlink(dest); pkg_emit_error("cached package %s-%s: " "size mismatch, fetching from remote", name, version); return (pkg_repo_binary_try_fetch(repo, pkg, true, mirror, destdir)); } retcode = sha256_file(dest, cksum); if (retcode == EPKG_OK) { if (strcmp(cksum, sum)) { if (already_tried || fetched == 1) { pkg_emit_error("%s-%s failed checksum " "from repository", name, version); retcode = EPKG_FATAL; } else { pkg_emit_error("cached package %s-%s: " "checksum mismatch, fetching from remote", name, version); unlink(dest); return (pkg_repo_binary_try_fetch(repo, pkg, true, mirror, destdir)); } } } cleanup: if (retcode != EPKG_OK) unlink(dest); else if (!mirror && path != NULL) { (void)pkg_repo_binary_create_symlink(pkg, dest, path); } /* allowed even if dir is NULL */ free(dir); return (retcode); }
static int analyse_elf(struct pkg *pkg, const char *fpath) { Elf *e = NULL; GElf_Ehdr elfhdr; Elf_Scn *scn = NULL; Elf_Scn *note = NULL; Elf_Scn *dynamic = NULL; GElf_Shdr shdr; Elf_Data *data; GElf_Dyn *dyn, dyn_mem; struct stat sb; int ret = EPKG_OK; size_t numdyn = 0; size_t sh_link = 0; size_t dynidx; const char *osname; const char *myarch; const char *shlib; bool is_shlib = false; myarch = pkg_object_string(pkg_config_get("ABI")); int fd; pkg_debug(1, "analysing elf"); if (lstat(fpath, &sb) != 0) pkg_emit_errno("fstat() failed for", fpath); /* ignore empty files and non regular files */ if (sb.st_size == 0 || !S_ISREG(sb.st_mode)) return (EPKG_END); /* Empty file or sym-link: no results */ if ((fd = open(fpath, O_RDONLY, 0)) < 0) { return (EPKG_FATAL); } if ((e = elf_begin(fd, ELF_C_READ, NULL)) == NULL) { ret = EPKG_FATAL; pkg_emit_error("elf_begin() for %s failed: %s", fpath, elf_errmsg(-1)); goto cleanup; } if (elf_kind(e) != ELF_K_ELF) { /* Not an elf file: no results */ ret = EPKG_END; goto cleanup; } if (developer_mode) pkg->flags |= PKG_CONTAINS_ELF_OBJECTS; if (gelf_getehdr(e, &elfhdr) == NULL) { ret = EPKG_FATAL; pkg_emit_error("getehdr() failed: %s.", elf_errmsg(-1)); goto cleanup; } if (elfhdr.e_type != ET_DYN && elfhdr.e_type != ET_EXEC && elfhdr.e_type != ET_REL) { ret = EPKG_END; goto cleanup; } /* Elf file has sections header */ while ((scn = elf_nextscn(e, scn)) != NULL) { if (gelf_getshdr(scn, &shdr) != &shdr) { ret = EPKG_FATAL; pkg_emit_error("getshdr() for %s failed: %s", fpath, elf_errmsg(-1)); goto cleanup; } switch (shdr.sh_type) { case SHT_NOTE: if ((data = elf_getdata(scn, NULL)) == NULL) { ret = EPKG_END; /* Some error occurred, ignore this file */ goto cleanup; } else if (data->d_buf != NULL) { Elf_Note *en = (Elf_Note *)data->d_buf; if (en->n_type == NT_ABI_TAG) note = scn; } break; case SHT_DYNAMIC: dynamic = scn; sh_link = shdr.sh_link; numdyn = shdr.sh_size / shdr.sh_entsize; break; } if (note != NULL && dynamic != NULL) break; } /* * note == NULL usually means a shared object for use with dlopen(3) * dynamic == NULL means not a dynamically linked elf */ if (dynamic == NULL) { ret = EPKG_END; goto cleanup; /* not a dynamically linked elf: no results */ } if (!shlib_valid_abi(fpath, &elfhdr, myarch)) { ret = EPKG_END; goto cleanup; /* Invalid ABI */ } if (note != NULL) { if ((data = elf_getdata(note, NULL)) == NULL) { ret = EPKG_END; /* Some error occurred, ignore this file */ goto cleanup; } if (data->d_buf == NULL) { ret = EPKG_END; /* No osname available */ goto cleanup; } osname = (const char *) data->d_buf + sizeof(Elf_Note); if (strncasecmp(osname, "freebsd", sizeof("freebsd")) != 0 && strncasecmp(osname, "dragonfly", sizeof("dragonfly")) != 0) { ret = EPKG_END; /* Foreign (probably linux) ELF object */ goto cleanup; } } else { if (elfhdr.e_ident[EI_OSABI] != ELFOSABI_FREEBSD && !is_old_freebsd_armheader(&elfhdr)) { ret = EPKG_END; goto cleanup; } } if ((data = elf_getdata(dynamic, NULL)) == NULL) { ret = EPKG_END; /* Some error occurred, ignore this file */ goto cleanup; } /* First, scan through the data from the .dynamic section to find any RPATH or RUNPATH settings. These are colon separated paths to prepend to the ld.so search paths from the ELF hints file. These always seem to come right after the NEEDED shared library entries. NEEDED entries should resolve to a filename for installed executables, but need not resolve for installed shared libraries -- additional info from the apps that link against them would be required. Shared libraries are distinguished by a DT_SONAME tag */ rpath_list_init(); for (dynidx = 0; dynidx < numdyn; dynidx++) { if ((dyn = gelf_getdyn(data, dynidx, &dyn_mem)) == NULL) { ret = EPKG_FATAL; pkg_emit_error("getdyn() failed for %s: %s", fpath, elf_errmsg(-1)); goto cleanup; } if (dyn->d_tag == DT_SONAME) { is_shlib = true; /* The file being scanned is a shared library *provided* by the package. Record this if appropriate */ pkg_addshlib_provided(pkg, elf_strptr(e, sh_link, dyn->d_un.d_val)); } if (dyn->d_tag != DT_RPATH && dyn->d_tag != DT_RUNPATH) continue; shlib_list_from_rpath(elf_strptr(e, sh_link, dyn->d_un.d_val), bsd_dirname(fpath)); break; } /* Now find all of the NEEDED shared libraries. */ for (dynidx = 0; dynidx < numdyn; dynidx++) { if ((dyn = gelf_getdyn(data, dynidx, &dyn_mem)) == NULL) { ret = EPKG_FATAL; pkg_emit_error("getdyn() failed for %s: %s", fpath, elf_errmsg(-1)); goto cleanup; } if (dyn->d_tag != DT_NEEDED) continue; shlib = elf_strptr(e, sh_link, dyn->d_un.d_val); add_shlibs_to_pkg(pkg, fpath, shlib, is_shlib); } cleanup: rpath_list_free(); if (e != NULL) elf_end(e); close(fd); return (ret); }
int pkg_register_old(struct pkg *pkg) { FILE *fp; char *content; const char *pkgdbdir, *tmp; char path[MAXPATHLEN]; struct sbuf *install_script = sbuf_new_auto(); struct sbuf *deinstall_script = sbuf_new_auto(); struct pkg_dep *dep = NULL; pkg_to_old(pkg); pkg_old_emit_content(pkg, &content); pkgdbdir = pkg_object_string(pkg_config_get("PKG_DBDIR")); pkg_snprintf(path, sizeof(path), "%S/%n-%v", pkgdbdir, pkg, pkg); mkdir(path, 0755); pkg_snprintf(path, sizeof(path), "%S/%n-%v/+CONTENTS", pkgdbdir, pkg, pkg); fp = fopen(path, "w"); fputs(content, fp); fclose(fp); pkg_snprintf(path, sizeof(path), "%S/%n-%v/+DESC", pkgdbdir, pkg, pkg); fp = fopen(path, "w"); pkg_fprintf(fp, "%e", pkg); fclose(fp); pkg_snprintf(path, sizeof(path), "%s/%n-%v/+COMMENT", pkgdbdir, pkg, pkg); fp = fopen(path, "w"); pkg_fprintf(fp, "%c\n", pkg); fclose(fp); if (pkg_has_message(pkg)) { pkg_snprintf(path, sizeof(path), "%s/%n-%v/+DISPLAY", pkgdbdir, pkg, pkg); fp = fopen(path, "w"); pkg_fprintf(fp, "%M", pkg); fclose(fp); } sbuf_clear(install_script); tmp = pkg_script_get(pkg, PKG_SCRIPT_PRE_INSTALL); if (tmp != NULL && *tmp != '\0') { if (sbuf_len(install_script) == 0) sbuf_cat(install_script, "#!/bin/sh\n\n"); sbuf_printf(install_script, "if [ \"$2\" = \"PRE-INSTALL\" ]; then\n" "%s\n" "fi\n", tmp); } tmp = pkg_script_get(pkg, PKG_SCRIPT_INSTALL); if (tmp != NULL && *tmp != '\0') { if (sbuf_len(install_script) == 0) sbuf_cat(install_script, "#!/bin/sh\n\n"); sbuf_cat(install_script, tmp); } tmp = pkg_script_get(pkg, PKG_SCRIPT_POST_INSTALL); if (tmp != NULL && *tmp != '\0') { if (sbuf_len(install_script) == 0) sbuf_cat(install_script, "#!/bin/sh\n\n"); sbuf_printf(install_script, "if [ \"$2\" = \"POST-INSTALL\" ]; then\n" "%s\n" "fi\n", tmp); } if (sbuf_len(install_script) > 0) { sbuf_finish(install_script); pkg_snprintf(path, sizeof(path), "%s/%n-%v/+INSTALL", pkgdbdir, pkg, pkg); fp = fopen(path, "w"); fputs(sbuf_data(install_script), fp); fclose(fp); } sbuf_clear(deinstall_script); tmp = pkg_script_get(pkg, PKG_SCRIPT_PRE_DEINSTALL); if (tmp != NULL && *tmp != '\0') { if (sbuf_len(deinstall_script) == 0) sbuf_cat(deinstall_script, "#!/bin/sh\n\n"); sbuf_printf(deinstall_script, "if [ \"$2\" = \"DEINSTALL\" ]; then\n" "%s\n" "fi\n", tmp); } tmp = pkg_script_get(pkg, PKG_SCRIPT_DEINSTALL); if (tmp != NULL && *tmp != '\0') { if (sbuf_len(deinstall_script) == 0) sbuf_cat(deinstall_script, "#!/bin/sh\n\n"); sbuf_cat(deinstall_script, tmp); } tmp = pkg_script_get(pkg, PKG_SCRIPT_POST_DEINSTALL); if (tmp != NULL && tmp[0] != '\0') { if (sbuf_len(deinstall_script) == 0) sbuf_cat(deinstall_script, "#!/bin/sh\n\n"); sbuf_printf(deinstall_script, "if [ \"$2\" = \"POST-DEINSTALL\" ]; then\n" "%s\n" "fi\n", tmp); } if (sbuf_len(deinstall_script) > 0) { sbuf_finish(deinstall_script); pkg_snprintf(path, sizeof(path), "%s/%n-%v/+DEINSTALL", pkgdbdir, pkg, pkg); fp = fopen(path, "w"); fputs(sbuf_data(deinstall_script), fp); fclose(fp); } while (pkg_deps(pkg, &dep)) { snprintf(path, sizeof(path), "%s/%s-%s/+REQUIRED_BY", pkgdbdir, pkg_dep_name(dep), pkg_dep_version(dep)); fp = fopen(path, "a"); pkg_fprintf(fp, "%n-%v\n", pkg, pkg); fclose(fp); } return (EPKG_OK); }
int exec_rquery(int argc, char **argv) { struct pkgdb *db = NULL; struct pkgdb_it *it = NULL; struct pkg *pkg = NULL; char *pkgname = NULL; int query_flags = PKG_LOAD_BASIC; match_t match = MATCH_EXACT; int ch; int ret = EPKG_OK; int retcode = EX_OK; int i; char multiline = 0; char *condition = NULL; const char *portsdir; struct sbuf *sqlcond = NULL; const unsigned int q_flags_len = NELEM(accepted_rquery_flags); const char *reponame = NULL; bool auto_update; bool onematched = false; bool old_quiet; bool index_output = false; struct option longopts[] = { { "all", no_argument, NULL, 'a' }, { "case-sensitive", no_argument, NULL, 'C' }, { "evaluate", required_argument, NULL, 'e' }, { "glob", no_argument, NULL, 'g' }, { "case-insensitive", no_argument, NULL, 'i' }, { "index-line", no_argument, NULL, 'I' }, { "repository", required_argument, NULL, 'r' }, { "no-repo-update", no_argument, NULL, 'U' }, { "regex", no_argument, NULL, 'x' }, { NULL, 0, NULL, 0 }, }; portsdir = pkg_object_string(pkg_config_get("PORTSDIR")); while ((ch = getopt_long(argc, argv, "+aCgiIxe:r:U", longopts, NULL)) != -1) { switch (ch) { case 'a': match = MATCH_ALL; break; case 'C': pkgdb_set_case_sensitivity(true); break; case 'e': match = MATCH_CONDITION; condition = optarg; break; case 'g': match = MATCH_GLOB; break; case 'i': pkgdb_set_case_sensitivity(false); break; case 'I': index_output = true; break; case 'r': reponame = optarg; break; case 'U': auto_update = false; break; case 'x': match = MATCH_REGEX; break; default: usage_rquery(); return (EX_USAGE); } } argc -= optind; argv += optind; if (argc == 0 && !index_output) { usage_rquery(); return (EX_USAGE); } /* Default to all packages if no pkg provided */ if (!index_output) { if (argc == 1 && condition == NULL && match == MATCH_EXACT) { match = MATCH_ALL; } else if (((argc == 1) ^ (match == MATCH_ALL )) && condition == NULL) { usage_rquery(); return (EX_USAGE); } } else { if (argc == 0) match = MATCH_ALL; } if (!index_output && analyse_query_string(argv[0], accepted_rquery_flags, q_flags_len, &query_flags, &multiline) != EPKG_OK) return (EX_USAGE); if (condition != NULL) { sqlcond = sbuf_new_auto(); if (format_sql_condition(condition, sqlcond, true) != EPKG_OK) return (EX_USAGE); sbuf_finish(sqlcond); } ret = pkgdb_access(PKGDB_MODE_READ, PKGDB_DB_REPO); if (ret == EPKG_ENOACCESS) { warnx("Insufficient privileges to query the package database"); return (EX_NOPERM); } else if (ret != EPKG_OK) return (EX_IOERR); /* first update the remote repositories if needed */ old_quiet = quiet; quiet = true; if (auto_update && (ret = pkgcli_update(false, false, reponame)) != EPKG_OK) return (ret); quiet = old_quiet; ret = pkgdb_open_all(&db, PKGDB_REMOTE, reponame); if (ret != EPKG_OK) return (EX_IOERR); if (index_output) query_flags = PKG_LOAD_BASIC|PKG_LOAD_CATEGORIES|PKG_LOAD_DEPS; if (match == MATCH_ALL || match == MATCH_CONDITION) { const char *condition_sql = NULL; if (match == MATCH_CONDITION && sqlcond) condition_sql = sbuf_data(sqlcond); if ((it = pkgdb_repo_query(db, condition_sql, match, reponame)) == NULL) return (EX_IOERR); while ((ret = pkgdb_it_next(it, &pkg, query_flags)) == EPKG_OK) { if (index_output) print_index(pkg, portsdir); else print_query(pkg, argv[0], multiline); } if (ret != EPKG_END) retcode = EX_SOFTWARE; pkgdb_it_free(it); } else { for (i = (index_output ? 0 : 1); i < argc; i++) { pkgname = argv[i]; if ((it = pkgdb_repo_query(db, pkgname, match, reponame)) == NULL) return (EX_IOERR); while ((ret = pkgdb_it_next(it, &pkg, query_flags)) == EPKG_OK) { onematched = true; if (index_output) print_index(pkg, portsdir); else print_query(pkg, argv[0], multiline); } if (ret != EPKG_END) { retcode = EX_SOFTWARE; break; } pkgdb_it_free(it); } if (!onematched && retcode == EX_OK) retcode = EX_UNAVAILABLE; } pkg_free(pkg); pkgdb_close(db); return (retcode); }
pkg_status_t pkg_status(int *count) { pkg_object *o; const char *progname; char dbpath[MAXPATHLEN]; int numpkgs = 0; sqlite3 *db = NULL; sqlite3_stmt *stmt = NULL; const char *sql = "SELECT COUNT(*) FROM packages"; bool dbsuccess; /* Is this executable called pkg, or does pkg exist at $LOCALBASE/sbin/pkg. Ditto: pkg-static. Portability: assumes setprogname() has been called */ progname = getprogname(); if (progname == NULL) return (PKG_STATUS_UNINSTALLED); if (strcmp(progname, PKG_EXEC_NAME) != 0 && strcmp(progname, PKG_STATIC_NAME) != 0 && !is_exec_at_localbase(PKG_EXEC_NAME) && !is_exec_at_localbase(PKG_STATIC_NAME)) return (PKG_STATUS_UNINSTALLED); /* Does the local.sqlite pkg database exist, and can we open it for reading? */ o = pkg_config_get("PKG_DBDIR"); snprintf(dbpath, sizeof(dbpath), "%s/local.sqlite", pkg_object_string(o)); if (eaccess(dbpath, R_OK) == -1) return (PKG_STATUS_NODB); /* Try opening the DB and preparing and running a simple query. */ dbsuccess = (sqlite3_initialize() == SQLITE_OK); if (dbsuccess) { dbsuccess = (sqlite3_open_v2(dbpath, &db, SQLITE_OPEN_READONLY, NULL) == SQLITE_OK); if (dbsuccess) { dbsuccess = (sqlite3_prepare_v2(db, sql, -1, &stmt, NULL) == SQLITE_OK); if (dbsuccess) { dbsuccess = (sqlite3_step(stmt) == SQLITE_ROW); if (dbsuccess) { numpkgs = sqlite3_column_int(stmt, 0); } sqlite3_finalize(stmt); } sqlite3_close(db); } sqlite3_shutdown(); } if (!dbsuccess) return (PKG_STATUS_NODB); /* Save result, if requested */ if (count != NULL) *count = numpkgs; return (numpkgs == 0 ? PKG_STATUS_NOPACKAGES : PKG_STATUS_ACTIVE); }
static int pkg_create_from_dir(struct pkg *pkg, const char *root, struct packing *pkg_archive) { char fpath[MAXPATHLEN]; struct pkg_file *file = NULL; struct pkg_dir *dir = NULL; char *m; int ret; const char *mtree; bool developer; struct stat st; char sha256[SHA256_DIGEST_LENGTH * 2 + 1]; int64_t flatsize = 0; ucl_object_t *obj; if (pkg_is_valid(pkg) != EPKG_OK) { pkg_emit_error("the package is not valid"); return (EPKG_FATAL); } obj = pkg_annotation_lookup(pkg, "relocated"); /* * Get / compute size / checksum if not provided in the manifest */ while (pkg_files(pkg, &file) == EPKG_OK) { const char *pkg_path = pkg_file_path(file); const char *pkg_sum = pkg_file_cksum(file); snprintf(fpath, sizeof(fpath), "%s%s%s", root ? root : "", obj ? pkg_object_string(obj) : "", pkg_path); if (lstat(fpath, &st) != 0 || S_ISLNK(st.st_mode)) continue; if (file->size == 0) file->size = (int64_t)st.st_size; flatsize += file->size; if (pkg_sum == NULL || pkg_sum[0] == '\0') { if (pkg->type == PKG_OLD_FILE) { if (md5_file(fpath, sha256) != EPKG_OK) return (EPKG_FATAL); } else { if (sha256_file(fpath, sha256) != EPKG_OK) return (EPKG_FATAL); } strlcpy(file->sum, sha256, sizeof(file->sum)); } } pkg_set(pkg, PKG_FLATSIZE, flatsize); if (pkg->type == PKG_OLD_FILE) { const char *desc, *display, *comment; char oldcomment[BUFSIZ]; pkg_old_emit_content(pkg, &m); packing_append_buffer(pkg_archive, m, "+CONTENTS", strlen(m)); free(m); pkg_get(pkg, PKG_DESC, &desc, PKG_MESSAGE, &display, PKG_COMMENT, &comment); packing_append_buffer(pkg_archive, desc, "+DESC", strlen(desc)); packing_append_buffer(pkg_archive, display, "+DISPLAY", strlen(display)); snprintf(oldcomment, sizeof(oldcomment), "%s\n", comment); packing_append_buffer(pkg_archive, oldcomment, "+COMMENT", strlen(oldcomment)); } else { /* * Register shared libraries used by the package if * SHLIBS enabled in conf. Deletes shlib info if not. */ struct sbuf *b = sbuf_new_auto(); pkg_register_shlibs(pkg, root); pkg_emit_manifest_sbuf(pkg, b, PKG_MANIFEST_EMIT_COMPACT, NULL); packing_append_buffer(pkg_archive, sbuf_data(b), "+COMPACT_MANIFEST", sbuf_len(b)); sbuf_clear(b); pkg_emit_manifest_sbuf(pkg, b, 0, NULL); sbuf_finish(b); packing_append_buffer(pkg_archive, sbuf_data(b), "+MANIFEST", sbuf_len(b)); sbuf_delete(b); } pkg_get(pkg, PKG_MTREE, &mtree); if (mtree != NULL) packing_append_buffer(pkg_archive, mtree, "+MTREE_DIRS", strlen(mtree)); while (pkg_files(pkg, &file) == EPKG_OK) { const char *pkg_path = pkg_file_path(file); snprintf(fpath, sizeof(fpath), "%s%s%s", root ? root : "", obj ? pkg_object_string(obj) : "", pkg_path); ret = packing_append_file_attr(pkg_archive, fpath, pkg_path, file->uname, file->gname, file->perm); developer = pkg_object_bool(pkg_config_get("DEVELOPER_MODE")); if (developer && ret != EPKG_OK) return (ret); } while (pkg_dirs(pkg, &dir) == EPKG_OK) { const char *pkg_path = pkg_dir_path(dir); snprintf(fpath, sizeof(fpath), "%s%s%s", root ? root : "", obj ? pkg_object_string(obj) : "", pkg_path); ret = packing_append_file_attr(pkg_archive, fpath, pkg_path, dir->uname, dir->gname, dir->perm); developer = pkg_object_bool(pkg_config_get("DEVELOPER_MODE")); if (developer && ret != EPKG_OK) return (ret); } return (EPKG_OK); }
int exec_clean(int argc, char **argv) { struct pkgdb *db = NULL; struct pkgdb_it *it = NULL; struct pkg *p = NULL; struct sumlist *sumlist = NULL, *s, *t; FTS *fts = NULL; FTSENT *ent = NULL; struct dl_head dl = STAILQ_HEAD_INITIALIZER(dl); const char *cachedir, *sum, *name; char *paths[2], csum[PKG_FILE_CKSUM_CHARS + 1], link_buf[MAXPATHLEN]; bool all = false; bool sumloaded = false; int retcode; int ch, cnt = 0; size_t total = 0, slen; ssize_t link_len; char size[7]; struct pkg_manifest_key *keys = NULL; struct option longopts[] = { { "all", no_argument, NULL, 'a' }, { "dry-run", no_argument, NULL, 'n' }, { "quiet", no_argument, NULL, 'q' }, { "yes", no_argument, NULL, 'y' }, { NULL, 0, NULL, 0 }, }; while ((ch = getopt_long(argc, argv, "+anqy", longopts, NULL)) != -1) { switch (ch) { case 'a': all = true; break; case 'n': dry_run = true; break; case 'q': quiet = true; break; case 'y': yes = true; break; default: usage_clean(); return (EX_USAGE); } } argc -= optind; argv += optind; cachedir = pkg_object_string(pkg_config_get("PKG_CACHEDIR")); paths[0] = __DECONST(char*, cachedir); paths[1] = NULL; retcode = pkgdb_access(PKGDB_MODE_READ, PKGDB_DB_REPO); if (retcode == EPKG_ENOACCESS) { warnx("Insufficient privileges to clean old packages"); return (EX_NOPERM); } else if (retcode == EPKG_ENODB) { warnx("No package database installed. Nothing to do!"); return (EX_OK); } else if (retcode != EPKG_OK) { warnx("Error accessing the package database"); return (EX_SOFTWARE); } retcode = EX_SOFTWARE; if (pkgdb_open(&db, PKGDB_REMOTE) != EPKG_OK) return (EX_IOERR); if (pkgdb_obtain_lock(db, PKGDB_LOCK_READONLY) != EPKG_OK) { pkgdb_close(db); warnx("Cannot get a read lock on a database, it is locked by another process"); return (EX_TEMPFAIL); } if ((fts = fts_open(paths, FTS_PHYSICAL, NULL)) == NULL) { warn("fts_open(%s)", cachedir); goto cleanup; } /* Build the list of out-of-date or obsolete packages */ pkg_manifest_keys_new(&keys); while ((ent = fts_read(fts)) != NULL) { if (ent->fts_info != FTS_F && ent->fts_info != FTS_SL) continue; if (all) { retcode = add_to_dellist(&dl, ent->fts_path); if (retcode == EPKG_OK) { total += ent->fts_statp->st_size; ++cnt; } continue; } if (sumlist == NULL && !sumloaded) { it = pkgdb_repo_search(db, "*", MATCH_GLOB, FIELD_NAME, FIELD_NONE, NULL); while (pkgdb_it_next(it, &p, PKG_LOAD_BASIC) == EPKG_OK) { pkg_get(p, PKG_CKSUM, &sum); slen = MIN(strlen(sum), PKG_FILE_CKSUM_CHARS); s = calloc(1, sizeof(struct sumlist)); memcpy(s->sum, sum, slen); s->sum[slen] = '\0'; HASH_ADD_STR(sumlist, sum, s); } } if (ent->fts_info == FTS_SL) { /* Dereference the symlink and check it for being * recognized checksum file, or delete the symlink * later. */ if ((link_len = readlink(ent->fts_name, link_buf, sizeof(link_buf))) == -1) continue; link_buf[link_len] = '\0'; name = link_buf; } else name = ent->fts_name; s = NULL; if (extract_filename_sum(name, csum)) HASH_FIND_STR(sumlist, csum, s); if (s == NULL) { retcode = add_to_dellist(&dl, ent->fts_path); if (retcode == EPKG_OK) { total += ent->fts_statp->st_size; ++cnt; } continue; } } HASH_ITER(hh, sumlist, s, t) { HASH_DEL(sumlist, s); free(s); }
int exec_clean(int argc, char **argv) { struct pkgdb *db = NULL; kh_sum_t *sumlist = NULL; dl_list dl; const char *cachedir; bool all = false; int retcode; int ch; int cachefd = -1; size_t total = 0; char size[8]; char *cksum; struct pkg_manifest_key *keys = NULL; #ifdef HAVE_CAPSICUM cap_rights_t rights; #endif struct option longopts[] = { { "all", no_argument, NULL, 'a' }, { "dry-run", no_argument, NULL, 'n' }, { "quiet", no_argument, NULL, 'q' }, { "yes", no_argument, NULL, 'y' }, { NULL, 0, NULL, 0 }, }; while ((ch = getopt_long(argc, argv, "+anqy", longopts, NULL)) != -1) { switch (ch) { case 'a': all = true; break; case 'n': dry_run = true; break; case 'q': quiet = true; break; case 'y': yes = true; break; default: usage_clean(); return (EX_USAGE); } } argc -= optind; argv += optind; cachedir = pkg_object_string(pkg_config_get("PKG_CACHEDIR")); cachefd = open(cachedir, O_DIRECTORY); if (cachefd == -1) { warn("Impossible to open %s", cachedir); return (EX_IOERR); } retcode = pkgdb_access(PKGDB_MODE_READ, PKGDB_DB_REPO); if (retcode == EPKG_ENOACCESS) { warnx("Insufficient privileges to clean old packages"); close(cachefd); return (EX_NOPERM); } else if (retcode == EPKG_ENODB) { warnx("No package database installed. Nothing to do!"); close(cachefd); return (EX_OK); } else if (retcode != EPKG_OK) { warnx("Error accessing the package database"); close(cachefd); return (EX_SOFTWARE); } retcode = EX_SOFTWARE; if (pkgdb_open(&db, PKGDB_REMOTE) != EPKG_OK) { close(cachefd); return (EX_IOERR); } if (pkgdb_obtain_lock(db, PKGDB_LOCK_READONLY) != EPKG_OK) { pkgdb_close(db); close(cachefd); warnx("Cannot get a read lock on a database, it is locked by " "another process"); return (EX_TEMPFAIL); } #ifdef HAVE_CAPSICUM cap_rights_init(&rights, CAP_READ, CAP_LOOKUP, CAP_FSTATFS, CAP_FSTAT, CAP_UNLINKAT); if (cap_rights_limit(cachefd, &rights) < 0 && errno != ENOSYS ) { warn("cap_rights_limit() failed"); close(cachefd); return (EX_SOFTWARE); } if (cap_enter() < 0 && errno != ENOSYS) { warn("cap_enter() failed"); close(cachefd); return (EX_SOFTWARE); } #endif kv_init(dl); /* Build the list of out-of-date or obsolete packages */ pkg_manifest_keys_new(&keys); recursive_analysis(cachefd, db, cachedir, cachedir, &dl, &sumlist, all, &total); if (sumlist != NULL) { kh_foreach_value(sumlist, cksum, free(cksum)); kh_destroy_sum(sumlist); } if (kv_size(dl) == 0) { if (!quiet) printf("Nothing to do.\n"); retcode = EX_OK; goto cleanup; } humanize_number(size, sizeof(size), total, "B", HN_AUTOSCALE, HN_IEC_PREFIXES); if (!quiet) printf("The cleanup will free %s\n", size); if (!dry_run) { if (query_yesno(false, "\nProceed with cleaning the cache? ")) { retcode = delete_dellist(cachefd, cachedir, &dl, kv_size(dl)); } } else { retcode = EX_OK; } cleanup: pkgdb_release_lock(db, PKGDB_LOCK_READONLY); pkgdb_close(db); pkg_manifest_keys_free(keys); free_dellist(&dl); if (cachefd != -1) close(cachefd); return (retcode); }
int pkg_repo_binary_open(struct pkg_repo *repo, unsigned mode) { char filepath[MAXPATHLEN]; struct statfs stfs; const char *dbdir = NULL; sqlite3 *sqlite = NULL; int flags; int64_t res; struct pkg_repo_it *it; struct pkg *pkg = NULL; const char *digest; sqlite3_initialize(); dbdir = pkg_object_string(pkg_config_get("PKG_DBDIR")); /* * Fall back on unix-dotfile locking strategy if on a network filesystem */ if (statfs(dbdir, &stfs) == 0) { if ((stfs.f_flags & MNT_LOCAL) != MNT_LOCAL) sqlite3_vfs_register(sqlite3_vfs_find("unix-dotfile"), 1); } snprintf(filepath, sizeof(filepath), "%s/%s.meta", dbdir, pkg_repo_name(repo)); /* Open metafile */ if (access(filepath, R_OK) != -1) { if (pkg_repo_meta_load(filepath, &repo->meta) != EPKG_OK) return (EPKG_FATAL); } snprintf(filepath, sizeof(filepath), "%s/%s", dbdir, pkg_repo_binary_get_filename(pkg_repo_name(repo))); /* Always want read mode here */ if (access(filepath, R_OK | mode) != 0) return (EPKG_ENOACCESS); flags = (mode & W_OK) != 0 ? SQLITE_OPEN_READWRITE : SQLITE_OPEN_READONLY; if (sqlite3_open_v2(filepath, &sqlite, flags, NULL) != SQLITE_OK) return (EPKG_FATAL); /* Sanitise sqlite database */ if (get_pragma(sqlite, "SELECT count(name) FROM sqlite_master " "WHERE type='table' AND name='repodata';", &res, false) != EPKG_OK) { pkg_emit_error("Unable to query repository"); sqlite3_close(sqlite); return (EPKG_FATAL); } if (res != 1) { pkg_emit_notice("Repository %s contains no repodata table, " "need to re-create database", repo->name); sqlite3_close(sqlite); return (EPKG_FATAL); } /* Check package site */ char *req = sqlite3_mprintf("select count(key) from repodata " "WHERE key = \"packagesite\" and value = '%q'", pkg_repo_url(repo)); res = 0; get_pragma(sqlite, req, &res, true); sqlite3_free(req); if (res != 1) { pkg_emit_notice("Repository %s has a wrong packagesite, need to " "re-create database", repo->name); sqlite3_close(sqlite); return (EPKG_FATAL); } /* Check version */ if (pkg_repo_binary_check_version(repo, sqlite) != EPKG_OK) { pkg_emit_error("need to re-create repo %s to upgrade schema version", repo->name); sqlite3_close(sqlite); if (mode & W_OK) unlink(filepath); return (EPKG_REPOSCHEMA); } repo->priv = sqlite; /* Check digests format */ if ((it = pkg_repo_binary_query(repo, NULL, MATCH_ALL)) == NULL) return (EPKG_OK); if (it->ops->next(it, &pkg, PKG_LOAD_BASIC) != EPKG_OK) { it->ops->free(it); return (EPKG_OK); } it->ops->free(it); pkg_get(pkg, PKG_DIGEST, &digest); if (digest == NULL || !pkg_checksum_is_valid(digest, strlen(digest))) { pkg_emit_notice("Repository %s has incompatible checksum format, need to " "re-create database", repo->name); pkg_free(pkg); sqlite3_close(sqlite); repo->priv = NULL; return (EPKG_FATAL); } pkg_free(pkg); return (EPKG_OK); }
int pkg_sshserve(int fd) { struct stat st; char *line = NULL; char *file, *age; size_t linecap = 0, r; ssize_t linelen; time_t mtime = 0; const char *errstr; int ffd; char buf[BUFSIZ]; char fpath[MAXPATHLEN]; char rpath[MAXPATHLEN]; const char *restricted = NULL; restricted = pkg_object_string(pkg_config_get("SSH_RESTRICT_DIR")); printf("ok: pkg "PKGVERSION"\n"); for (;;) { if ((linelen = getline(&line, &linecap, stdin)) < 0) break; if (linelen == 0) continue; /* trim cr */ if (line[linelen - 1] == '\n') line[linelen - 1] = '\0'; if (strcmp(line, "quit") == 0) return (EPKG_OK); if (strncmp(line, "get ", 4) != 0) { printf("ko: unknown command '%s'\n", line); continue; } file = line + 4; if (*file == '/') file++; else if (*file == '\0') { printf("ko: bad command get, expecting 'get file age'\n"); continue; } pkg_debug(1, "SSH server> file requested: %s", file); age = file; while (!isspace(*age)) { if (*age == '\0') { age = NULL; break; } age++; } if (age == NULL) { printf("ko: bad command get, expecting 'get file age'\n"); continue; } *age = '\0'; age++; while (isspace(*age)) { if (*age == '\0') { age = NULL; break; } age++; } if (age == NULL) { printf("ko: bad command get, expecting 'get file age'\n"); continue; } mtime = strtonum(age, 0, LONG_MAX, &errstr); if (errstr) { printf("ko: bad number %s: %s\n", age, errstr); continue; } #ifdef HAVE_CAPSICUM if (!cap_sandboxed() && restricted != NULL) { #else if (restricted != NULL) { #endif chdir(restricted); if (realpath(file, fpath) == NULL || realpath(restricted, rpath) == NULL || strncmp(fpath, rpath, strlen(rpath)) != 0) { printf("ko: file not found\n"); continue; } } if (fstatat(fd, file, &st, 0) == -1) { pkg_debug(1, "SSH server> fstatat failed"); printf("ko: file not found\n"); continue; } if (!S_ISREG(st.st_mode)) { printf("ko: not a file\n"); continue; } if (st.st_mtime <= mtime) { printf("ok: 0\n"); continue; } if ((ffd = openat(fd, file, O_RDONLY)) == -1) { printf("ko: file not found\n"); continue; } printf("ok: %" PRIdMAX "\n", (intmax_t)st.st_size); pkg_debug(1, "SSH server> sending ok: %" PRIdMAX "", (intmax_t)st.st_size); while ((r = read(ffd, buf, sizeof(buf))) > 0) { pkg_debug(1, "SSH server> sending data"); fwrite(buf, 1, r, stdout); } pkg_debug(1, "SSH server> finished"); close(ffd); } free(line); return (EPKG_OK); }
int exec_alias(int argc, char **argv) { const pkg_object *all_aliases; const pkg_object *alias; pkg_iter it = NULL; int ch; int ret = EX_OK; bool list = false; struct option longopts[] = { { "quiet", no_argument, NULL, 'q' }, { "list", no_argument, NULL, 'l' }, { NULL, 0, NULL, 0 }, }; while ((ch = getopt_long(argc, argv, "+ql", longopts, NULL)) != -1) { switch (ch) { case 'q': quiet = true; break; case 'l': list = true; break; default: usage_alias(); return (EX_USAGE); } } argc -= optind; argv += optind; all_aliases = pkg_config_get("ALIAS"); if (argc == 0) { if (!quiet && list) printf("%s\n", "ALIAS"); else if (!quiet) printf("%-20s %s\n", "ALIAS", "ARGUMENTS"); while ((alias = pkg_object_iterate(all_aliases, &it))) { if (list) printf("%s\n", pkg_object_key(alias)); else printf("%-20s '%s'\n", pkg_object_key(alias), pkg_object_string(alias)); } return (ret); } for (int i = 0; i < argc; i++) { it = NULL; while ((alias = pkg_object_iterate(all_aliases, &it))) { if (strcmp(argv[i], pkg_object_key(alias)) == 0) break; } if (alias) { if (list) printf("%s\n", argv[i]); else printf("%-20s '%s'\n", argv[i], pkg_object_string(alias)); } else { warnx("No such alias: '%s'", argv[i]); ret = EX_UNAVAILABLE; } } return (ret); }
int pkg_ini(const char *path, const char *reposdir, pkg_init_flags flags) { struct ucl_parser *p = NULL; size_t i; const char *val = NULL; const char *buf, *walk, *value, *key, *k; const char *evkey = NULL; const char *nsname = NULL; const char *evpipe = NULL; const ucl_object_t *cur, *object; ucl_object_t *obj = NULL, *o, *ncfg; ucl_object_iter_t it = NULL; struct sbuf *ukey = NULL; bool fatal_errors = false; k = NULL; o = NULL; pkg_get_myarch(myabi, BUFSIZ); pkg_get_myarch_legacy(myabi_legacy, BUFSIZ); if (parsed != false) { pkg_emit_error("pkg_init() must only be called once"); return (EPKG_FATAL); } if (((flags & PKG_INIT_FLAG_USE_IPV4) == PKG_INIT_FLAG_USE_IPV4) && ((flags & PKG_INIT_FLAG_USE_IPV6) == PKG_INIT_FLAG_USE_IPV6)) { pkg_emit_error("Invalid flags for pkg_init()"); return (EPKG_FATAL); } config = ucl_object_typed_new(UCL_OBJECT); for (i = 0; i < c_size; i++) { switch (c[i].type) { case PKG_STRING: obj = ucl_object_fromstring_common( c[i].def != NULL ? c[i].def : "", 0, UCL_STRING_TRIM); ucl_object_insert_key(config, obj, c[i].key, strlen(c[i].key), false); break; case PKG_INT: ucl_object_insert_key(config, ucl_object_fromstring_common(c[i].def, 0, UCL_STRING_PARSE_INT), c[i].key, strlen(c[i].key), false); break; case PKG_BOOL: ucl_object_insert_key(config, ucl_object_fromstring_common(c[i].def, 0, UCL_STRING_PARSE_BOOLEAN), c[i].key, strlen(c[i].key), false); break; case PKG_OBJECT: obj = ucl_object_typed_new(UCL_OBJECT); if (c[i].def != NULL) { walk = buf = c[i].def; while ((buf = strchr(buf, ',')) != NULL) { key = walk; value = walk; while (*value != ',') { if (*value == '=') break; value++; } ucl_object_insert_key(obj, ucl_object_fromstring_common(value + 1, buf - value - 1, UCL_STRING_TRIM), key, value - key, false); buf++; walk = buf; } key = walk; value = walk; while (*value != ',') { if (*value == '=') break; value++; } if (o == NULL) o = ucl_object_typed_new(UCL_OBJECT); ucl_object_insert_key(o, ucl_object_fromstring_common(value + 1, strlen(value + 1), UCL_STRING_TRIM), key, value - key, false); } ucl_object_insert_key(config, obj, c[i].key, strlen(c[i].key), false); break; case PKG_ARRAY: obj = ucl_object_typed_new(UCL_ARRAY); if (c[i].def != NULL) { walk = buf = c[i].def; while ((buf = strchr(buf, ',')) != NULL) { ucl_array_append(obj, ucl_object_fromstring_common(walk, buf - walk, UCL_STRING_TRIM)); buf++; walk = buf; } ucl_array_append(obj, ucl_object_fromstring_common(walk, strlen(walk), UCL_STRING_TRIM)); } ucl_object_insert_key(config, obj, c[i].key, strlen(c[i].key), false); break; } } if (path == NULL) path = PREFIX"/etc/pkg.conf"; p = ucl_parser_new(0); errno = 0; obj = NULL; if (!ucl_parser_add_file(p, path)) { if (errno != ENOENT) pkg_emit_error("Invalid configuration file: %s", ucl_parser_get_error(p)); } else { obj = ucl_parser_get_object(p); } ncfg = NULL; while (obj != NULL && (cur = ucl_iterate_object(obj, &it, true))) { sbuf_init(&ukey); key = ucl_object_key(cur); for (i = 0; key[i] != '\0'; i++) sbuf_putc(ukey, toupper(key[i])); sbuf_finish(ukey); object = ucl_object_find_keyl(config, sbuf_data(ukey), sbuf_len(ukey)); if (strncasecmp(sbuf_data(ukey), "PACKAGESITE", sbuf_len(ukey)) == 0 || strncasecmp(sbuf_data(ukey), "PUBKEY", sbuf_len(ukey)) == 0 || strncasecmp(sbuf_data(ukey), "MIRROR_TYPE", sbuf_len(ukey)) == 0) { pkg_emit_error("%s in pkg.conf is no longer " "supported. Convert to the new repository style." " See pkg.conf(5)", sbuf_data(ukey)); fatal_errors = true; continue; } /* ignore unknown keys */ if (object == NULL) continue; if (object->type != cur->type) { pkg_emit_error("Malformed key %s, ignoring", key); continue; } if (ncfg == NULL) ncfg = ucl_object_typed_new(UCL_OBJECT); ucl_object_insert_key(ncfg, ucl_object_copy(cur), sbuf_data(ukey), sbuf_len(ukey), true); } if (fatal_errors) { ucl_object_unref(ncfg); ucl_parser_free(p); return (EPKG_FATAL); } if (ncfg != NULL) { it = NULL; while (( cur = ucl_iterate_object(ncfg, &it, true))) { key = ucl_object_key(cur); ucl_object_replace_key(config, ucl_object_ref(cur), key, strlen(key), true); } ucl_object_unref(ncfg); } ncfg = NULL; it = NULL; while ((cur = ucl_iterate_object(config, &it, true))) { o = NULL; key = ucl_object_key(cur); val = getenv(key); if (val == NULL) continue; switch (cur->type) { case UCL_STRING: o = ucl_object_fromstring_common(val, 0, UCL_STRING_TRIM); break; case UCL_INT: o = ucl_object_fromstring_common(val, 0, UCL_STRING_PARSE_INT); if (o->type != UCL_INT) { pkg_emit_error("Invalid type for environment " "variable %s, got %s, while expecting an integer", key, val); ucl_object_unref(o); continue; } break; case UCL_BOOLEAN: o = ucl_object_fromstring_common(val, 0, UCL_STRING_PARSE_BOOLEAN); if (o->type != UCL_BOOLEAN) { pkg_emit_error("Invalid type for environment " "variable %s, got %s, while expecting a boolean", key, val); ucl_object_unref(o); continue; } break; case UCL_OBJECT: o = ucl_object_typed_new(UCL_OBJECT); walk = buf = val; while ((buf = strchr(buf, ',')) != NULL) { k = walk; value = walk; while (*value != ',') { if (*value == '=') break; value++; } ucl_object_insert_key(o, ucl_object_fromstring_common(value + 1, buf - value - 1, UCL_STRING_TRIM), k, value - k, false); buf++; walk = buf; } key = walk; value = walk; while (*value != '\0') { if (*value == '=') break; value++; } ucl_object_insert_key(o, ucl_object_fromstring_common(value + 1, strlen(value + 1), UCL_STRING_TRIM), k, value - k, false); break; case UCL_ARRAY: o = ucl_object_typed_new(UCL_ARRAY); walk = buf = val; while ((buf = strchr(buf, ',')) != NULL) { ucl_array_append(o, ucl_object_fromstring_common(walk, buf - walk, UCL_STRING_TRIM)); buf++; walk = buf; } ucl_array_append(o, ucl_object_fromstring_common(walk, strlen(walk), UCL_STRING_TRIM)); break; default: /* ignore other types */ break; } if (o != NULL) { if (ncfg == NULL) ncfg = ucl_object_typed_new(UCL_OBJECT); ucl_object_insert_key(ncfg, o, key, strlen(key), true); } } if (ncfg != NULL) { it = NULL; while (( cur = ucl_iterate_object(ncfg, &it, true))) { key = ucl_object_key(cur); ucl_object_replace_key(config, ucl_object_ref(cur), key, strlen(key), true); } ucl_object_unref(ncfg); } disable_plugins_if_static(); parsed = true; ucl_object_unref(obj); ucl_parser_free(p); if (strcmp(pkg_object_string(pkg_config_get("ABI")), "unknown") == 0) { pkg_emit_error("Unable to determine ABI"); return (EPKG_FATAL); } pkg_debug(1, "%s", "pkg initialized"); /* Start the event pipe */ evpipe = pkg_object_string(pkg_config_get("EVENT_PIPE")); if (evpipe != NULL) connect_evpipe(evpipe); debug_level = pkg_object_int(pkg_config_get("DEBUG_LEVEL")); it = NULL; object = ucl_object_find_key(config, "PKG_ENV"); while ((cur = ucl_iterate_object(object, &it, true))) { evkey = ucl_object_key(cur); pkg_debug(1, "Setting env var: %s", evkey); if (evkey != NULL && evkey[0] != '\0') setenv(evkey, ucl_object_tostring_forced(cur), 1); } /* load the repositories */ load_repositories(reposdir, flags); setenv("HTTP_USER_AGENT", "pkg/"PKGVERSION, 1); /* bypass resolv.conf with specified NAMESERVER if any */ nsname = pkg_object_string(pkg_config_get("NAMESERVER")); if (nsname != NULL) set_nameserver(ucl_object_tostring_forced(o)); return (EPKG_OK); }
static int pkg_repo_binary_try_fetch(struct pkg_repo *repo, struct pkg *pkg, bool already_tried, bool mirror, const char *destdir) { char dest[MAXPATHLEN]; char url[MAXPATHLEN]; char *dir = NULL; bool fetched = false; struct stat st; char *path = NULL; const char *packagesite = NULL; ssize_t offset = -1; int retcode = EPKG_OK; assert((pkg->type & PKG_REMOTE) == PKG_REMOTE); if (mirror) { const char *cachedir; if (destdir != NULL) cachedir = destdir; else cachedir = pkg_object_string(pkg_config_get("PKG_CACHEDIR")); snprintf(dest, sizeof(dest), "%s/%s", cachedir, pkg->repopath); } else pkg_repo_binary_get_cached_name(repo, pkg, dest, sizeof(dest)); /* If it is already in the local cachedir, dont bother to * download it */ if (stat(dest, &st) == 0) { /* try to resume */ if (pkg->pkgsize > st.st_size) { offset = st.st_size; pkg_debug(1, "Resuming fetch"); } else { goto checksum; } } /* Create the dirs in cachedir */ dir = strdup(dest); if (dir == NULL || (path = dirname(dir)) == NULL) { pkg_emit_errno("dirname", dest); retcode = EPKG_FATAL; goto cleanup; } if ((retcode = mkdirs(path)) != EPKG_OK) goto cleanup; /* * In multi-repos the remote URL is stored in pkg[PKG_REPOURL] * For a single attached database the repository URL should be * defined by URL. */ packagesite = pkg_repo_url(repo); if (packagesite == NULL || packagesite[0] == '\0') { pkg_emit_error("URL is not defined"); retcode = 1; goto cleanup; } if (packagesite[strlen(packagesite) - 1] == '/') pkg_snprintf(url, sizeof(url), "%S%R", packagesite, pkg); else pkg_snprintf(url, sizeof(url), "%S/%R", packagesite, pkg); if (!mirror && strncasecmp(packagesite, "file://", 7) == 0) { free(dir); return (EPKG_OK); } retcode = pkg_fetch_file(repo, url, dest, 0, offset, pkg->pkgsize); fetched = true; if (retcode != EPKG_OK) goto cleanup; checksum: /* checksum calculation is expensive, if size does not match, skip it and assume failed checksum. */ if (stat(dest, &st) == -1 || pkg->pkgsize != st.st_size) { if (already_tried) { pkg_emit_error("cached package %s-%s: " "size mismatch, cannot continue", pkg->name, pkg->version); retcode = EPKG_FATAL; goto cleanup; } unlink(dest); free(dir); pkg_emit_error("cached package %s-%s: " "size mismatch, fetching from remote", pkg->name, pkg->version); return (pkg_repo_binary_try_fetch(repo, pkg, true, mirror, destdir)); } if (pkg_checksum_validate_file(dest, pkg->sum) != 0) { if (already_tried || fetched) { pkg_emit_error("%s-%s failed checksum " "from repository", pkg->name, pkg->version); retcode = EPKG_FATAL; } else { pkg_emit_error("cached package %s-%s: " "checksum mismatch, fetching from remote", pkg->name, pkg->version); unlink(dest); return (pkg_repo_binary_try_fetch(repo, pkg, true, mirror, destdir)); } } cleanup: if (retcode != EPKG_OK) unlink(dest); else if (!mirror && path != NULL) { (void)pkg_repo_binary_create_symlink(pkg, dest, path); } /* allowed even if dir is NULL */ free(dir); return (retcode); }
static int pkg_repo_binary_add_pkg(struct pkg *pkg, const char *pkg_path, sqlite3 *sqlite, bool forced) { const char *name, *version, *origin, *comment, *desc; const char *arch, *maintainer, *www, *prefix, *sum, *rpath; const char *olddigest, *manifestdigest; int64_t flatsize, pkgsize; int64_t licenselogic; int ret; struct pkg_dep *dep = NULL; struct pkg_option *option = NULL; struct pkg_shlib *shlib = NULL; const pkg_object *obj, *licenses, *categories, *annotations; pkg_iter it; int64_t package_id; pkg_get(pkg, PKG_ORIGIN, &origin, PKG_NAME, &name, PKG_VERSION, &version, PKG_COMMENT, &comment, PKG_DESC, &desc, PKG_ARCH, &arch, PKG_MAINTAINER, &maintainer, PKG_WWW, &www, PKG_PREFIX, &prefix, PKG_FLATSIZE, &flatsize, PKG_LICENSE_LOGIC, &licenselogic, PKG_CKSUM, &sum, PKG_PKGSIZE, &pkgsize, PKG_REPOPATH, &rpath, PKG_LICENSES, &licenses, PKG_CATEGORIES, &categories, PKG_ANNOTATIONS, &annotations, PKG_OLD_DIGEST, &olddigest, PKG_DIGEST, &manifestdigest); try_again: if ((ret = pkg_repo_binary_run_prstatement(PKG, origin, name, version, comment, desc, arch, maintainer, www, prefix, pkgsize, flatsize, (int64_t)licenselogic, sum, rpath, manifestdigest, olddigest)) != SQLITE_DONE) { if (ret == SQLITE_CONSTRAINT) { switch(pkg_repo_binary_delete_conflicting(origin, version, pkg_path, forced)) { case EPKG_FATAL: /* sqlite error */ ERROR_SQLITE(sqlite, pkg_repo_binary_sql_prstatement(PKG)); return (EPKG_FATAL); break; case EPKG_END: /* repo already has newer */ return (EPKG_END); break; default: /* conflict cleared, try again */ goto try_again; break; } } else { ERROR_SQLITE(sqlite, pkg_repo_binary_sql_prstatement(PKG)); return (EPKG_FATAL); } } package_id = sqlite3_last_insert_rowid(sqlite); if (pkg_repo_binary_run_prstatement (FTS_APPEND, package_id, name, version, origin) != SQLITE_DONE) { ERROR_SQLITE(sqlite, pkg_repo_binary_sql_prstatement(FTS_APPEND)); return (EPKG_FATAL); } dep = NULL; while (pkg_deps(pkg, &dep) == EPKG_OK) { if (pkg_repo_binary_run_prstatement(DEPS, pkg_dep_origin(dep), pkg_dep_name(dep), pkg_dep_version(dep), package_id) != SQLITE_DONE) { ERROR_SQLITE(sqlite, pkg_repo_binary_sql_prstatement(DEPS)); return (EPKG_FATAL); } } it = NULL; while ((obj = pkg_object_iterate(categories, &it))) { ret = pkg_repo_binary_run_prstatement(CAT1, pkg_object_string(obj)); if (ret == SQLITE_DONE) ret = pkg_repo_binary_run_prstatement(CAT2, package_id, pkg_object_string(obj)); if (ret != SQLITE_DONE) { ERROR_SQLITE(sqlite, pkg_repo_binary_sql_prstatement(CAT2)); return (EPKG_FATAL); } } it = NULL; while ((obj = pkg_object_iterate(licenses, &it))) { ret = pkg_repo_binary_run_prstatement(LIC1, pkg_object_string(obj)); if (ret == SQLITE_DONE) ret = pkg_repo_binary_run_prstatement(LIC2, package_id, pkg_object_string(obj)); if (ret != SQLITE_DONE) { ERROR_SQLITE(sqlite, pkg_repo_binary_sql_prstatement(LIC2)); return (EPKG_FATAL); } } option = NULL; while (pkg_options(pkg, &option) == EPKG_OK) { ret = pkg_repo_binary_run_prstatement(OPT1, pkg_option_opt(option)); if (ret == SQLITE_DONE) ret = pkg_repo_binary_run_prstatement(OPT2, pkg_option_opt(option), pkg_option_value(option), package_id); if(ret != SQLITE_DONE) { ERROR_SQLITE(sqlite, pkg_repo_binary_sql_prstatement(OPT2)); return (EPKG_FATAL); } } shlib = NULL; while (pkg_shlibs_required(pkg, &shlib) == EPKG_OK) { const char *shlib_name = pkg_shlib_name(shlib); ret = pkg_repo_binary_run_prstatement(SHLIB1, shlib_name); if (ret == SQLITE_DONE) ret = pkg_repo_binary_run_prstatement(SHLIB_REQD, package_id, shlib_name); if (ret != SQLITE_DONE) { ERROR_SQLITE(sqlite, pkg_repo_binary_sql_prstatement(SHLIB_REQD)); return (EPKG_FATAL); } } shlib = NULL; while (pkg_shlibs_provided(pkg, &shlib) == EPKG_OK) { const char *shlib_name = pkg_shlib_name(shlib); ret = pkg_repo_binary_run_prstatement(SHLIB1, shlib_name); if (ret == SQLITE_DONE) ret = pkg_repo_binary_run_prstatement(SHLIB_PROV, package_id, shlib_name); if (ret != SQLITE_DONE) { ERROR_SQLITE(sqlite, pkg_repo_binary_sql_prstatement(SHLIB_PROV)); return (EPKG_FATAL); } } it = NULL; while ((obj = pkg_object_iterate(annotations, &it))) { const char *note_tag = pkg_object_key(obj); const char *note_val = pkg_object_string(obj); ret = pkg_repo_binary_run_prstatement(ANNOTATE1, note_tag); if (ret == SQLITE_DONE) ret = pkg_repo_binary_run_prstatement(ANNOTATE1, note_val); if (ret == SQLITE_DONE) ret = pkg_repo_binary_run_prstatement(ANNOTATE2, package_id, note_tag, note_val); if (ret != SQLITE_DONE) { ERROR_SQLITE(sqlite, pkg_repo_binary_sql_prstatement(ANNOTATE2)); return (EPKG_FATAL); } } return (EPKG_OK); }
int pkg_repo_binary_create(struct pkg_repo *repo) { char filepath[MAXPATHLEN]; struct statfs stfs; const char *dbdir = NULL; sqlite3 *sqlite = NULL; int retcode; sqlite3_initialize(); dbdir = pkg_object_string(pkg_config_get("PKG_DBDIR")); snprintf(filepath, sizeof(filepath), "%s/%s", dbdir, pkg_repo_binary_get_filename(pkg_repo_name(repo))); /* Should never ever happen */ if (access(filepath, R_OK) == 0) return (EPKG_CONFLICT); /* * Fall back on unix-dotfile locking strategy if on a network filesystem */ if (statfs(dbdir, &stfs) == 0) { if ((stfs.f_flags & MNT_LOCAL) != MNT_LOCAL) sqlite3_vfs_register(sqlite3_vfs_find("unix-dotfile"), 1); } /* Open for read/write/create */ if (sqlite3_open(filepath, &sqlite) != SQLITE_OK) return (EPKG_FATAL); retcode = sql_exec(sqlite, binary_repo_initsql, REPO_SCHEMA_VERSION); if (retcode == EPKG_OK) { sqlite3_stmt *stmt; const char sql[] = "" "INSERT OR REPLACE INTO repodata (key, value) " "VALUES (\"packagesite\", ?1);"; /* register the packagesite */ if (sql_exec(sqlite, "CREATE TABLE IF NOT EXISTS repodata (" " key TEXT UNIQUE NOT NULL," " value TEXT NOT NULL" ");") != EPKG_OK) { pkg_emit_error("Unable to register the packagesite in the " "database"); retcode = EPKG_FATAL; goto cleanup; } if (sqlite3_prepare_v2(sqlite, sql, -1, &stmt, NULL) != SQLITE_OK) { ERROR_SQLITE(sqlite, sql); retcode = EPKG_FATAL; goto cleanup; } sqlite3_bind_text(stmt, 1, pkg_repo_url(repo), -1, SQLITE_STATIC); if (sqlite3_step(stmt) != SQLITE_DONE) { ERROR_SQLITE(sqlite, sql); sqlite3_finalize(stmt); retcode = EPKG_FATAL; goto cleanup; } sqlite3_finalize(stmt); } cleanup: sqlite3_close(sqlite); return (retcode); }