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); }
void set_globals(void) { yes = pkg_object_bool(pkg_config_get("ASSUME_ALWAYS_YES")); dry_run = 0; auto_update = pkg_object_bool(pkg_config_get("REPO_AUTOUPDATE")); case_sensitive = pkg_object_bool(pkg_config_get("CASE_SENSITIVE_MATCH")); force = 0; quiet = 0; newpkgversion = 0; }
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 int filter_system_shlibs(const char *name, char *path, size_t pathlen) { const char *shlib_path; shlib_path = shlib_list_find_by_name(name); if (shlib_path == NULL) { /* dynamic linker could not resolve */ return (EPKG_FATAL); } if (pkg_object_bool(pkg_config_get("ALLOW_BASE_SHLIBS"))) { if (strstr(shlib_path, "/lib32/") != NULL) return (EPKG_END); } else { /* match /lib, /lib32, /usr/lib and /usr/lib32 */ if (strncmp(shlib_path, "/lib", 4) == 0 || strncmp(shlib_path, "/usr/lib", 8) == 0) return (EPKG_END); /* ignore libs from base */ } if (path != NULL) strncpy(path, shlib_path, pathlen); 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 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); }
void pkg_emit_deinstall_finished(struct pkg *p) { struct pkg_event ev; bool syslog_enabled = false; ev.type = PKG_EVENT_DEINSTALL_FINISHED; ev.e_deinstall_finished.pkg = p; syslog_enabled = pkg_object_bool(pkg_config_get("SYSLOG")); if (syslog_enabled) { syslog(LOG_NOTICE, "%s-%s deinstalled", p->name, p->version); } pkg_emit_event(&ev); }
void pkg_emit_install_finished(struct pkg *p) { struct pkg_event ev; bool syslog_enabled = false; char *name, *version; ev.type = PKG_EVENT_INSTALL_FINISHED; ev.e_install_finished.pkg = p; syslog_enabled = pkg_object_bool(pkg_config_get("SYSLOG")); if (syslog_enabled) { pkg_get(p, PKG_NAME, &name, PKG_VERSION, &version); syslog(LOG_NOTICE, "%s-%s installed", name, version); } pkg_emit_event(&ev); }
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); } }
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 do_extract(struct archive *a, struct archive_entry *ae, const char *location, int nfiles, struct pkg *pkg, struct pkg *local) { int retcode = EPKG_OK; int ret = 0, cur_file = 0; char path[MAXPATHLEN], pathname[MAXPATHLEN], rpath[MAXPATHLEN]; struct stat st; const struct stat *aest; bool renamed = false; const struct pkg_file *rf; struct pkg_config_file *rcf; struct sbuf *newconf; bool automerge = pkg_object_bool(pkg_config_get("AUTOMERGE")); unsigned long set, clear; #ifndef HAVE_ARC4RANDOM srand(time(NULL)); #endif if (nfiles == 0) return (EPKG_OK); pkg_emit_extract_begin(pkg); pkg_emit_progress_start(NULL); newconf = sbuf_new_auto(); do { ret = ARCHIVE_OK; sbuf_clear(newconf); rf = NULL; rcf = NULL; pkg_absolutepath(archive_entry_pathname(ae), path, sizeof(path)); snprintf(pathname, sizeof(pathname), "%s%s%s", location ? location : "", *path == '/' ? "" : "/", path ); strlcpy(rpath, pathname, sizeof(rpath)); aest = archive_entry_stat(ae); archive_entry_fflags(ae, &set, &clear); if (lstat(rpath, &st) != -1) { /* * We have an existing file on the path, so handle it */ if (!S_ISDIR(aest->st_mode)) { pkg_debug(2, "Old version found, renaming"); pkg_add_file_random_suffix(rpath, sizeof(rpath), 12); renamed = true; } if (!S_ISDIR(st.st_mode) && S_ISDIR(aest->st_mode)) { if (S_ISLNK(st.st_mode)) { if (stat(rpath, &st) == -1) { pkg_emit_error("Dead symlink %s", rpath); } else { pkg_debug(2, "Directory is a symlink, use it"); pkg_emit_progress_tick(cur_file++, nfiles); continue; } } } } archive_entry_set_pathname(ae, rpath); /* load in memory the content of config files */ if (pkg_is_config_file(pkg, path, &rf, &rcf)) { pkg_debug(1, "Populating config_file %s", pathname); size_t len = archive_entry_size(ae); rcf->content = malloc(len); archive_read_data(a, rcf->content, len); if (renamed && (!automerge || local == NULL)) strlcat(pathname, ".pkgnew", sizeof(pathname)); } /* * check if the file is already provided by previous package */ if (!automerge) attempt_to_merge(renamed, rcf, local, pathname, path, newconf); if (sbuf_len(newconf) == 0 && (rcf == NULL || rcf->content == NULL)) { pkg_debug(1, "Extracting: %s", archive_entry_pathname(ae)); int install_as_user = (getenv("INSTALL_AS_USER") != NULL); int extract_flags = EXTRACT_ARCHIVE_FLAGS; if (install_as_user) { /* when installing as user don't try to set file ownership */ extract_flags &= ~ARCHIVE_EXTRACT_OWNER; } ret = archive_read_extract(a, ae, extract_flags); } else { if (sbuf_len(newconf) == 0) { sbuf_cat(newconf, rcf->content); sbuf_finish(newconf); } pkg_debug(2, "Writing conf in %s", pathname); unlink(rpath); FILE *f = fopen(rpath, "w+"); fprintf(f, "%s", sbuf_data(newconf)); fclose(f); } if (ret != ARCHIVE_OK) { /* * show error except when the failure is during * extracting a directory and that the directory already * exists. * this allow to install packages linux_base from * package for example */ if (archive_entry_filetype(ae) != AE_IFDIR || !is_dir(pathname)) { pkg_emit_error("archive_read_extract(): %s", archive_error_string(a)); retcode = EPKG_FATAL; goto cleanup; } } /* Reapply modes to the directories to work around a problem on FreeBSD 9 */ if (archive_entry_filetype(ae) == AE_IFDIR) chmod(pathname, aest->st_mode); pkg_emit_progress_tick(cur_file++, nfiles); /* Rename old file */ if (renamed) { pkg_debug(1, "Renaming %s -> %s", rpath, pathname); #ifdef HAVE_CHFLAGS bool old = false; if (set & NOCHANGESFLAGS) chflags(rpath, 0); if (lstat(pathname, &st) != -1) { old = true; if (st.st_flags & NOCHANGESFLAGS) chflags(pathname, 0); } #endif if (rename(rpath, pathname) == -1) { #ifdef HAVE_CHFLAGS /* restore flags */ if (old) chflags(pathname, st.st_flags); #endif pkg_emit_error("cannot rename %s to %s: %s", rpath, pathname, strerror(errno)); retcode = EPKG_FATAL; goto cleanup; } #ifdef HAVE_CHFLAGS /* Restore flags */ chflags(pathname, set); #endif } if (string_end_with(pathname, ".pkgnew")) pkg_emit_notice("New configuration file: %s", pathname); renamed = false; } while ((ret = archive_read_next_header(a, &ae)) == ARCHIVE_OK); if (ret != ARCHIVE_EOF) { pkg_emit_error("archive_read_next_header(): %s", archive_error_string(a)); retcode = EPKG_FATAL; } cleanup: pkg_emit_progress_tick(nfiles, nfiles); pkg_emit_extract_finished(pkg); if (renamed && retcode == EPKG_FATAL) { #ifdef HAVE_CHFLAGS if (set & NOCHANGESFLAGS) chflags(rpath, set & ~NOCHANGESFLAGS); #endif unlink(rpath); } return (retcode); }
retcode = EPKG_OK; cleanup: pkg_emit_add_deps_finished(pkg); return (retcode); } static int pkg_add_cleanup_old(struct pkgdb *db, struct pkg *old, struct pkg *new, int flags) { struct pkg_file *f; int ret = EPKG_OK; bool handle_rc; handle_rc = pkg_object_bool(pkg_config_get("HANDLE_RC_SCRIPTS")); if (handle_rc) pkg_start_stop_rc_scripts(old, PKG_RC_STOP); /* * Execute pre deinstall scripts */ if ((flags & PKG_ADD_NOSCRIPT) == 0) { if ((flags & PKG_ADD_USE_UPGRADE_SCRIPTS) == PKG_ADD_USE_UPGRADE_SCRIPTS) ret = pkg_script_run(old, PKG_SCRIPT_PRE_UPGRADE); else ret = pkg_script_run(old, PKG_SCRIPT_PRE_DEINSTALL); if (ret != EPKG_OK) return (ret); }
int exec_register(int argc, char **argv) { struct pkg *pkg = NULL; struct pkgdb *db = NULL; struct pkg_manifest_key *keys = NULL; regex_t preg; regmatch_t pmatch[2]; char *arch = NULL; char myarch[BUFSIZ]; char *www = NULL; char fpath[MAXPATHLEN]; const char *plist = NULL; const char *mdir = NULL; const char *mfile = NULL; const char *input_path = NULL; const char *desc = NULL; const char *location = NULL; size_t size; bool developer; bool legacy = false; bool old = false; bool __unused metadata_only = false; bool testing_mode = false; int ch; int i; int ret = EPKG_OK; int retcode = EX_OK; /* options descriptor */ struct option longopts[] = { { "automatic", no_argument, NULL, 'A' }, { "plist", required_argument, NULL, 'f' }, { "root", required_argument, NULL, 'i' }, { "legacy", no_argument, NULL, 'l' }, { "manifest", required_argument, NULL, 'M' }, { "metadata", required_argument, NULL, 'm' }, { "old", no_argument, NULL, 'O' }, { "test", no_argument, NULL, 't' }, { "relocate", required_argument, NULL, 1 }, { NULL, 0, NULL, 0}, }; developer = pkg_object_bool(pkg_config_get("DEVELOPER_MODE")); if (pkg_new(&pkg, PKG_INSTALLED) != EPKG_OK) err(EX_OSERR, "malloc"); while ((ch = getopt_long(argc, argv, "Adf:i:lM:m:Ot", longopts, NULL)) != -1) { switch (ch) { case 'A': case 'd': pkg_set(pkg, PKG_AUTOMATIC, (bool)true); break; case 'f': plist = optarg; break; case 'i': input_path = optarg; break; case 'l': legacy = true; break; case 'M': metadata_only = true; mfile = optarg; break; case 'm': mdir = optarg; break; case 'O': old = true; break; case 't': testing_mode = true; break; case 1: location = optarg; break; default: warnx("Unrecognised option -%c\n", ch); usage_register(); return (EX_USAGE); } } if (!old) { retcode = pkgdb_access(PKGDB_MODE_READ | PKGDB_MODE_WRITE | PKGDB_MODE_CREATE, PKGDB_DB_LOCAL); if (retcode == EPKG_ENOACCESS) { warnx("Insufficient privileges to register packages"); return (EX_NOPERM); } else if (retcode != EPKG_OK) return (EX_IOERR); else retcode = EX_OK; } /* * Ideally, the +MANIFEST should be all that is necessary, * since it can contain all of the meta-data supplied by the * other files mentioned below. These are here for backwards * compatibility with the way the ports tree works with * pkg_tools. * * The -M option specifies one manifest file to read the * meta-data from, and overrides the use of legacy meta-data * inputs. * * Dependencies, shlibs, files etc. may be derived by * analysing the package files (maybe discovered as the * content of the staging directory) unless -t (testing_mode) * is used. */ if (mfile != NULL && mdir != NULL) { warnx("Cannot use both -m and -M together"); usage_register(); return (EX_USAGE); } if (mfile == NULL && mdir == NULL) { warnx("One of either -m or -M flags is required"); usage_register(); return (EX_USAGE); } if (mfile != NULL && plist != NULL) { warnx("-M incompatible with -f option"); usage_register(); return (EX_USAGE); } if (testing_mode && input_path != NULL) { warnx("-i incompatible with -t option"); usage_register(); return (EX_USAGE); } pkg_manifest_keys_new(&keys); if (mfile != NULL) { ret = pkg_parse_manifest_file(pkg, mfile, keys); pkg_manifest_keys_free(keys); if (ret != EPKG_OK) return (EX_IOERR); } else { snprintf(fpath, sizeof(fpath), "%s/+MANIFEST", mdir); ret = pkg_parse_manifest_file(pkg, fpath, keys); pkg_manifest_keys_free(keys); if (ret != EPKG_OK) return (EX_IOERR); snprintf(fpath, sizeof(fpath), "%s/+DESC", mdir); pkg_set_from_file(pkg, PKG_DESC, fpath, false); snprintf(fpath, sizeof(fpath), "%s/+DISPLAY", mdir); if (access(fpath, F_OK) == 0) pkg_set_from_file(pkg, PKG_MESSAGE, fpath, false); snprintf(fpath, sizeof(fpath), "%s/+MTREE_DIRS", mdir); if (access(fpath, F_OK) == 0) pkg_set_from_file(pkg, PKG_MTREE, fpath, false); for (i = 0; scripts[i] != NULL; i++) { snprintf(fpath, sizeof(fpath), "%s/%s", mdir, scripts[i]); if (access(fpath, F_OK) == 0) pkg_addscript_file(pkg, fpath); } if (www != NULL) { pkg_set(pkg, PKG_WWW, www); free(www); } pkg_get(pkg, PKG_WWW, &www); /* * if www is not given then try to determine it from * description */ if (www == NULL) { pkg_get(pkg, PKG_DESC, &desc); regcomp(&preg, "^WWW:[[:space:]]*(.*)$", REG_EXTENDED|REG_ICASE|REG_NEWLINE); if (regexec(&preg, desc, 2, pmatch, 0) == 0) { size = pmatch[1].rm_eo - pmatch[1].rm_so; www = strndup(&desc[pmatch[1].rm_so], size); pkg_set(pkg, PKG_WWW, www); free(www); } else { pkg_set(pkg, PKG_WWW, "UNKNOWN"); } regfree(&preg); } if (plist != NULL) ret += ports_parse_plist(pkg, plist, input_path); } if (ret != EPKG_OK) { return (EX_IOERR); } if (!old) { if (pkgdb_open(&db, PKGDB_DEFAULT) != EPKG_OK) return (EX_IOERR); if (pkgdb_obtain_lock(db, PKGDB_LOCK_EXCLUSIVE) != EPKG_OK) { pkgdb_close(db); warnx("Cannot get an exclusive lock on a database, it is locked by another process"); return (EX_TEMPFAIL); } } /* * testing_mode allows updating the local package database * without any check that the files etc. listed in the meta * data actually exist on the system. Inappropriate use of * testing_mode can really screw things up. */ if (!testing_mode) pkg_analyse_files(db, pkg, input_path); pkg_get(pkg, PKG_ARCH, &arch); if (arch == NULL) { /* * do not take the one from configuration on purpose * but the real abi of the package. */ pkg_get_myarch(myarch, BUFSIZ); if (developer) pkg_suggest_arch(pkg, myarch, true); pkg_set(pkg, PKG_ARCH, myarch); } else { if (developer) pkg_suggest_arch(pkg, arch, false); } if (!testing_mode && input_path != NULL) pkg_copy_tree(pkg, input_path, location ? location : "/"); if (location != NULL) pkg_addannotation(pkg, "relocated", location); if (old) { if (pkg_register_old(pkg) != EPKG_OK) retcode = EX_SOFTWARE; } else { if (pkgdb_register_ports(db, pkg) != EPKG_OK) retcode = EX_SOFTWARE; } if (!legacy && pkg_has_message(pkg)) pkg_printf("%M\n", pkg); if (!old) { pkgdb_release_lock(db, PKGDB_LOCK_EXCLUSIVE); pkgdb_close(db); } pkg_free(pkg); return (retcode); }
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_upgrade(int argc, char **argv) { struct pkgdb *db = NULL; struct pkg_jobs *jobs = NULL; const char *reponame = NULL; int retcode; int updcode; int ch; int lock_type = PKGDB_LOCK_ADVISORY; bool yes = true, yes_arg = false; bool dry_run = false; bool auto_update; int done = 0; nbactions = nbdone = 0; pkg_flags f = PKG_FLAG_NONE | PKG_FLAG_PKG_VERSION_TEST; yes_arg = pkg_object_bool(pkg_config_get("ASSUME_ALWAYS_YES")); auto_update = pkg_object_bool(pkg_config_get("REPO_AUTOUPDATE")); while ((ch = getopt(argc, argv, "fInqFr:Uy")) != -1) { switch (ch) { case 'f': f |= PKG_FLAG_FORCE; break; case 'I': f |= PKG_FLAG_NOSCRIPT; break; case 'U': auto_update = false; break; case 'n': f |= PKG_FLAG_DRY_RUN; lock_type = PKGDB_LOCK_READONLY; dry_run = true; break; case 'F': f |= PKG_FLAG_SKIP_INSTALL; lock_type = PKGDB_LOCK_READONLY; break; case 'q': quiet = true; break; case 'r': reponame = optarg; break; case 'y': yes_arg = true; break; default: usage_upgrade(); return (EX_USAGE); /* NOTREACHED */ } } argc -= optind; argv += optind; if (argc != 0) { usage_upgrade(); return (EX_USAGE); } if (dry_run && !auto_update) retcode = pkgdb_access(PKGDB_MODE_READ, PKGDB_DB_LOCAL|PKGDB_DB_REPO); else retcode = pkgdb_access(PKGDB_MODE_READ | PKGDB_MODE_WRITE | PKGDB_MODE_CREATE, PKGDB_DB_LOCAL|PKGDB_DB_REPO); if (retcode == EPKG_ENOACCESS && dry_run) { auto_update = false; retcode = pkgdb_access(PKGDB_MODE_READ, PKGDB_DB_LOCAL|PKGDB_DB_REPO); } if (retcode == EPKG_ENOACCESS) { warnx("Insufficient privilege to upgrade packages"); return (EX_NOPERM); } else if (retcode != EPKG_OK) return (EX_IOERR); else retcode = EX_SOFTWARE; /* first update the remote repositories if needed */ if (auto_update && (updcode = pkgcli_update(false, reponame)) != EPKG_OK) return (updcode); if (pkgdb_open_all(&db, PKGDB_REMOTE, reponame) != EPKG_OK) return (EX_IOERR); if (pkgdb_obtain_lock(db, lock_type, 0, 0) != EPKG_OK) { pkgdb_close(db); warnx("Cannot get an advisory lock on a database, it is locked by another process"); return (EX_TEMPFAIL); } if (pkg_jobs_new(&jobs, PKG_JOBS_UPGRADE, db) != EPKG_OK) goto cleanup; if (reponame != NULL && pkg_jobs_set_repository(jobs, reponame) != EPKG_OK) goto cleanup; pkg_jobs_set_flags(jobs, f); if (pkg_jobs_solve(jobs) != EPKG_OK) goto cleanup; while ((nbactions = pkg_jobs_count(jobs)) > 0) { /* print a summary before applying the jobs */ yes = yes_arg; if (!quiet || dry_run) { print_jobs_summary(jobs, "The following %d packages will be affected (of %d checked):\n\n", nbactions, pkg_jobs_total(jobs)); if (!yes && !dry_run) yes = query_yesno(false, "\nProceed with this action [y/N]: "); if (dry_run) yes = false; } if (yes) { retcode = pkg_jobs_apply(jobs); done = 1; if (retcode == EPKG_CONFLICT) { printf ("The conflicts with the existing packages have been found.\n" "We need to run one more solver iteration to resolve them.\n"); continue; } else if (retcode != EPKG_OK) goto cleanup; } if (messages != NULL) { sbuf_finish(messages); printf("%s", sbuf_data(messages)); } break; } if (done == 0 && yes) printf("Your packages are up to date\n"); retcode = EX_OK; cleanup: pkg_jobs_free(jobs); pkgdb_release_lock(db, lock_type); pkgdb_close(db); if (!yes && newpkgversion) newpkgversion = false; return (retcode); }
int exec_set(int argc, char **argv) { struct pkgdb *db = NULL; struct pkgdb_it *it = NULL; struct pkg *pkg = NULL; int ch; int i; bool yes; match_t match = MATCH_EXACT; int64_t newautomatic = -1; bool automatic = false; const char *errstr; char *neworigin = NULL; char *oldorigin = NULL; unsigned int loads = PKG_LOAD_BASIC; unsigned int sets = 0; int retcode; yes = pkg_object_bool(pkg_config_get("ASSUME_ALWAYS_YES")); while ((ch = getopt(argc, argv, "A:agio:xy")) != -1) { switch (ch) { case 'A': sets |= AUTOMATIC; newautomatic = strtonum(optarg, 0, 1, &errstr); if (errstr) errx(EX_USAGE, "Wrong value for -A. " "Expecting 0 or 1, got: %s (%s)", optarg, errstr); break; case 'a': match = MATCH_ALL; break; case 'g': match = MATCH_GLOB; break; case 'i': pkgdb_set_case_sensitivity(false); break; case 'o': sets |= ORIGIN; loads |= PKG_LOAD_DEPS; match = MATCH_ALL; oldorigin = strdup(optarg); neworigin = strrchr(oldorigin, ':'); if (neworigin == NULL) { free(oldorigin); errx(EX_USAGE, "Wrong format for -o. " "Expecting oldorigin:neworigin, got: %s", optarg); } *neworigin = '\0'; neworigin++; if (strrchr(oldorigin, '/') == NULL || strrchr(neworigin, '/') == NULL) { free(oldorigin); errx(EX_USAGE, "Bad origin format, got: %s", optarg); } break; case 'x': match = MATCH_REGEX; break; case 'y': yes = true; break; default: if (oldorigin != NULL) free(oldorigin); usage_set(); return (EX_USAGE); } } argc -= optind; argv += optind; if ((argc < 1 && match != MATCH_ALL) || (newautomatic == -1 && neworigin == NULL)) { usage_set(); return (EX_USAGE); } retcode = pkgdb_access(PKGDB_MODE_READ|PKGDB_MODE_WRITE, PKGDB_DB_LOCAL); if (retcode == EPKG_ENODB) { if (match == MATCH_ALL) return (EX_OK); if (!quiet) warnx("No packages installed. Nothing to do!"); return (EX_OK); } else if (retcode == EPKG_ENOACCESS) { warnx("Insufficient privileges to modify the package database"); return (EX_NOPERM); } else if (retcode != EPKG_OK) { warnx("Error accessing package database"); return (EX_SOFTWARE); } if (pkgdb_open(&db, PKGDB_DEFAULT) != EPKG_OK) return (EX_IOERR); if (pkgdb_obtain_lock(db, PKGDB_LOCK_EXCLUSIVE, 0, 0) != EPKG_OK) { pkgdb_close(db); warnx("Cannot get an exclusive lock on a database, it is locked by another process"); return (EX_TEMPFAIL); } if (oldorigin != NULL) { match = MATCH_ALL; if ((it = pkgdb_query(db, oldorigin, MATCH_EXACT)) == NULL) { retcode = EX_IOERR; goto cleanup; } if (pkgdb_it_next(it, &pkg, PKG_LOAD_BASIC) != EPKG_OK) { pkg = NULL; /* fprintf(stderr, "%s not installed\n", oldorigin); free(oldorigin); pkgdb_it_free(it); pkgdb_close(db); return (EX_SOFTWARE);*/ } if (!yes) { if (pkg != NULL) yes = query_yesno(false, "Change origin from %S to %S for %n-%v? [y/N]: ", oldorigin, neworigin, pkg, pkg); else yes = query_yesno(false, "Change origin from %S to %S for all dependencies? " "[y/N]: ", oldorigin, neworigin); } if (pkg != NULL && yes) { if (pkgdb_set(db, pkg, PKG_SET_ORIGIN, neworigin) != EPKG_OK) { retcode = EX_IOERR; goto cleanup; } } pkgdb_it_free(it); } i = 0; do { bool save_yes = yes; if ((it = pkgdb_query(db, argv[i], match)) == NULL) { retcode = EX_IOERR; goto cleanup; } while (pkgdb_it_next(it, &pkg, loads) == EPKG_OK) { if ((sets & AUTOMATIC) == AUTOMATIC) { pkg_get(pkg, PKG_AUTOMATIC, &automatic); if (automatic == newautomatic) continue; if (!yes) { if (newautomatic) yes = query_yesno(false, "Mark %n-%v as automatically installed? [y/N]: ", pkg, pkg); else yes = query_yesno(false, "Mark %n-%v as not automatically installed? [y/N]: ", pkg, pkg); } if (yes) pkgdb_set(db, pkg, PKG_SET_AUTOMATIC, newautomatic); yes = save_yes; } if ((sets & ORIGIN) == ORIGIN) { struct pkg_dep *d = NULL; while (pkg_deps(pkg, &d) == EPKG_OK) { /* * Do not query user when he has already * been queried. */ if (pkgdb_set(db, pkg, PKG_SET_DEPORIGIN, oldorigin, neworigin) != EPKG_OK) { retcode = EX_IOERR; goto cleanup; } } } } pkgdb_it_free(it); i++; } while (i < argc); cleanup: if (oldorigin) free(oldorigin); if (pkg != NULL) pkg_free(pkg); pkgdb_release_lock(db, PKGDB_LOCK_EXCLUSIVE); pkgdb_close(db); return (retcode); }
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 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); }
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); }
int pkg_delete(struct pkg *pkg, struct pkgdb *db, unsigned flags) { struct pkg_dep *rdep = NULL; int ret; bool handle_rc = false; const char *origin; assert(pkg != NULL); assert(db != NULL); /* * Do not trust the existing entries as it may have changed if we * delete packages in batch. */ pkg_list_free(pkg, PKG_RDEPS); /* * Ensure that we have all the informations we need */ if ((ret = pkgdb_load_rdeps(db, pkg)) != EPKG_OK) return (ret); if ((ret = pkgdb_load_files(db, pkg)) != EPKG_OK) return (ret); if ((ret = pkgdb_load_dirs(db, pkg)) != EPKG_OK) return (ret); if ((ret = pkgdb_load_scripts(db, pkg)) != EPKG_OK) return (ret); if ((ret = pkgdb_load_mtree(db, pkg)) != EPKG_OK) return (ret); if ((ret = pkgdb_load_annotations(db, pkg)) != EPKG_OK) return (ret); if ((flags & PKG_DELETE_UPGRADE) == 0) pkg_emit_deinstall_begin(pkg); /* If the package is locked */ if (pkg_is_locked(pkg)) { pkg_emit_locked(pkg); return (EPKG_LOCKED); } /* If there are dependencies */ if ((flags & (PKG_DELETE_UPGRADE|PKG_DELETE_CONFLICT)) == 0) { if (pkg_rdeps(pkg, &rdep) == EPKG_OK) { pkg_emit_required(pkg, flags & PKG_DELETE_FORCE); if ((flags & PKG_DELETE_FORCE) == 0) return (EPKG_REQUIRED); } } /* * stop the different related services if the users do want that * and that the service is running */ handle_rc = pkg_object_bool(pkg_config_get("HANDLE_RC_SCRIPTS")); if (handle_rc) pkg_start_stop_rc_scripts(pkg, PKG_RC_STOP); if ((flags & PKG_DELETE_NOSCRIPT) == 0) { if (flags & PKG_DELETE_UPGRADE) { ret = pkg_script_run(pkg, PKG_SCRIPT_PRE_UPGRADE); if (ret != EPKG_OK) return (ret); } else { ret = pkg_script_run(pkg, PKG_SCRIPT_PRE_DEINSTALL); if (ret != EPKG_OK) return (ret); } } if ((ret = pkg_delete_files(pkg, flags & PKG_DELETE_FORCE ? 1 : 0)) != EPKG_OK) return (ret); if ((flags & (PKG_DELETE_NOSCRIPT | PKG_DELETE_UPGRADE)) == 0) { ret = pkg_script_run(pkg, PKG_SCRIPT_POST_DEINSTALL); if (ret != EPKG_OK) return (ret); } ret = pkg_delete_dirs(db, pkg, flags & PKG_DELETE_FORCE); if (ret != EPKG_OK) return (ret); if ((flags & PKG_DELETE_UPGRADE) == 0) pkg_emit_deinstall_finished(pkg); pkg_get(pkg, PKG_ORIGIN, &origin); return (pkgdb_unregister_pkg(db, origin)); }
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_analyse_files(struct pkgdb *db, struct pkg *pkg, const char *stage) { struct pkg_file *file = NULL; char *sh; khint_t k; int ret = EPKG_OK; char fpath[MAXPATHLEN]; const char *lib; bool failures = false; if (kh_count(pkg->shlibs_required) != 0) pkg_list_free(pkg, PKG_SHLIBS_REQUIRED); if (kh_count(pkg->shlibs_provided) != 0) pkg_list_free(pkg, PKG_SHLIBS_PROVIDED); if (elf_version(EV_CURRENT) == EV_NONE) return (EPKG_FATAL); shlib_list_init(); if (stage != NULL && pkg_object_bool(pkg_config_get("ALLOW_BASE_SHLIBS"))) { /* Do not check the return */ shlib_list_from_stage(stage); } ret = shlib_list_from_elf_hints(_PATH_ELF_HINTS); if (ret != EPKG_OK) goto cleanup; /* Assume no architecture dependence, for contradiction */ if (developer_mode) pkg->flags &= ~(PKG_CONTAINS_ELF_OBJECTS | PKG_CONTAINS_STATIC_LIBS | PKG_CONTAINS_H_OR_LA); while (pkg_files(pkg, &file) == EPKG_OK) { if (stage != NULL) snprintf(fpath, sizeof(fpath), "%s/%s", stage, file->path); else strlcpy(fpath, file->path, sizeof(fpath)); ret = analyse_elf(pkg, fpath); if (developer_mode) { if (ret != EPKG_OK && ret != EPKG_END) { failures = true; continue; } analyse_fpath(pkg, fpath); } } /* * Do not depend on libraries that a package provides itself */ kh_each_value(pkg->shlibs_required, sh, { if (kh_contains(strings, pkg->shlibs_provided, sh)) { pkg_debug(2, "remove %s from required shlibs as the " "package %s provides this library itself", sh, pkg->name); k = kh_get_strings(pkg->shlibs_required, sh); kh_del_strings(pkg->shlibs_required, k); continue; } file = NULL; while (pkg_files(pkg, &file) == EPKG_OK) { if ((lib = strstr(file->path, sh)) != NULL && strlen(lib) == strlen(sh) && lib[-1] == '/') { pkg_debug(2, "remove %s from required shlibs as " "the package %s provides this library itself", sh, pkg->name); k = kh_get_strings(pkg->shlibs_required, sh); kh_del_strings(pkg->shlibs_required, k); break; } } });
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 exec_create(int argc, char **argv) { match_t match = MATCH_EXACT; const char *outdir = NULL; const char *format = NULL; const char *rootdir = NULL; const char *metadatadir = NULL; const char *manifest = NULL; char *plist = NULL; pkg_formats fmt; int ch; bool overwrite = true; bool hash = false; /* POLA: pkg create is quiet by default, unless * PKG_CREATE_VERBOSE is set in pkg.conf. This is for * historical reasons. */ quiet = !pkg_object_bool(pkg_config_get("PKG_CREATE_VERBOSE")); struct option longopts[] = { { "all", no_argument, NULL, 'a' }, { "format", required_argument, NULL, 'f' }, { "glob", no_argument, NULL, 'g' }, { "hash", no_argument, NULL, 'h' }, { "regex", no_argument, NULL, 'x' }, { "root-dir", required_argument, NULL, 'r' }, { "metadata", required_argument, NULL, 'm' }, { "manifest", required_argument, NULL, 'M' }, { "no-clobber", no_argument, NULL, 'n' }, { "out-dir", required_argument, NULL, 'o' }, { "plist", required_argument, NULL, 'p' }, { "quiet", no_argument, NULL, 'q' }, { "verbose", no_argument, NULL, 'v' }, { NULL, 0, NULL, 0 }, }; while ((ch = getopt_long(argc, argv, "+aghxf:r:m:M:o:np:qv", longopts, NULL)) != -1) { switch (ch) { case 'a': match = MATCH_ALL; break; case 'f': format = optarg; break; case 'g': match = MATCH_GLOB; break; case 'h': hash = true; break; case 'm': metadatadir = optarg; break; case 'M': manifest = optarg; break; case 'n': overwrite = false; break; case 'o': outdir = optarg; break; case 'p': plist = optarg; break; case 'q': quiet = true; break; case 'r': rootdir = optarg; break; case 'v': quiet = false; break; case 'x': match = MATCH_REGEX; break; default: usage_create(); return (EX_USAGE); } } argc -= optind; argv += optind; if (match != MATCH_ALL && metadatadir == NULL && manifest == NULL && argc == 0) { usage_create(); return (EX_USAGE); } if (metadatadir == NULL && manifest == NULL && rootdir != NULL) { warnx("Do not specify a rootdir without also specifying " "either a metadatadir or manifest"); usage_create(); return (EX_USAGE); } if (outdir == NULL) outdir = "./"; if (format == NULL) { fmt = TXZ; } else { if (format[0] == '.') ++format; if (strcmp(format, "txz") == 0) fmt = TXZ; else if (strcmp(format, "tbz") == 0) fmt = TBZ; else if (strcmp(format, "tgz") == 0) fmt = TGZ; else if (strcmp(format, "tar") == 0) fmt = TAR; else { warnx("unknown format %s, using txz", format); fmt = TXZ; } } if (metadatadir == NULL && manifest == NULL) { return (pkg_create_matches(argc, argv, match, fmt, outdir, overwrite) == EPKG_OK ? EX_OK : EX_SOFTWARE); } else if (metadatadir != NULL) { return (pkg_create_staged(outdir, fmt, rootdir, metadatadir, plist, hash) == EPKG_OK ? EX_OK : EX_SOFTWARE); } else { /* (manifest != NULL) */ return (pkg_create_from_manifest(outdir, fmt, rootdir, manifest, plist) == EPKG_OK ? EX_OK : EX_SOFTWARE); } }
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_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); }