void pkg_shutdown(void) { if (!parsed) { pkg_emit_error("pkg_shutdown() must be called after pkg_init()"); _exit(EX_SOFTWARE); /* NOTREACHED */ } ucl_object_unref(config); HASH_FREE(repos, pkg_repo_free); parsed = false; return; }
pkg_formats packing_format_from_string(const char *str) { if (str == NULL) return TXZ; if (strcmp(str, "txz") == 0) return TXZ; if (strcmp(str, "tbz") == 0) return TBZ; if (strcmp(str, "tgz") == 0) return TGZ; if (strcmp(str, "tar") == 0) return TAR; pkg_emit_error("unknown format %s, using txz", str); return TXZ; }
bool is_valid_abi(const char *arch, bool emit_error) { const char *myarch; myarch = pkg_object_string(pkg_config_get("ABI")); if (fnmatch(arch, myarch, FNM_CASEFOLD) == FNM_NOMATCH && strncmp(arch, myarch, strlen(myarch)) != 0) { if (emit_error) pkg_emit_error("wrong architecture: %s instead of %s", arch, myarch); return (false); } return (true); }
static ucl_object_t * keyword_open_schema(void) { struct ucl_parser *parser; static const char keyword_schema_str[] = "" "{" " type = object;" " properties {" " actions = { " " type = array; " " items = { type = string }; " " uniqueItems: true " " }; " " attributes = { " " type = object; " " properties { " " owner = { type = string }; " " group = { type = string }; " " mode = { oneOf: [ { type = integer }, { type = string } ] }; " " }" " }; " " pre-install = { type = string }; " " post-install = { type = string }; " " pre-deinstall = { type = string }; " " post-deinstall = { type = string }; " " pre-upgrade = { type = string }; " " post-upgrade = { type = string }; " " }" "}"; if (keyword_schema != NULL) return (keyword_schema); parser = ucl_parser_new(0); if (!ucl_parser_add_chunk(parser, keyword_schema_str, sizeof(keyword_schema_str) -1)) { pkg_emit_error("Cannot parse schema for keywords: %s", ucl_parser_get_error(parser)); ucl_parser_free(parser); return (NULL); } keyword_schema = ucl_parser_get_object(parser); ucl_parser_free(parser); return (keyword_schema); }
static RSA * _load_rsa_public_key_buf(unsigned char *cert, int certlen) { RSA *rsa = NULL; BIO *bp; char errbuf[1024]; bp = BIO_new_mem_buf((void *)cert, certlen); if (!PEM_read_bio_RSA_PUBKEY(bp, &rsa, NULL, NULL)) { pkg_emit_error("error reading public key: %s", ERR_error_string(ERR_get_error(), errbuf)); BIO_free(bp); return (NULL); } BIO_free(bp); return (rsa); }
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); }
static int pkg_repo_fetch_remote_tmp(struct pkg_repo *repo, const char *filename, const char *extension, time_t *t, int *rc) { char url[MAXPATHLEN]; char tmp[MAXPATHLEN]; int fd; const char *tmpdir, *dot; /* * XXX: here we support old naming scheme, such as filename.yaml */ dot = strrchr(filename, '.'); if (dot != NULL) { snprintf(tmp, MIN(sizeof(tmp), dot - filename + 1), "%s", filename); snprintf(url, sizeof(url), "%s/%s.%s", pkg_repo_url(repo), tmp, extension); } else { snprintf(url, sizeof(url), "%s/%s.%s", pkg_repo_url(repo), filename, extension); } tmpdir = getenv("TMPDIR"); if (tmpdir == NULL) tmpdir = "/tmp"; mkdirs(tmpdir); snprintf(tmp, sizeof(tmp), "%s/%s.%s.XXXXXX", tmpdir, filename, extension); fd = mkstemp(tmp); if (fd == -1) { pkg_emit_error("Could not create temporary file %s, " "aborting update.\n", tmp); *rc = EPKG_FATAL; return (-1); } (void)unlink(tmp); if ((*rc = pkg_fetch_file_to_fd(repo, url, fd, t)) != EPKG_OK) { close(fd); fd = -1; } return (fd); }
static int parse_sequence(struct pkg * pkg, yaml_node_t *node, yaml_document_t *doc, int attr) { yaml_node_item_t *item; yaml_node_t *val; item = node->data.sequence.items.start; while (item < node->data.sequence.items.top) { val = yaml_document_get_node(doc, *item); switch (attr) { case PKG_CONFLICTS: if (val->type != YAML_SCALAR_NODE || val->data.scalar.length <= 0) pkg_emit_error("Skipping malformed conflict"); else pkg_addconflict(pkg, val->data.scalar.value); break; case PKG_CATEGORIES: if (val->type != YAML_SCALAR_NODE || val->data.scalar.length <= 0) pkg_emit_error("Skipping malformed category"); else pkg_addcategory(pkg, val->data.scalar.value); break; case PKG_LICENSES: if (val->type != YAML_SCALAR_NODE || val->data.scalar.length <= 0) pkg_emit_error("Skipping malformed license"); else pkg_addlicense(pkg, val->data.scalar.value); break; case PKG_USERS: if (val->type != YAML_SCALAR_NODE || val->data.scalar.length <= 0) pkg_emit_error("Skipping malformed license"); else pkg_adduser(pkg, val->data.scalar.value); break; case PKG_GROUPS: if (val->type != YAML_SCALAR_NODE || val->data.scalar.length <= 0) pkg_emit_error("Skipping malformed license"); else pkg_addgroup(pkg, val->data.scalar.value); break; case PKG_DIRS: if (val->type == YAML_SCALAR_NODE && val->data.scalar.length > 0) pkg_adddir(pkg, val->data.scalar.value, 1); else if (val->type == YAML_MAPPING_NODE) parse_mapping(pkg, val, doc, attr); else pkg_emit_error("Skipping malformed dirs"); } ++item; } return (EPKG_OK); }
static int set_repo_user_version(sqlite3 *sqlite, const char *database, int reposcver) { int retcode = EPKG_OK; char sql[BUFSIZ]; char *errmsg; const char *fmt = "PRAGMA %Q.user_version = %d;" ; assert(database != NULL); sqlite3_snprintf(sizeof(sql), sql, fmt, database, reposcver); if (sqlite3_exec(sqlite, sql, NULL, NULL, &errmsg) != SQLITE_OK) { pkg_emit_error("sqlite: %s", errmsg); sqlite3_free(errmsg); retcode = EPKG_FATAL; } return (retcode); }
static int pkg_set_licenselogic_from_node(struct pkg *pkg, yaml_node_t *val, __unused yaml_document_t *doc, __unused int attr) { if (!strcmp(val->data.scalar.value, "single")) pkg_set(pkg, PKG_LICENSE_LOGIC, (int64_t) LICENSE_SINGLE); else if (!strcmp(val->data.scalar.value, "or") || !strcmp(val->data.scalar.value, "dual")) pkg_set(pkg, PKG_LICENSE_LOGIC, (int64_t)LICENSE_OR); else if (!strcmp(val->data.scalar.value, "and") || !strcmp(val->data.scalar.value, "multi")) pkg_set(pkg, PKG_LICENSE_LOGIC, (int64_t)LICENSE_AND); else { pkg_emit_error("Unknown license logic: %s", val->data.scalar.value); return (EPKG_FATAL); } return (EPKG_OK); }
int pkg_create_installed(const char *outdir, pkg_formats format, struct pkg *pkg) { struct packing *pkg_archive; unsigned required_flags = PKG_LOAD_DEPS | PKG_LOAD_FILES | PKG_LOAD_CATEGORIES | PKG_LOAD_DIRS | PKG_LOAD_SCRIPTS | PKG_LOAD_OPTIONS | PKG_LOAD_MTREE | PKG_LOAD_LICENSES ; assert(pkg->type == PKG_INSTALLED || pkg->type == PKG_OLD_FILE); pkg_archive = pkg_create_archive(outdir, pkg, format, required_flags); if (pkg_archive == NULL) { pkg_emit_error("unable to create archive"); return (EPKG_FATAL); } pkg_create_from_dir(pkg, NULL, pkg_archive); return packing_finish(pkg_archive); }
static void walk_repo_obj(const ucl_object_t *obj, const char *file, pkg_init_flags flags) { const ucl_object_t *cur; ucl_object_iter_t it = NULL; struct pkg_repo *r; const char *key; while ((cur = ucl_iterate_object(obj, &it, true))) { key = ucl_object_key(cur); pkg_debug(1, "PkgConfig: parsing key '%s'", key); r = pkg_repo_find(key); if (r != NULL) pkg_debug(1, "PkgConfig: overwriting repository %s", key); if (cur->type == UCL_OBJECT) add_repo(cur, r, key, flags); else pkg_emit_error("Ignoring bad configuration entry in %s: %s", file, ucl_object_emit(cur, UCL_EMIT_YAML)); } }
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; while (pkg_files(pkg, &file) == EPKG_OK) { const char *sum = pkg_file_cksum(file); if (file->keep == 1) continue; path = pkg_file_path(file); /* Regular files and links */ /* check sha256 */ if (!force && sum[0] != '\0') { if (sha256_file(path, sha256) != EPKG_OK) continue; if (strcmp(sha256, sum)) { pkg_emit_error("%s fails original SHA256 " "checksum, not removing", path); continue; } } if (unlink(path) == -1) { if (force < 2) pkg_emit_errno("unlink", path); continue; } } return (EPKG_OK); }
static int urldecode(const char *src, struct sbuf **dest) { size_t len; size_t i; char c; char hex[] = {'\0', '\0', '\0'}; sbuf_init(dest); len = strlen(src); for (i = 0; i < len; i++) { if (src[i] != '%') { sbuf_putc(*dest, src[i]); } else { if (i + 2 > len) { pkg_emit_error("unexpected end of string"); return (EPKG_FATAL); } hex[0] = src[++i]; hex[1] = src[++i]; errno = 0; c = strtol(hex, NULL, 16); if (errno != 0) { /* * if it fails consider this is not a urlencoded * information */ sbuf_printf(*dest, "%%%s", hex); } else { sbuf_putc(*dest, c); } } } sbuf_finish(*dest); return (EPKG_OK); }
static RSA * load_rsa_public_key(const char *rsa_key_path) { FILE *fp; RSA *rsa = NULL; char errbuf[1024]; if ((fp = fopen(rsa_key_path, "rb")) == 0) { pkg_emit_errno("fopen", rsa_key_path); return (NULL); } if (!PEM_read_RSA_PUBKEY( fp, &rsa, NULL, NULL )) { pkg_emit_error("error reading public key(%s): %s", rsa_key_path, ERR_error_string(ERR_get_error(), errbuf)); fclose(fp); return (NULL); } fclose(fp); return (rsa); }
bool pkg_compiled_for_same_os_major(void) { #ifdef OSMAJOR struct utsname u; int osmajor; /* Are we running the same OS major version as the one we were * compiled under? */ if (uname(&u) != 0) { pkg_emit_error("Cannot determine OS version number"); return (true); /* Can't tell, so assume yes */ } osmajor = (int) strtol(u.release, NULL, 10); return (osmajor == OSMAJOR); #else return (true); /* Can't tell, so assume yes */ #endif }
static int rsa_verify_cert_cb(int fd, void *ud) { struct rsa_verify_cbdata *cbdata = ud; char *sha256; char *hash; char errbuf[1024]; RSA *rsa = NULL; int ret; sha256 = pkg_checksum_fd(fd, PKG_HASH_TYPE_SHA256_HEX); if (sha256 == NULL) return (EPKG_FATAL); hash = pkg_checksum_data(sha256, strlen(sha256), PKG_HASH_TYPE_SHA256_RAW); free(sha256); rsa = _load_rsa_public_key_buf(cbdata->key, cbdata->keylen); if (rsa == NULL) { free(hash); return (EPKG_FATAL); } ret = RSA_verify(NID_sha256, hash, pkg_checksum_type_size(PKG_HASH_TYPE_SHA256_RAW), cbdata->sig, cbdata->siglen, rsa); free(hash); if (ret == 0) { pkg_emit_error("rsa verify failed: %s", ERR_error_string(ERR_get_error(), errbuf)); RSA_free(rsa); return (EPKG_FATAL); } RSA_free(rsa); return (EPKG_OK); }
static int urldecode(const char *src, struct sbuf **dest) { size_t len; size_t i; char c; char hex[] = {'\0', '\0', '\0'}; if (*dest == NULL) *dest = sbuf_new_auto(); else sbuf_reset(*dest); len = strlen(src); for (i = 0; i < len; i++) { if (src[i] != '%') { sbuf_putc(*dest, src[i]); } else { if (i + 2 > len) { pkg_emit_error("unexpected end of string"); return (EPKG_FATAL); } hex[0] = src[++i]; hex[1] = src[++i]; errno = 0; c = strtol(hex, NULL, 16); if (errno != 0) { pkg_emit_errno("strtol()", hex); return (EPKG_FATAL); } sbuf_putc(*dest, c); } } sbuf_finish(*dest); return (EPKG_OK); }
/* The "no concessions to old pkg_tools" variant: just get everything * from the manifest */ int pkg_create_from_manifest(const char *outdir, pkg_formats format, const char *rootdir, const char *manifest, const char *plist) { struct pkg *pkg = NULL; struct packing *pkg_archive = NULL; int ret = ENOMEM; pkg_debug(1, "Creating package from stage directory: '%s'", rootdir); if(pkg_new(&pkg, PKG_FILE) != EPKG_OK) { ret = EPKG_FATAL; goto cleanup; } if ((ret = pkg_load_metadata(pkg, manifest, NULL, plist, rootdir, false)) != EPKG_OK) { ret = EPKG_FATAL; goto cleanup; } /* Create the archive */ pkg_archive = pkg_create_archive(outdir, pkg, format, 0); if (pkg_archive == NULL) { ret = EPKG_FATAL; /* XXX do better */ goto cleanup; } if ((ret = pkg_create_from_dir(pkg, rootdir, pkg_archive)) != EPKG_OK) pkg_emit_error("package creation failed"); cleanup: free(pkg); packing_finish(pkg_archive); return (ret); }
static int pkg_string(struct pkg *pkg, ucl_object_t *obj, int attr) { int ret = EPKG_OK; const char *str; str = ucl_object_tostring_forced(obj); switch (attr) { case PKG_INFOS: pkg_addannotation(pkg, "_INFOS_", str); break; case PKG_LICENSE_LOGIC: if (!strcmp(str, "single")) pkg_set(pkg, PKG_LICENSE_LOGIC, (int64_t) LICENSE_SINGLE); else if (!strcmp(str, "or") || !strcmp(str, "dual")) pkg_set(pkg, PKG_LICENSE_LOGIC, (int64_t)LICENSE_OR); else if (!strcmp(str, "and") || !strcmp(str, "multi")) pkg_set(pkg, PKG_LICENSE_LOGIC, (int64_t)LICENSE_AND); else { pkg_emit_error("Unknown license logic: %s", str); ret = EPKG_FATAL; } break; default: if (attr == PKG_DESC) ret = urldecode(str, &pkg->fields[attr]); else ret = pkg_set(pkg, attr, str); break; } return (ret); }
static int pkg_repo_binary_update_incremental(const char *name, struct pkg_repo *repo, time_t *mtime, bool force) { FILE *fmanifest = NULL, *fdigests = NULL /*, *fconflicts = NULL*/; struct pkg *pkg = NULL; int rc = EPKG_FATAL; sqlite3 *sqlite = NULL; sqlite3_stmt *stmt; const char *origin, *digest, *offset, *length, *checksum; char *linebuf = NULL, *p; int updated = 0, removed = 0, added = 0, processed = 0, pushed = 0; long num_offset, num_length; time_t local_t; time_t digest_t; time_t packagesite_t; struct pkg_increment_task_item *ldel = NULL, *ladd = NULL, *item, *tmp_item; struct pkg_manifest_key *keys = NULL; size_t linecap = 0; ssize_t linelen; char *map = MAP_FAILED; size_t len = 0; int hash_it = 0; bool in_trans = false, legacy_repo = false; /* Required for making iterator */ struct pkgdb_it *it = NULL; struct pkgdb fakedb; pkg_debug(1, "Pkgrepo, begin incremental update of '%s'", name); /* In forced mode, ignore mtime */ if (force) *mtime = 0; /* Fetch meta */ local_t = *mtime; if (pkg_repo_fetch_meta(repo, &local_t) == EPKG_FATAL) pkg_emit_notice("repository %s has no meta file, using " "default settings", repo->name); /* Fetch digests */ local_t = *mtime; fdigests = pkg_repo_fetch_remote_extract_tmp(repo, repo->meta->digests, &local_t, &rc); if (fdigests == NULL) goto cleanup; /* Fetch packagesite */ digest_t = local_t; local_t = *mtime; fmanifest = pkg_repo_fetch_remote_extract_tmp(repo, repo->meta->manifests, &local_t, &rc); if (fmanifest == NULL) goto cleanup; packagesite_t = local_t; *mtime = digest_t; /*fconflicts = repo_fetch_remote_extract_tmp(repo, repo_conflicts_archive, "txz", &local_t, &rc, repo_conflicts_file);*/ fseek(fmanifest, 0, SEEK_END); len = ftell(fmanifest); /* Detect whether we have legacy repo */ if ((linelen = getline(&linebuf, &linecap, fdigests)) > 0) { p = linebuf; origin = strsep(&p, ":"); digest = strsep(&p, ":"); if (digest == NULL) { pkg_emit_error("invalid digest file format"); rc = EPKG_FATAL; goto cleanup; } if (!pkg_checksum_is_valid(digest, strlen(digest))) { legacy_repo = true; pkg_debug(1, "repository '%s' has a legacy digests format", repo->name); } } fseek(fdigests, 0, SEEK_SET); /* Load local repository data */ rc = pkg_repo_binary_init_update(repo, name, force); if (rc == EPKG_END) { /* Need to perform forced update */ repo->ops->close(repo, false); return (pkg_repo_binary_update_incremental(name, repo, mtime, true)); } if (rc != EPKG_OK) { rc = EPKG_FATAL; goto cleanup; } /* Here sqlite is initialized */ sqlite = PRIV_GET(repo); stmt = pkg_repo_binary_get_origins(sqlite); if (stmt == NULL) { rc = EPKG_FATAL; goto cleanup; } fakedb.sqlite = sqlite; it = pkgdb_it_new_sqlite(&fakedb, stmt, PKG_REMOTE, PKGDB_IT_FLAG_ONCE); if (it != NULL) { while (pkgdb_it_next(it, &pkg, PKG_LOAD_BASIC) == EPKG_OK) { pkg_get(pkg, PKG_ORIGIN, &origin, legacy_repo ? PKG_OLD_DIGEST : PKG_DIGEST, &digest, PKG_CKSUM, &checksum); pkg_repo_binary_update_item_new(&ldel, origin, digest, 0, 0, checksum); } pkgdb_it_free(it); } else { sqlite3_finalize(stmt); } pkg_debug(1, "Pkgrepo, reading new packagesite.yaml for '%s'", name); /* load the while digests */ while ((linelen = getline(&linebuf, &linecap, fdigests)) > 0) { p = linebuf; origin = strsep(&p, ":"); digest = strsep(&p, ":"); offset = strsep(&p, ":"); /* files offset */ strsep(&p, ":"); length = p ? strsep(&p, ":\n") : NULL; checksum = p ? strsep(&p, ":\n") : NULL; if (origin == NULL || digest == NULL || offset == NULL) { pkg_emit_error("invalid digest file format"); rc = EPKG_FATAL; goto cleanup; } errno = 0; num_offset = (long)strtoul(offset, NULL, 10); if (errno != 0) { pkg_emit_errno("strtoul", "digest format error"); rc = EPKG_FATAL; goto cleanup; } if (length != NULL) { errno = 0; num_length = (long)strtoul(length, NULL, 10); if (errno != 0) { pkg_emit_errno("strtoul", "digest format error"); rc = EPKG_FATAL; goto cleanup; } } else { num_length = 0; } processed++; HASH_FIND_STR(ldel, origin, item); if (item == NULL) { added++; pkg_repo_binary_update_item_new(&ladd, origin, digest, num_offset, num_length, checksum); } else { HASH_DEL(ldel, item); if (checksum == NULL || item->checksum == NULL) { pkg_repo_binary_update_item_new(&ladd, origin, digest, num_offset, num_length, checksum); updated++; } else if (strcmp(checksum, item->checksum) != 0) { /* Allow checksum to be used as unique mark */ pkg_repo_binary_update_item_new(&ladd, origin, digest, num_offset, num_length, checksum); updated++; } pkg_repo_binary_update_item_free(item); } } rc = EPKG_OK; pkg_debug(1, "Pkgrepo, removing old entries for '%s'", name); rc = pkgdb_transaction_begin(sqlite, "REPO"); if (rc != EPKG_OK) goto cleanup; in_trans = true; removed = HASH_COUNT(ldel); hash_it = 0; if (removed > 0) pkg_emit_progress_start("Removing expired repository entries"); HASH_ITER(hh, ldel, item, tmp_item) { pkg_emit_progress_tick(++hash_it, removed); if (rc == EPKG_OK) { rc = pkgdb_repo_remove_package(item->origin); } else { pkg_emit_progress_tick(removed, removed); } HASH_DEL(ldel, item); pkg_repo_binary_update_item_free(item); }
int pkgdb_repo_check_version(struct pkgdb *db, const char *database) { int reposcver; int repomajor; int ret; assert(db != NULL); assert(database != NULL); if ((ret = get_repo_user_version(db->sqlite, database, &reposcver)) != EPKG_OK) return (ret); /* sqlite error */ /* * If the local pkgng uses a repo schema behind that used to * create the repo, we may still be able use it for reading * (ie pkg install), but pkg repo can't do an incremental * update unless the actual schema matches the compiled in * schema version. * * Use a major - minor version schema: as the user_version * PRAGMA takes an integer version, encode this as MAJOR * * 1000 + MINOR. * * So long as the major versions are the same, the local pkgng * should be compatible with any repo created by a more recent * pkgng, although it may need some modification of the repo * schema */ /* --- Temporary ---- Grandfather in the old repo schema version so this patch doesn't immediately invalidate all the repos out there */ if (reposcver == 2) reposcver = 2000; if (reposcver == 3) reposcver = 2001; repomajor = reposcver / 1000; if (repomajor < REPO_SCHEMA_MAJOR) { pkg_emit_error("Repo %s (schema version %d) is too old - " "need at least schema %d", database, reposcver, REPO_SCHEMA_MAJOR * 1000); return (EPKG_REPOSCHEMA); } if (repomajor > REPO_SCHEMA_MAJOR) { pkg_emit_error("Repo %s (schema version %d) is too new - " "we can accept at most schema %d", database, reposcver, ((REPO_SCHEMA_MAJOR + 1) * 1000) - 1); return (EPKG_REPOSCHEMA); } /* This is a repo schema version we can work with */ ret = EPKG_OK; if (reposcver < REPO_SCHEMA_VERSION) { if (sqlite3_db_readonly(db->sqlite, database)) { pkg_emit_error("Repo %s needs schema upgrade from " "%d to %d but it is opened readonly", database, reposcver, REPO_SCHEMA_VERSION ); ret = EPKG_FATAL; } else ret = upgrade_repo_schema(db, database, reposcver); } else if (reposcver > REPO_SCHEMA_VERSION) { if (sqlite3_db_readonly(db->sqlite, database)) { pkg_emit_error("Repo %s needs schema downgrade from " "%d to %d but it is opened readonly", database, reposcver, REPO_SCHEMA_VERSION ); ret = EPKG_FATAL; } else ret = downgrade_repo_schema(db, database, reposcver); } return (ret); }
static int apply_repo_change(struct pkgdb *db, const char *database, const struct repo_changes *repo_changes, const char *updown, int version, int *next_version) { const struct repo_changes *change; bool found = false, in_trans = false; int ret = EPKG_OK; char sql[8192]; char *errmsg; for (change = repo_changes; change->version != -1; change++) { if (change->version == version) { found = true; break; } } if (!found) { pkg_emit_error("Failed to %s \"%s\" repo schema " " version %d (target version %d) " "-- change not found", updown, database, version, REPO_SCHEMA_VERSION); return (EPKG_FATAL); } /* substitute the repo database name */ ret = substitute_into_sql(sql, sizeof(sql), change->sql, database); /* begin transaction */ if (ret == EPKG_OK) { in_trans = true; ret = pkgdb_transaction_begin(db->sqlite, "SCHEMA"); } /* apply change */ if (ret == EPKG_OK) { pkg_debug(4, "Pkgdb: running '%s'", sql); ret = sqlite3_exec(db->sqlite, sql, NULL, NULL, &errmsg); if (ret != SQLITE_OK) { pkg_emit_error("sqlite: %s", errmsg); sqlite3_free(errmsg); ret = EPKG_FATAL; } } /* update repo user_version */ if (ret == EPKG_OK) { *next_version = change->next_version; ret = set_repo_user_version(db->sqlite, database, *next_version); } /* commit or rollback */ if (in_trans) { if (ret != EPKG_OK) pkgdb_transaction_rollback(db->sqlite, "SCHEMA"); if (pkgdb_transaction_commit(db->sqlite, "SCHEMA") != EPKG_OK) ret = EPKG_FATAL; } if (ret == EPKG_OK) { pkg_emit_notice("Repo \"%s\" %s schema %d to %d: %s", database, updown, version, change->next_version, change->message); } return (ret); }
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 pkg_create_staged(const char *outdir, pkg_formats format, const char *rootdir, const char *md_dir, char *plist, bool old) { struct pkg *pkg = NULL; struct pkg_file *file = NULL; struct pkg_dir *dir = NULL; struct packing *pkg_archive = NULL; char *manifest = NULL; char path[MAXPATHLEN]; char arch[BUFSIZ]; int ret = ENOMEM; char *buf; int i; regex_t preg; regmatch_t pmatch[2]; size_t size; char *www = NULL; struct pkg_manifest_key *keys = NULL; pkg_debug(1, "Creating package from stage directory: '%s'", rootdir); /* Load the manifest from the metadata directory */ if (snprintf(path, sizeof(path), "%s/+MANIFEST", md_dir) == -1) goto cleanup; if(pkg_new(&pkg, old ? PKG_OLD_FILE : PKG_FILE) != EPKG_OK) { ret = EPKG_FATAL; goto cleanup; } pkg_manifest_keys_new(&keys); if ((ret = pkg_parse_manifest_file(pkg, path, keys)) != EPKG_OK) { ret = EPKG_FATAL; goto cleanup; } /* if no descriptions provided then try to get it from a file */ pkg_get(pkg, PKG_DESC, &buf); if (buf == NULL) { if (snprintf(path, sizeof(path), "%s/+DESC", md_dir) == -1) goto cleanup; if (access(path, F_OK) == 0) { pkg_debug(1, "Taking description from: '%s'", path); pkg_set_from_file(pkg, PKG_DESC, path, false); } } /* if no message try to get it from a file */ pkg_get(pkg, PKG_MESSAGE, &buf); if (buf == NULL) { ret = snprintf(path, sizeof(path), "%s/+DISPLAY", md_dir); if (ret == -1) goto cleanup; if (access(path, F_OK) == 0) { pkg_debug(1, "Taking message from: '%s'", path); pkg_set_from_file(pkg, PKG_MESSAGE, path, false); } } /* if no arch autodetermine it */ pkg_get(pkg, PKG_ARCH, &buf); if (buf == NULL) { pkg_get_myarch(arch, BUFSIZ); pkg_set(pkg, PKG_ARCH, arch); } /* if no mtree try to get it from a file */ pkg_get(pkg, PKG_MTREE, &buf); if (buf == NULL) { ret = snprintf(path, sizeof(path), "%s/+MTREE_DIRS", md_dir); if (ret == -1) goto cleanup; if (access(path, F_OK) == 0) { pkg_debug(1, "Taking mtree definition from: '%s'", path); pkg_set_from_file(pkg, PKG_MTREE, path, false); } } for (i = 0; scripts[i] != NULL; i++) { snprintf(path, sizeof(path), "%s/%s", md_dir, scripts[i]); if (access(path, F_OK) == 0) pkg_addscript_file(pkg, path); } if (plist != NULL && ports_parse_plist(pkg, plist, rootdir) != EPKG_OK) { ret = EPKG_FATAL; goto cleanup; } /* if www is not given then try to determine it from description */ if (www != NULL) { pkg_set(pkg, PKG_WWW, www); free(www); } pkg_get(pkg, PKG_WWW, &www); if (www == NULL) { pkg_get(pkg, PKG_DESC, &buf); if (buf == NULL) { pkg_emit_error("No www or desc defined in manifest"); ret = EPKG_FATAL; goto cleanup; } regcomp(&preg, "^WWW:[[:space:]]*(.*)$", REG_EXTENDED|REG_ICASE|REG_NEWLINE); if (regexec(&preg, buf, 2, pmatch, 0) == 0) { size = pmatch[1].rm_eo - pmatch[1].rm_so; www = strndup(&buf[pmatch[1].rm_so], size); pkg_set(pkg, PKG_WWW, www); free(www); } else { pkg_set(pkg, PKG_WWW, "UNKNOWN"); } regfree(&preg); } /* Create the archive */ pkg_archive = pkg_create_archive(outdir, pkg, format, 0); if (pkg_archive == NULL) { ret = EPKG_FATAL; /* XXX do better */ goto cleanup; } /* XXX: autoplist support doesn't work right with meta-ports */ if (0 && pkg_files(pkg, &file) != EPKG_OK && pkg_dirs(pkg, &dir) != EPKG_OK) { /* Now traverse the file directories, adding to the archive */ packing_append_tree(pkg_archive, md_dir, NULL); packing_append_tree(pkg_archive, rootdir, "/"); } else { pkg_create_from_dir(pkg, rootdir, pkg_archive); } ret = EPKG_OK; cleanup: free(pkg); free(manifest); pkg_manifest_keys_free(keys); if (ret == EPKG_OK) ret = packing_finish(pkg_archive); return ret; }
int packing_append_file_attr(struct packing *pack, const char *filepath, const char *newpath, const char *uname, const char *gname, mode_t perm, u_long fflags) { int fd; int retcode = EPKG_OK; int ret; time_t source_time; struct stat st; struct archive_entry *entry, *sparse_entry; bool unset_timestamp; const char *source_date_epoch; char buf[32768]; int len; entry = archive_entry_new(); archive_entry_copy_sourcepath(entry, filepath); pkg_debug(2, "Packing file '%s'", filepath); if (lstat(filepath, &st) != 0) { pkg_emit_errno("lstat", filepath); retcode = EPKG_FATAL; goto cleanup; } ret = archive_read_disk_entry_from_file(pack->aread, entry, -1, &st); if (ret != ARCHIVE_OK) { pkg_emit_error("%s: %s", filepath, archive_error_string(pack->aread)); retcode = EPKG_FATAL; goto cleanup; } if (newpath != NULL) archive_entry_set_pathname(entry, newpath); if (archive_entry_filetype(entry) != AE_IFREG) { archive_entry_set_size(entry, 0); } if (uname != NULL && uname[0] != '\0') { archive_entry_set_uname(entry, uname); } if (gname != NULL && gname[0] != '\0') { archive_entry_set_gname(entry, gname); } if (fflags > 0) archive_entry_set_fflags(entry, fflags, 0); if (perm != 0) archive_entry_set_perm(entry, perm); unset_timestamp = pkg_object_bool(pkg_config_get("UNSET_TIMESTAMP")); if (unset_timestamp) { archive_entry_unset_atime(entry); archive_entry_unset_ctime(entry); archive_entry_unset_mtime(entry); archive_entry_unset_birthtime(entry); } if ((source_date_epoch = getenv("SOURCE_DATE_EPOCH")) != NULL) { if (source_date_epoch[strspn(source_date_epoch, "0123456789")] != '\0') { pkg_emit_error("Bad environment variable " "SOURCE_DATE_EPOCH: %s", source_date_epoch); retcode = EPKG_FATAL; goto cleanup; } source_time = strtoll(source_date_epoch, NULL, 10); archive_entry_set_atime(entry, source_time, 0); archive_entry_set_ctime(entry, source_time, 0); archive_entry_set_mtime(entry, source_time, 0); archive_entry_set_birthtime(entry, source_time, 0); } archive_entry_linkify(pack->resolver, &entry, &sparse_entry); if (sparse_entry != NULL && entry == NULL) entry = sparse_entry; archive_write_header(pack->awrite, entry); if (archive_entry_size(entry) <= 0) goto cleanup; if ((fd = open(filepath, O_RDONLY)) < 0) { pkg_emit_errno("open", filepath); retcode = EPKG_FATAL; goto cleanup; } while ((len = read(fd, buf, sizeof(buf))) > 0) { if (archive_write_data(pack->awrite, buf, len) == -1) { pkg_emit_errno("archive_write_data", "archive write error"); retcode = EPKG_FATAL; break; } } if (len == -1) { pkg_emit_errno("read", "file read error"); retcode = EPKG_FATAL; } close(fd); cleanup: archive_entry_free(entry); return (retcode); }
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); }
int format_exec_cmd(char **dest, const char *in, const char *prefix, const char *plist_file, char *line) { struct sbuf *buf = sbuf_new_auto(); char path[MAXPATHLEN + 1]; char *cp; while (in[0] != '\0') { if (in[0] == '%') { in++; switch(in[0]) { case 'D': sbuf_cat(buf, prefix); break; case 'F': if (plist_file == NULL) { pkg_emit_error("No files defined %%F couldn't be expanded, ignoring %s", in); sbuf_finish(buf); sbuf_free(buf); return (EPKG_FATAL); } sbuf_cat(buf, plist_file); break; case 'f': if (plist_file == NULL) { pkg_emit_error("No files defined %%f couldn't be expanded, ignoring %s", in); sbuf_finish(buf); sbuf_free(buf); return (EPKG_FATAL); } if (prefix[strlen(prefix) - 1] == '/') snprintf(path, sizeof(path), "%s%s", prefix, plist_file); else snprintf(path, sizeof(path), "%s/%s", prefix, plist_file); cp = strrchr(path, '/'); cp ++; sbuf_cat(buf, cp); break; case 'B': if (plist_file == NULL) { pkg_emit_error("No files defined %%B couldn't be expanded, ignoring %s", in); sbuf_finish(buf); sbuf_free(buf); return (EPKG_FATAL); } if (prefix[strlen(prefix) - 1] == '/') snprintf(path, sizeof(path), "%s%s", prefix, plist_file); else snprintf(path, sizeof(path), "%s/%s", prefix, plist_file); cp = strrchr(path, '/'); cp[0] = '\0'; sbuf_cat(buf, path); break; case '%': sbuf_putc(buf, '%'); break; case '@': if (line != NULL) { sbuf_cat(buf, line); break; } /* * no break here because if line is not * given (default exec) %@ does not * exists */ default: sbuf_putc(buf, '%'); sbuf_putc(buf, in[0]); break; } } else { sbuf_putc(buf, in[0]); } in++; } sbuf_finish(buf); *dest = strdup(sbuf_data(buf)); sbuf_free(buf); return (EPKG_OK); }
static void add_repo(const ucl_object_t *obj, struct pkg_repo *r, const char *rname, pkg_init_flags flags) { const ucl_object_t *cur, *enabled; ucl_object_iter_t it = NULL; bool enable = true; const char *url = NULL, *pubkey = NULL, *mirror_type = NULL; const char *signature_type = NULL, *fingerprints = NULL; const char *key; const char *type = NULL; int use_ipvx = 0; pkg_debug(1, "PkgConfig: parsing repository object %s", rname); enabled = ucl_object_find_key(obj, "enabled"); if (enabled == NULL) enabled = ucl_object_find_key(obj, "ENABLED"); if (enabled != NULL) { enable = ucl_object_toboolean(enabled); if (!enable && r == NULL) { pkg_debug(1, "PkgConfig: skipping disabled repo %s", rname); return; } else if (!enable && r != NULL) { /* * We basically want to remove the existing repo r and * forget all stuff parsed */ pkg_debug(1, "PkgConfig: disabling repo %s", rname); HASH_DEL(repos, r); pkg_repo_free(r); return; } } while ((cur = ucl_iterate_object(obj, &it, true))) { key = ucl_object_key(cur); if (key == NULL) continue; if (strcasecmp(key, "url") == 0) { if (cur->type != UCL_STRING) { pkg_emit_error("Expecting a string for the " "'%s' key of the '%s' repo", key, rname); return; } url = ucl_object_tostring(cur); } else if (strcasecmp(key, "pubkey") == 0) { if (cur->type != UCL_STRING) { pkg_emit_error("Expecting a string for the " "'%s' key of the '%s' repo", key, rname); return; } pubkey = ucl_object_tostring(cur); } else if (strcasecmp(key, "mirror_type") == 0) { if (cur->type != UCL_STRING) { pkg_emit_error("Expecting a string for the " "'%s' key of the '%s' repo", key, rname); return; } mirror_type = ucl_object_tostring(cur); } else if (strcasecmp(key, "signature_type") == 0) { if (cur->type != UCL_STRING) { pkg_emit_error("Expecting a string for the " "'%s' key of the '%s' repo", key, rname); return; } signature_type = ucl_object_tostring(cur); } else if (strcasecmp(key, "fingerprints") == 0) { if (cur->type != UCL_STRING) { pkg_emit_error("Expecting a string for the " "'%s' key of the '%s' repo", key, rname); return; } fingerprints = ucl_object_tostring(cur); } else if (strcasecmp(key, "type") == 0) { if (cur->type != UCL_STRING) { pkg_emit_error("Expecting a string for the " "'%s' key of the '%s' repo", key, rname); return; } type = ucl_object_tostring(cur); } else if (strcasecmp(key, "ip_version") == 0) { if (cur->type != UCL_INT) { pkg_emit_error("Expecting a integer for the " "'%s' key of the '%s' repo", key, rname); return; } use_ipvx = ucl_object_toint(cur); if (use_ipvx != 4 && use_ipvx != 6) use_ipvx = 0; } } if (r == NULL && url == NULL) { pkg_debug(1, "No repo and no url for %s", rname); return; } if (r == NULL) r = pkg_repo_new(rname, url, type); else pkg_repo_overwrite(r, rname, url, type); if (signature_type != NULL) { if (strcasecmp(signature_type, "pubkey") == 0) r->signature_type = SIG_PUBKEY; else if (strcasecmp(signature_type, "fingerprints") == 0) r->signature_type = SIG_FINGERPRINT; else r->signature_type = SIG_NONE; } if (fingerprints != NULL) { free(r->fingerprints); r->fingerprints = strdup(fingerprints); } if (pubkey != NULL) { free(r->pubkey); r->pubkey = strdup(pubkey); } r->enable = enable; if (mirror_type != NULL) { if (strcasecmp(mirror_type, "srv") == 0) r->mirror_type = SRV; else if (strcasecmp(mirror_type, "http") == 0) r->mirror_type = HTTP; else r->mirror_type = NOMIRROR; } if ((flags & PKG_INIT_FLAG_USE_IPV4) == PKG_INIT_FLAG_USE_IPV4) use_ipvx = 4; else if ((flags & PKG_INIT_FLAG_USE_IPV6) == PKG_INIT_FLAG_USE_IPV6) use_ipvx = 6; if (use_ipvx != 4 && use_ipvx != 6) use_ipvx = pkg_object_int(pkg_config_get("IP_VERSION")); if (use_ipvx == 4) r->flags = REPO_FLAGS_USE_IPV4; else if (use_ipvx == 6) r->flags = REPO_FLAGS_USE_IPV6; }
static int pkg_jobs_universe_process_deps(struct pkg_jobs_universe *universe, struct pkg *pkg, unsigned flags) { struct pkg_dep *d = NULL; int (*deps_func)(const struct pkg *pkg, struct pkg_dep **d); int rc; struct pkg_job_universe_item *unit; struct pkg *npkg, *rpkg; pkg_chain_t *rpkgs = NULL; bool found = false; rpkg = NULL; rc = EPKG_OK; if (flags & DEPS_FLAG_REVERSE) { deps_func = pkg_rdeps; } else { deps_func = pkg_deps; } while (deps_func(pkg, &d) == EPKG_OK) { HASH_FIND_STR(universe->items, d->uid, unit); if (unit != NULL) { continue; } rpkgs = NULL; npkg = NULL; if (!(flags & DEPS_FLAG_MIRROR)) { npkg = pkg_jobs_universe_get_local(universe, d->uid, 0); } if (!(flags & DEPS_FLAG_FORCE_LOCAL)) { /* Check for remote dependencies */ rpkgs = pkg_jobs_universe_get_remote(universe, d->uid, 0); } if (npkg == NULL && rpkgs == NULL) { pkg_emit_error("%s has a missing dependency: %s", pkg->name, d->name); if (flags & DEPS_FLAG_FORCE_MISSING) { continue; } return (EPKG_FATAL); } if (npkg != NULL) { if (pkg_jobs_universe_process_item(universe, npkg, &unit) != EPKG_OK) { continue; } } if (rpkgs == NULL) continue; /* * When processing deps, we should first try to select a dependency * from the same repo. * Otherwise, we would have ping-pong of dependencies instead of * the situation when this behaviour is handled by * CONSERVATIVE_UPGRADES. * * Important notes here: * 1. We are looking for packages that are dependencies of a package * `pkg` * 2. Now if `pkg` belongs to repo `r` and `rpkg` belongs to repo * `r` then we just select it. * 3. If `rpkg` is not found in `r` we just scan all packages */ /* * XXX: this is the proper place to expand flexible dependencies */ found = false; /* Iteration one */ for (int i = 0; i < kv_size(*rpkgs); i++) { rpkg = kv_A(*rpkgs, i); if (pkg->reponame && rpkg->reponame && strcmp (pkg->reponame, rpkg->reponame) == 0) { found = true; break; } } /* Fallback if a dependency is not found in the same repo */ if (!found) { for (int i = 0; i < kv_size(*rpkgs); i++) { rpkg = kv_A(*rpkgs, i); if (npkg != NULL) { /* Set reason for upgrades */ if (!pkg_jobs_need_upgrade(rpkg, npkg)) continue; /* Save automatic flag */ rpkg->automatic = npkg->automatic; } rc = pkg_jobs_universe_process_item(universe, rpkg, NULL); /* Special case if we cannot find any package */ if (npkg == NULL && rc != EPKG_OK) { kv_destroy(*rpkgs); free(rpkgs); return (rc); } } } else { assert (rpkg != NULL); if (npkg != NULL) { /* Set reason for upgrades */ if (!pkg_jobs_need_upgrade(rpkg, npkg)) continue; /* Save automatic flag */ rpkg->automatic = npkg->automatic; } rc = pkg_jobs_universe_process_item(universe, rpkg, NULL); if (npkg == NULL && rc != EPKG_OK) { kv_destroy(*rpkgs); free(rpkgs); return (rc); } } kv_destroy(*rpkgs); free(rpkgs); } return (EPKG_OK); }