/** * @file lib/initend.c * @brief Initialization and finalization routines * @defgroup initend Initialization and finalization functions * * Use these functions to initialize some parameters before start * using libxbps and finalize usage to release resources at the end. */ static void store_vpkg(struct xbps_handle *xhp, const char *path, size_t line, char *vpkg_s) { /* * Append virtual package overrides to our vpkgd dictionary: * * <key>vpkgver</key> * <string>realpkgname</string> */ char *vpkg, *rpkg, *tc; size_t vpkglen; if (xhp->vpkgd == NULL) xhp->vpkgd = xbps_dictionary_create(); /* real pkg after ':' */ vpkg = vpkg_s; rpkg = strchr(vpkg_s, ':'); if (rpkg == NULL || *rpkg == '\0') { xbps_dbg_printf(xhp, "%s: ignoring invalid " "virtualpkg option at line %zu\n", path, line); return; } /* vpkg until ':' */ tc = strchr(vpkg_s, ':'); vpkglen = strlen(vpkg_s) - strlen(tc); vpkg[vpkglen] = '\0'; /* skip ':' */ rpkg++; xbps_dictionary_set_cstring(xhp->vpkgd, vpkg, rpkg); xbps_dbg_printf(xhp, "%s: added vpkg %s for %s\n", path, vpkg, rpkg); }
int HIDDEN xbps_pkgdb_init(struct xbps_handle *xhp) { int rv; assert(xhp != NULL); if (xhp->pkgdb_plist == NULL) xhp->pkgdb_plist = xbps_xasprintf("%s/%s", xhp->metadir, XBPS_PKGDB); #if 0 if ((rv = xbps_pkgdb_conversion(xhp)) != 0) return rv; #endif if (xhp->pkgdb != NULL) return 0; if ((rv = xbps_pkgdb_update(xhp, false, true)) != 0) { if (rv != ENOENT) xbps_dbg_printf(xhp, "[pkgdb] cannot internalize " "pkgdb array: %s\n", strerror(rv)); return rv; } if ((rv = pkgdb_map_vpkgs(xhp)) != 0) { xbps_dbg_printf(xhp, "[pkgdb] pkgdb_map_vpkgs %s\n", strerror(rv)); return rv; } assert(xhp->pkgdb); xbps_dbg_printf(xhp, "[pkgdb] initialized ok.\n"); return 0; }
static int repo_find_best_pkg_cb(struct xbps_handle *xhp, struct xbps_rpool_index *rpi, void *arg, bool *done) { struct repo_pool_fpkg *rpf = arg; const char *repopkgver; prop_dictionary_t pkgd; (void)done; (void)xhp; if (rpf->bypattern) { pkgd = xbps_find_pkg_in_array_by_pattern(xhp, rpi->repo, rpf->pattern, NULL); } else { pkgd = xbps_find_pkg_in_array_by_name(xhp, rpi->repo, rpf->pattern, NULL); } if (pkgd == NULL) { if (errno && errno != ENOENT) return errno; xbps_dbg_printf(xhp, "[rpool] Package '%s' not found in repository " "'%s'.\n", rpf->pattern, rpi->uri); return 0; } prop_dictionary_get_cstring_nocopy(pkgd, "pkgver", &repopkgver); if (rpf->bestpkgver == NULL) { xbps_dbg_printf(xhp, "[rpool] Found best match '%s' (%s).\n", repopkgver, rpi->uri); rpf->pkgd = pkgd; prop_dictionary_set_cstring_nocopy(rpf->pkgd, "repository", rpi->uri); rpf->bestpkgver = repopkgver; return 0; } /* * Compare current stored version against new * version from current package in repository. */ if (xbps_cmpver(repopkgver, rpf->bestpkgver) == 1) { xbps_dbg_printf(xhp, "[rpool] Found best match '%s' (%s).\n", repopkgver, rpi->uri); rpf->pkgd = pkgd; prop_dictionary_set_cstring_nocopy(rpf->pkgd, "repository", rpi->uri); rpf->bestpkgver = repopkgver; } return 0; }
static int pkgdb_map_vpkgs(struct xbps_handle *xhp) { xbps_object_iterator_t iter; xbps_object_t obj; int rv = 0; if (!xbps_dictionary_count(xhp->pkgdb)) return 0; if (xhp->vpkgd == NULL) { xhp->vpkgd = xbps_dictionary_create(); assert(xhp->vpkgd); } /* * This maps all pkgs that have virtualpkgs in pkgdb. */ iter = xbps_dictionary_iterator(xhp->pkgdb); assert(iter); while ((obj = xbps_object_iterator_next(iter))) { xbps_array_t provides; xbps_dictionary_t pkgd; const char *pkgver; char *pkgname; pkgd = xbps_dictionary_get_keysym(xhp->pkgdb, obj); provides = xbps_dictionary_get(pkgd, "provides"); if (provides == NULL) continue; xbps_dictionary_get_cstring_nocopy(pkgd, "pkgver", &pkgver); pkgname = xbps_pkg_name(pkgver); assert(pkgname); for (unsigned int i = 0; i < xbps_array_count(provides); i++) { const char *vpkg; xbps_array_get_cstring_nocopy(provides, i, &vpkg); if (!xbps_dictionary_set_cstring(xhp->vpkgd, vpkg, pkgname)) { xbps_dbg_printf(xhp, "%s: set_cstring vpkg " "%s pkgname %s\n", __func__, vpkg, pkgname); rv = EINVAL; } else { xbps_dbg_printf(xhp, "[pkgdb] added vpkg %s for %s\n", vpkg, pkgname); } } free(pkgname); } xbps_object_iterator_release(iter); return rv; }
int xbps_pkgdb_lock(struct xbps_handle *xhp) { mode_t prev_umask; int rv; /* * Use a mandatory file lock to only allow one writer to pkgdb, * other writers will block. */ xhp->pkgdb_plist = xbps_xasprintf("%s/%s", xhp->metadir, XBPS_PKGDB); if (xbps_pkgdb_init(xhp) == ENOENT) { /* if metadir does not exist, create it */ if (access(xhp->metadir, R_OK|X_OK) == -1) { if (errno != ENOENT) return errno; if (xbps_mkpath(xhp->metadir, 0755) == -1) { rv = errno; xbps_dbg_printf(xhp, "[pkgdb] failed to create metadir " "%s: %s\n", xhp->metadir, strerror(rv)); return rv; } } /* if pkgdb is unexistent, create it with an empty dictionary */ xhp->pkgdb = xbps_dictionary_create(); if (!xbps_dictionary_externalize_to_file(xhp->pkgdb, xhp->pkgdb_plist)) { rv = errno; xbps_dbg_printf(xhp, "[pkgdb] failed to create pkgdb " "%s: %s\n", xhp->pkgdb_plist, strerror(rv)); return rv; } } prev_umask = umask(022); if ((pkgdb_fd = open(xhp->pkgdb_plist, O_CREAT|O_RDWR|O_CLOEXEC, 0664)) == -1) { rv = errno; xbps_dbg_printf(xhp, "[pkgdb] cannot open pkgdb for locking " "%s: %s\n", xhp->pkgdb_plist, strerror(rv)); free(xhp->pkgdb_plist); umask(prev_umask); return rv; } umask(prev_umask); if (lockf(pkgdb_fd, F_TLOCK, 0) == -1) { rv = errno; xbps_dbg_printf(xhp, "[pkgdb] cannot lock pkgdb: %s\n", strerror(rv)); return rv; } return 0; }
static xbps_dictionary_t get_pkg_metadata(struct xbps_handle *xhp, xbps_dictionary_t pkgd) { xbps_dictionary_t pkg_metad; const char *pkgver; char *pkgname, *plist; xbps_dictionary_get_cstring_nocopy(pkgd, "pkgver", &pkgver); pkgname = xbps_pkg_name(pkgver); assert(pkgname); if ((pkg_metad = xbps_dictionary_get(xhp->pkg_metad, pkgname)) != NULL) { free(pkgname); return pkg_metad; } plist = xbps_xasprintf("%s/.%s.plist", xhp->metadir, pkgname); pkg_metad = xbps_dictionary_internalize_from_file(plist); free(plist); if (pkg_metad == NULL) { xbps_dbg_printf(xhp, "[pkgdb] cannot read %s metadata: %s\n", pkgver, strerror(errno)); free(pkgname); return NULL; } if (xhp->pkg_metad == NULL) xhp->pkg_metad = xbps_dictionary_create(); xbps_dictionary_set(xhp->pkg_metad, pkgname, pkg_metad); xbps_object_release(pkg_metad); free(pkgname); return pkg_metad; }
static bool rsa_verify_hash(struct xbps_repo *repo, xbps_data_t pubkey, unsigned char *sig, unsigned int siglen, unsigned char *sha256) { BIO *bio; RSA *rsa; int rv; ERR_load_crypto_strings(); SSL_load_error_strings(); bio = BIO_new_mem_buf(__UNCONST(xbps_data_data_nocopy(pubkey)), xbps_data_size(pubkey)); assert(bio); rsa = PEM_read_bio_RSA_PUBKEY(bio, NULL, NULL, NULL); if (rsa == NULL) { xbps_dbg_printf(repo->xhp, "`%s' error reading public key: %s\n", repo->uri, ERR_error_string(ERR_get_error(), NULL)); return false; } rv = RSA_verify(NID_sha1, sha256, SHA256_DIGEST_LENGTH, sig, siglen, rsa); RSA_free(rsa); BIO_free(bio); ERR_free_strings(); return rv ? true : false; }
xbps_dictionary_t xbps_pkgdb_get_pkg_files(struct xbps_handle *xhp, const char *pkg) { xbps_dictionary_t pkgd, pkgfilesd; const char *pkgver; char *pkgname, *plist; if (pkg == NULL) return NULL; pkgd = xbps_pkgdb_get_pkg(xhp, pkg); if (pkgd == NULL) return NULL; xbps_dictionary_get_cstring_nocopy(pkgd, "pkgver", &pkgver); pkgname = xbps_pkg_name(pkgver); assert(pkgname); plist = xbps_xasprintf("%s/.%s-files.plist", xhp->metadir, pkgname); free(pkgname); pkgfilesd = xbps_plist_dictionary_from_file(xhp, plist); free(plist); if (pkgfilesd == NULL) { xbps_dbg_printf(xhp, "[pkgdb] cannot read %s metadata: %s\n", pkgver, strerror(errno)); return NULL; } return pkgfilesd; }
static int pfcexec(struct xbps_handle *xhp, const char *file, const char **argv) { pid_t child; int status; child = vfork(); switch (child) { case 0: /* * If rootdir != / and uid==0 and bin/sh exists, * change root directory and exec command. */ if (strcmp(xhp->rootdir, "/")) { if ((geteuid() == 0) && (access("bin/sh", X_OK) == 0)) { if (chroot(xhp->rootdir) == -1) { xbps_dbg_printf(xhp, "%s: chroot() " "failed: %s\n", *argv, strerror(errno)); _exit(errno); } if (chdir("/") == -1) { xbps_dbg_printf(xhp, "%s: chdir() " "failed: %s\n", *argv, strerror(errno)); _exit(errno); } } } (void)execv(file, __UNCONST(argv)); _exit(errno); /* NOTREACHED */ case -1: return -1; } while (waitpid(child, &status, 0) < 0) { if (errno != EINTR) return -1; } if (!WIFEXITED(status)) return -1; return WEXITSTATUS(status); }
void xbps_pkgdb_unlock(struct xbps_handle *xhp) { if (pkgdb_fd != -1) { if (lockf(pkgdb_fd, F_ULOCK, 0) == -1) xbps_dbg_printf(xhp, "[pkgdb] failed to unlock pkgdb: %s\n", strerror(errno)); (void)close(pkgdb_fd); pkgdb_fd = -1; } }
static void store_preserved_file(struct xbps_handle *xhp, const char *file) { glob_t globbuf; char *p = NULL, *rfile = NULL; size_t len; int rv = 0; if (xhp->preserved_files == NULL) { xhp->preserved_files = xbps_array_create(); assert(xhp->preserved_files); } rfile = xbps_xasprintf("%s%s", xhp->rootdir, file); rv = glob(rfile, 0, NULL, &globbuf); if (rv == GLOB_NOMATCH) { if (xbps_match_string_in_array(xhp->preserved_files, file)) goto out; xbps_array_add_cstring(xhp->preserved_files, file); xbps_dbg_printf(xhp, "Added preserved file: %s\n", file); goto out; } else if (rv != 0) { goto out; } for (size_t i = 0; i < globbuf.gl_pathc; i++) { if (xbps_match_string_in_array(xhp->preserved_files, globbuf.gl_pathv[i])) continue; len = strlen(globbuf.gl_pathv[i]) - strlen(xhp->rootdir) + 1; p = malloc(len); assert(p); strlcpy(p, globbuf.gl_pathv[i] + strlen(xhp->rootdir), len); xbps_array_add_cstring(xhp->preserved_files, p); xbps_dbg_printf(xhp, "Added preserved file: %s (expanded from %s)\n", p, file); free(p); } out: globfree(&globbuf); free(rfile); }
static bool repo_open_local(struct xbps_repo *repo, const char *repofile) { struct stat st; int rv = 0; if (fstat(repo->fd, &st) == -1) { rv = errno; xbps_dbg_printf(repo->xhp, "[repo] `%s' fstat repodata %s\n", repofile, strerror(rv)); return false; } repo->ar = archive_read_new(); archive_read_support_compression_gzip(repo->ar); archive_read_support_format_tar(repo->ar); if (archive_read_open_fd(repo->ar, repo->fd, st.st_blksize) == ARCHIVE_FATAL) { rv = archive_errno(repo->ar); xbps_dbg_printf(repo->xhp, "[repo] `%s' failed to open repodata archive %s\n", repofile, strerror(rv)); return false; } if ((repo->idx = repo_get_dict(repo)) == NULL) { rv = archive_errno(repo->ar); xbps_dbg_printf(repo->xhp, "[repo] `%s' failed to internalize " " index on archive, removing file.\n", repofile); /* broken archive, remove it */ (void)unlink(repofile); return false; } xbps_dictionary_make_immutable(repo->idx); repo->idxmeta = repo_get_dict(repo); if (repo->idxmeta != NULL) { repo->is_signed = true; xbps_dictionary_make_immutable(repo->idxmeta); } return true; }
void HIDDEN xbps_pkgdb_release(struct xbps_handle *xhp) { assert(xhp != NULL); if (xhp->pkgdb == NULL) return; xbps_pkgdb_unlock(xhp); xbps_object_release(xhp->pkgdb); xbps_dbg_printf(xhp, "[pkgdb] released ok.\n"); }
/** * @file lib/pkgdb.c * @brief Package database handling routines * @defgroup pkgdb Package database handling functions * * Functions to manipulate the main package database plist file (pkgdb). * * The following image shown below shows the proplib structure used * by the main package database plist: * * @image html images/xbps_pkgdb_array.png * * Legend: * - <b>Salmon filled box</b>: \a XBPS_PKGDB file internalized. * - <b>White filled box</b>: mandatory objects. * - <b>Grey filled box</b>: optional objects. * - <b>Green filled box</b>: possible value set in the object, only one * of them is set. * * Text inside of white boxes are the key associated with the object, its * data type is specified on its edge, i.e array, bool, integer, string, * dictionary. */ int HIDDEN xbps_pkgdb_init(struct xbps_handle *xhp) { int rv; assert(xhp != NULL); if (xhp->pkgdb != NULL) return 0; if ((rv = xbps_pkgdb_update(xhp, false)) != 0) { if (rv != ENOENT) xbps_dbg_printf(xhp, "[pkgdb] cannot internalize " "pkgdb array: %s\n", strerror(rv)); return rv; } xbps_dbg_printf(xhp, "[pkgdb] initialized ok.\n"); return 0; }
bool xbps_repo_store(struct xbps_handle *xhp, const char *repo) { char *url = NULL; assert(xhp); assert(repo); if (xhp->repositories == NULL) { xhp->repositories = xbps_array_create(); assert(xhp->repositories); } /* * If it's a local repo and path is relative, make it absolute. */ if (!xbps_repository_is_remote(repo)) { if (repo[0] != '/' && repo[0] != '\0') { if ((url = realpath(repo, NULL)) == NULL) xbps_dbg_printf(xhp, "[repo] %s: realpath %s\n", __func__, repo); } } if (xbps_match_string_in_array(xhp->repositories, url ? url : repo)) { xbps_dbg_printf(xhp, "[repo] `%s' already stored\n", url ? url : repo); if (url) free(url); return false; } if (xbps_array_add_cstring(xhp->repositories, url ? url : repo)) { xbps_dbg_printf(xhp, "[repo] `%s' stored successfully\n", url ? url : repo); if (url) free(url); return true; } if (url) free(url); return false; }
bool xbps_repo_lock(struct xbps_handle *xhp, const char *repodir, int *lockfd, char **lockfname) { char *repofile, *lockfile; int fd, rv; assert(repodir); assert(lockfd); assert(lockfname); repofile = xbps_repo_path(xhp, repodir); assert(repofile); lockfile = xbps_xasprintf("%s.lock", repofile); free(repofile); for (;;) { fd = open(lockfile, O_WRONLY|O_CREAT|O_EXCL|O_CLOEXEC, 0660); rv = errno; if (fd != -1) break; if (rv != EEXIST) { xbps_dbg_printf(xhp, "[repo] `%s' failed to " "create lock file %s\n", lockfile, strerror(rv)); free(lockfile); return false; } else { xbps_dbg_printf(xhp, "[repo] `%s' lock file exists," "waiting for 1s...\n", lockfile); sleep(1); } } *lockfname = lockfile; *lockfd = fd; return true; }
void HIDDEN xbps_pkgdb_release(struct xbps_handle *xhp) { assert(xhp != NULL); if (xhp->pkgdb == NULL) return; if (xbps_object_type(xhp->pkg_metad) == XBPS_TYPE_DICTIONARY) xbps_object_release(xhp->pkg_metad); xbps_object_release(xhp->pkgdb); xhp->pkgdb = NULL; xbps_dbg_printf(xhp, "[pkgdb] released ok.\n"); }
static bool repo_open_remote(struct xbps_repo *repo) { char *rpath; bool rv; rpath = xbps_repo_path(repo->xhp, repo->uri); rv = xbps_repo_fetch_remote(repo, rpath); free(rpath); if (rv) { xbps_dbg_printf(repo->xhp, "[repo] `%s' used remotely (kept in memory).\n", repo->uri); if (repo->xhp->state_cb && xbps_repo_key_import(repo) != 0) rv = false; } return rv; }
static xbps_dictionary_t repo_get_dict(struct xbps_repo *repo) { struct archive_entry *entry; int rv; if (repo->ar == NULL) return NULL; rv = archive_read_next_header(repo->ar, &entry); if (rv != ARCHIVE_OK) { xbps_dbg_printf(repo->xhp, "%s: read_next_header %s\n", repo->uri, archive_error_string(repo->ar)); return NULL; } return xbps_archive_get_dictionary(repo->ar, entry); }
bool HIDDEN xbps_transaction_shlibs(struct xbps_handle *xhp, xbps_array_t pkgs, xbps_array_t mshlibs) { xbps_object_t obj; xbps_object_iterator_t iter; xbps_dictionary_t shrequires, shprovides; bool unmatched = false; shrequires = collect_shlibs(xhp, pkgs, true); shprovides = collect_shlibs(xhp, pkgs, false); /* iterate over shlib-requires to find unmatched shlibs */ iter = xbps_dictionary_iterator(shrequires); assert(iter); while ((obj = xbps_object_iterator_next(iter))) { xbps_array_t array; const char *pkgver, *shlib; char *buf; shlib = xbps_dictionary_keysym_cstring_nocopy(obj); xbps_dbg_printf(xhp, "%s: checking for `%s': ", __func__, shlib); if (xbps_dictionary_get(shprovides, shlib)) { xbps_dbg_printf_append(xhp, "found\n"); continue; } xbps_dbg_printf_append(xhp, "not found\n"); unmatched = true; array = xbps_dictionary_get_keysym(shrequires, obj); for (unsigned int i = 0; i < xbps_array_count(array); i++) { xbps_array_get_cstring_nocopy(array, i, &pkgver); buf = xbps_xasprintf("%s: broken, unresolvable " "shlib `%s'", pkgver, shlib); xbps_array_add_cstring(mshlibs, buf); free(buf); } xbps_object_release(array); } xbps_object_iterator_release(iter); xbps_object_release(shprovides); return unmatched; }
int HIDDEN xbps_repository_find_deps(struct xbps_handle *xhp, xbps_array_t unsorted, xbps_dictionary_t repo_pkgd) { xbps_array_t pkg_rdeps, pkg_provides = NULL; const char *pkgver; unsigned short depth = 0; pkg_rdeps = xbps_dictionary_get(repo_pkgd, "run_depends"); if (xbps_array_count(pkg_rdeps) == 0) return 0; xbps_dictionary_get_cstring_nocopy(repo_pkgd, "pkgver", &pkgver); xbps_dbg_printf(xhp, "Finding required dependencies for '%s':\n", pkgver); /* * This will find direct and indirect deps, if any of them is not * there it will be added into the missing_deps array. */ pkg_provides = xbps_dictionary_get(repo_pkgd, "provides"); return find_repo_deps(xhp, unsorted, pkg_rdeps, pkg_provides, pkgver, &depth); }
int HIDDEN xbps_transaction_package_replace(struct xbps_handle *xhp, xbps_array_t pkgs) { for (unsigned int i = 0; i < xbps_array_count(pkgs); i++) { xbps_array_t replaces; xbps_object_t obj, obj2; xbps_object_iterator_t iter; const char *pkgver; char *pkgname; obj = xbps_array_get(pkgs, i); replaces = xbps_dictionary_get(obj, "replaces"); if (replaces == NULL || xbps_array_count(replaces) == 0) continue; iter = xbps_array_iterator(replaces); assert(iter); xbps_dictionary_get_cstring_nocopy(obj, "pkgver", &pkgver); pkgname = xbps_pkg_name(pkgver); assert(pkgname); while ((obj2 = xbps_object_iterator_next(iter)) != NULL) { xbps_dictionary_t instd, reppkgd; const char *tract, *pattern, *curpkgver; char *curpkgname; bool instd_auto = false; pattern = xbps_string_cstring_nocopy(obj2); /* * Find the installed package that matches the pattern * to be replaced. */ if (((instd = xbps_pkgdb_get_pkg(xhp, pattern)) == NULL) && ((instd = xbps_pkgdb_get_virtualpkg(xhp, pattern)) == NULL)) continue; xbps_dictionary_get_cstring_nocopy(instd, "pkgver", &curpkgver); curpkgname = xbps_pkg_name(curpkgver); assert(curpkgname); /* * Check that we are not replacing the same package, * due to virtual packages. */ if (strcmp(pkgname, curpkgname) == 0) { free(curpkgname); continue; } /* * Make sure to not add duplicates. */ xbps_dictionary_get_bool(instd, "automatic-install", &instd_auto); reppkgd = xbps_find_pkg_in_array(pkgs, curpkgname, NULL); if (reppkgd) { xbps_dictionary_get_cstring_nocopy(reppkgd, "transaction", &tract); if (strcmp(tract, "remove") == 0) continue; /* * Package contains replaces="pkgpattern", but the * package that should be replaced is also in the * transaction and it's going to be updated. */ xbps_dictionary_set_bool(reppkgd, "automatic-install", instd_auto); xbps_array_replace_dict_by_name(pkgs, reppkgd, curpkgname); continue; } /* * If new package is providing a virtual package to the * package that we want to replace we should respect * the automatic-install object. */ if (xbps_match_virtual_pkg_in_dict(obj, pattern)) { xbps_dictionary_set_bool(obj, "automatic-install", instd_auto); } xbps_dbg_printf(xhp, "Package `%s' will be replaced by `%s', " "matched with `%s'\n", curpkgver, pkgver, pattern); /* * Add package dictionary into the transaction and mark * it as to be "removed". */ xbps_dictionary_set_cstring_nocopy(instd, "transaction", "remove"); if (!xbps_array_add_first(pkgs, instd)) return EINVAL; free(curpkgname); } xbps_object_iterator_release(iter); free(pkgname); } return 0; }
int xbps_repo_key_import(struct xbps_repo *repo) { xbps_dictionary_t repokeyd = NULL; xbps_data_t pubkey = NULL; uint16_t pubkey_size = 0; const char *signedby = NULL; char *hexfp = NULL; char *p, *dbkeyd, *rkeyfile = NULL; int import, rv = 0; assert(repo); /* * If repository does not have required metadata plist, ignore it. */ if (!xbps_dictionary_count(repo->idxmeta)) { xbps_dbg_printf(repo->xhp, "[repo] `%s' unsigned repository!\n", repo->uri); return 0; } /* * Check for required objects in index-meta: * - signature-by (string) * - public-key (data) * - public-key-size (number) */ xbps_dictionary_get_cstring_nocopy(repo->idxmeta, "signature-by", &signedby); xbps_dictionary_get_uint16(repo->idxmeta, "public-key-size", &pubkey_size); pubkey = xbps_dictionary_get(repo->idxmeta, "public-key"); if (signedby == NULL || pubkey_size == 0 || xbps_object_type(pubkey) != XBPS_TYPE_DATA) { xbps_dbg_printf(repo->xhp, "[repo] `%s': incomplete signed repository " "(missing objs)\n", repo->uri); rv = EINVAL; goto out; } hexfp = xbps_pubkey2fp(repo->xhp, pubkey); /* * Check if the public key is alredy stored. */ rkeyfile = xbps_xasprintf("%s/keys/%s.plist", repo->xhp->metadir, hexfp); repokeyd = xbps_plist_dictionary_from_file(repo->xhp, rkeyfile); if (xbps_object_type(repokeyd) == XBPS_TYPE_DICTIONARY) { xbps_dbg_printf(repo->xhp, "[repo] `%s' public key already stored.\n", repo->uri); goto out; } /* * Notify the client and take appropiate action to import * the repository public key. Pass back the public key openssh fingerprint * to the client. */ import = xbps_set_cb_state(repo->xhp, XBPS_STATE_REPO_KEY_IMPORT, 0, hexfp, "`%s' repository has been RSA signed by \"%s\"", repo->uri, signedby); if (import <= 0) { rv = EAGAIN; goto out; } p = strdup(rkeyfile); dbkeyd = dirname(p); assert(dbkeyd); if (access(dbkeyd, R_OK|W_OK) == -1) { rv = errno; if (rv == ENOENT) rv = xbps_mkpath(dbkeyd, 0755); if (rv != 0) { rv = errno; xbps_dbg_printf(repo->xhp, "[repo] `%s' cannot create %s: %s\n", repo->uri, dbkeyd, strerror(errno)); free(p); goto out; } } free(p); repokeyd = xbps_dictionary_create(); xbps_dictionary_set(repokeyd, "public-key", pubkey); xbps_dictionary_set_uint16(repokeyd, "public-key-size", pubkey_size); xbps_dictionary_set_cstring_nocopy(repokeyd, "signature-by", signedby); if (!xbps_dictionary_externalize_to_file(repokeyd, rkeyfile)) { rv = errno; xbps_dbg_printf(repo->xhp, "[repo] `%s' failed to externalize %s: %s\n", repo->uri, rkeyfile, strerror(rv)); } out: if (hexfp) free(hexfp); if (repokeyd) xbps_object_release(repokeyd); if (rkeyfile) free(rkeyfile); return rv; }
static int create_symlinks(struct xbps_handle *xhp, xbps_array_t a, const char *grname) { unsigned int i, cnt; cnt = xbps_array_count(a); for (i = 0; i < cnt; i++) { xbps_string_t str; char *tgt_dup, *tgt_dir, *lnk_dup, *lnk_dir; char *l, *lnk, *tgt = NULL; const char *tgt0; int rv; str = xbps_array_get(a, i); l = left(xbps_string_cstring_nocopy(str)); assert(l); tgt0 = right(xbps_string_cstring_nocopy(str)); assert(tgt0); /* always create target dir, for dangling symlinks */ tgt_dup = strdup(tgt0); assert(tgt_dup); tgt_dir = dirname(tgt_dup); if (strcmp(tgt_dir, ".")) { tgt = xbps_xasprintf("%s%s", xhp->rootdir, tgt_dir); if (xbps_mkpath(tgt, 0755) != 0) { if (errno != EEXIST) { rv = errno; xbps_dbg_printf(xhp, "failed to create " "target dir '%s' for group '%s': %s\n", tgt, grname, strerror(errno)); free(tgt_dup); free(tgt); free(l); return rv; } } free(tgt); } /* always create link dir, for dangling symlinks */ lnk_dup = strdup(l); assert(lnk_dup); lnk_dir = dirname(lnk_dup); if (strcmp(lnk_dir, ".")) { lnk = xbps_xasprintf("%s%s", xhp->rootdir, lnk_dir); if (xbps_mkpath(lnk, 0755) != 0) { if (errno != EEXIST) { rv = errno; xbps_dbg_printf(xhp, "failed to create symlink" "dir '%s' for group '%s': %s\n", lnk, grname, strerror(errno)); free(tgt_dup); free(lnk_dup); free(lnk); free(l); return rv; } } free(lnk); } free(lnk_dup); if (l[0] != '/') { lnk = xbps_xasprintf("%s%s/%s", xhp->rootdir, tgt_dir, l); free(tgt_dup); tgt_dup = strdup(tgt0); assert(tgt_dup); tgt = strdup(basename(tgt_dup)); free(tgt_dup); } else { free(tgt_dup); tgt = strdup(tgt0); lnk = xbps_xasprintf("%s%s", xhp->rootdir, l); } xbps_set_cb_state(xhp, XBPS_STATE_ALTGROUP_LINK_ADDED, 0, NULL, "Creating '%s' alternatives group symlink: %s -> %s", grname, l, tgt); unlink(lnk); if (tgt[0] == '/') { tgt_dup = relpath(lnk + strlen(xhp->rootdir), tgt); free(tgt); tgt = tgt_dup; } if ((rv = symlink(tgt, lnk)) != 0) { xbps_dbg_printf(xhp, "failed to create alt symlink '%s'" "for group '%s': %s\n", lnk, grname, strerror(errno)); free(tgt); free(lnk); free(l); return rv; } free(tgt); free(lnk); free(l); } return 0; }
bool xbps_verify_file_signature(struct xbps_repo *repo, const char *fname) { xbps_dictionary_t repokeyd = NULL; xbps_data_t pubkey; char *hexfp = NULL; unsigned char *digest = NULL, *sig_buf = NULL; size_t sigbuflen, sigfilelen; char *rkeyfile = NULL, *sig = NULL; bool val = false; if (!xbps_dictionary_count(repo->idxmeta)) { xbps_dbg_printf(repo->xhp, "%s: unsigned repository\n", repo->uri); return false; } hexfp = xbps_pubkey2fp(repo->xhp, xbps_dictionary_get(repo->idxmeta, "public-key")); if (hexfp == NULL) { xbps_dbg_printf(repo->xhp, "%s: incomplete signed repo, missing hexfp obj\n", repo->uri); return false; } /* * Prepare repository RSA public key to verify fname signature. */ rkeyfile = xbps_xasprintf("%s/keys/%s.plist", repo->xhp->metadir, hexfp); repokeyd = xbps_plist_dictionary_from_file(repo->xhp, rkeyfile); if (xbps_object_type(repokeyd) != XBPS_TYPE_DICTIONARY) { xbps_dbg_printf(repo->xhp, "cannot read rkey data at %s: %s\n", rkeyfile, strerror(errno)); goto out; } pubkey = xbps_dictionary_get(repokeyd, "public-key"); if (xbps_object_type(pubkey) != XBPS_TYPE_DATA) goto out; /* * Prepare fname and signature data buffers. */ if (!(digest = xbps_file_hash_raw(fname))) { xbps_dbg_printf(repo->xhp, "can't open file %s: %s\n", fname, strerror(errno)); goto out; } sig = xbps_xasprintf("%s.sig", fname); if (!xbps_mmap_file(sig, (void *)&sig_buf, &sigbuflen, &sigfilelen)) { xbps_dbg_printf(repo->xhp, "can't open signature file %s: %s\n", sig, strerror(errno)); goto out; } /* * Verify fname RSA signature. */ if (rsa_verify_hash(repo, pubkey, sig_buf, sigfilelen, digest)) val = true; out: if (hexfp) free(hexfp); if (rkeyfile) free(rkeyfile); if (digest) free(digest); if (sig_buf) (void)munmap(sig_buf, sigbuflen); if (sig) free(sig); if (repokeyd) xbps_object_release(repokeyd); return val; }
/* * Returns 1 if entry should be installed, 0 if don't or -1 on error. */ int HIDDEN xbps_entry_install_conf_file(struct xbps_handle *xhp, xbps_dictionary_t filesd, struct archive_entry *entry, const char *entry_pname, const char *pkgver, const char *pkgname) { xbps_dictionary_t forigd; xbps_object_t obj, obj2; xbps_object_iterator_t iter, iter2; const char *cffile, *sha256_new = NULL; char *buf, *sha256_cur = NULL, *sha256_orig = NULL; int rv = 0; assert(xbps_object_type(filesd) == XBPS_TYPE_DICTIONARY); assert(entry != NULL); assert(entry_pname != NULL); assert(pkgver != NULL); iter = xbps_array_iter_from_dict(filesd, "conf_files"); if (iter == NULL) return -1; /* * Get original hash for the file from current * installed package. */ xbps_dbg_printf(xhp, "%s: processing conf_file %s\n", pkgver, entry_pname); forigd = xbps_pkgdb_get_pkg_metadata(xhp, pkgname); if (forigd == NULL) { xbps_dbg_printf(xhp, "%s: conf_file %s not currently " "installed\n", pkgver, entry_pname); rv = 1; goto out; } iter2 = xbps_array_iter_from_dict(forigd, "conf_files"); if (iter2 != NULL) { while ((obj2 = xbps_object_iterator_next(iter2))) { xbps_dictionary_get_cstring_nocopy(obj2, "file", &cffile); buf = xbps_xasprintf(".%s", cffile); if (strcmp(entry_pname, buf) == 0) { xbps_dictionary_get_cstring(obj2, "sha256", &sha256_orig); free(buf); break; } free(buf); buf = NULL; } xbps_object_iterator_release(iter2); } /* * First case: original hash not found, install new file. */ if (sha256_orig == NULL) { xbps_dbg_printf(xhp, "%s: conf_file %s not installed\n", pkgver, entry_pname); rv = 1; goto out; } /* * Compare original, installed and new hash for current file. */ while ((obj = xbps_object_iterator_next(iter))) { xbps_dictionary_get_cstring_nocopy(obj, "file", &cffile); buf = xbps_xasprintf(".%s", cffile); if (strcmp(entry_pname, buf)) { free(buf); buf = NULL; continue; } sha256_cur = xbps_file_hash(buf); free(buf); xbps_dictionary_get_cstring_nocopy(obj, "sha256", &sha256_new); if (sha256_cur == NULL) { if (errno == ENOENT) { /* * File not installed, install new one. */ xbps_dbg_printf(xhp, "%s: conf_file %s not " "installed\n", pkgver, entry_pname); rv = 1; break; } else { rv = -1; break; } } /* * Orig = X, Curr = X, New = X * * Keep file as is (no changes). */ if ((strcmp(sha256_orig, sha256_cur) == 0) && (strcmp(sha256_orig, sha256_new) == 0) && (strcmp(sha256_cur, sha256_new) == 0)) { xbps_dbg_printf(xhp, "%s: conf_file %s orig = X, " "cur = X, new = X\n", pkgver, entry_pname); rv = 0; break; /* * Orig = X, Curr = X, New = Y * * Install new file (installed file hasn't been modified). */ } else if ((strcmp(sha256_orig, sha256_cur) == 0) && (strcmp(sha256_orig, sha256_new)) && (strcmp(sha256_cur, sha256_new))) { xbps_set_cb_state(xhp, XBPS_STATE_CONFIG_FILE, 0, pkgver, "Updating configuration file `%s' provided " "by `%s'.", cffile, pkgver); rv = 1; break; /* * Orig = X, Curr = Y, New = X * * Keep installed file as is because it has been modified, * but new package doesn't contain new changes compared * to the original version. */ } else if ((strcmp(sha256_orig, sha256_new) == 0) && (strcmp(sha256_cur, sha256_new)) && (strcmp(sha256_orig, sha256_cur))) { xbps_set_cb_state(xhp, XBPS_STATE_CONFIG_FILE, 0, pkgver, "Keeping modified configuration file `%s'.", cffile); rv = 0; break; /* * Orig = X, Curr = Y, New = Y * * Keep file as is because changes made are compatible * with new version. */ } else if ((strcmp(sha256_cur, sha256_new) == 0) && (strcmp(sha256_orig, sha256_new)) && (strcmp(sha256_orig, sha256_cur))) { xbps_dbg_printf(xhp, "%s: conf_file %s orig = X, " "cur = Y, new = Y\n", pkgver, entry_pname); rv = 0; break; /* * Orig = X, Curr = Y, New = Z * * Install new file as <file>.new-<version> */ } else if ((strcmp(sha256_orig, sha256_cur)) && (strcmp(sha256_cur, sha256_new)) && (strcmp(sha256_orig, sha256_new))) { const char *version; version = xbps_pkg_version(pkgver); assert(version); buf = xbps_xasprintf(".%s.new-%s", cffile, version); xbps_set_cb_state(xhp, XBPS_STATE_CONFIG_FILE, 0, pkgver, "Installing new configuration file to " "`%s.new-%s'.", cffile, version); archive_entry_set_pathname(entry, buf); free(buf); rv = 1; break; } } out: if (sha256_orig) free(sha256_orig); if (sha256_cur) free(sha256_cur); xbps_object_iterator_release(iter); xbps_dbg_printf(xhp, "%s: conf_file %s returned %d\n", pkgver, entry_pname, rv); return rv; }
int HIDDEN xbps_remove_pkg(struct xbps_handle *xhp, const char *pkgver, bool update, bool soft_replace) { xbps_dictionary_t pkgd = NULL; char *pkgname, *buf = NULL; int rv = 0; pkg_state_t state = 0; assert(xhp); assert(pkgver); pkgname = xbps_pkg_name(pkgver); assert(pkgname); if ((rv = xbps_pkg_state_installed(xhp, pkgname, &state)) != 0) goto out; xbps_dbg_printf(xhp, "attempting to remove %s state %d\n", pkgver, state); if (!update) xbps_set_cb_state(xhp, XBPS_STATE_REMOVE, 0, pkgver, NULL); if (chdir(xhp->rootdir) == -1) { rv = errno; xbps_set_cb_state(xhp, XBPS_STATE_REMOVE_FAIL, rv, pkgver, "%s: [remove] failed to chdir to rootdir `%s': %s", pkgver, xhp->rootdir, strerror(rv)); goto out; } /* internalize pkg dictionary from metadir */ buf = xbps_xasprintf("%s/.%s.plist", xhp->metadir, pkgname); pkgd = xbps_dictionary_internalize_from_file(buf); free(buf); if (pkgd == NULL) xbps_dbg_printf(xhp, "WARNING: metaplist for %s " "doesn't exist!\n", pkgver); /* If package was "half-removed", remove it fully. */ if (state == XBPS_PKG_STATE_HALF_REMOVED) goto purge; /* * Run the pre remove action. */ if (pkgd) { rv = xbps_pkg_exec_script(xhp, pkgd, "remove-script", "pre", update); if (rv != 0) { xbps_set_cb_state(xhp, XBPS_STATE_REMOVE_FAIL, errno, pkgver, "%s: [remove] REMOVE script failed to " "execute pre ACTION: %s", pkgver, strerror(rv)); goto out; } } /* * If updating a package, we just need to execute the current * pre-remove action target and we are done. Its files will be * overwritten later in unpack phase. */ if (update) { if (pkgd) xbps_object_release(pkgd); free(pkgname); return 0; } else if (soft_replace) { /* * Soft replace a package. Do not remove its files, but * execute PURGE action, remove metadata files and unregister * from pkgdb. */ goto softreplace; } if (pkgd) { /* Remove regular files */ if ((rv = xbps_remove_pkg_files(xhp, pkgd, "files", pkgver)) != 0) goto out; /* Remove configuration files */ if ((rv = xbps_remove_pkg_files(xhp, pkgd, "conf_files", pkgver)) != 0) goto out; /* Remove links */ if ((rv = xbps_remove_pkg_files(xhp, pkgd, "links", pkgver)) != 0) goto out; /* Remove dirs */ if ((rv = xbps_remove_pkg_files(xhp, pkgd, "dirs", pkgver)) != 0) goto out; /* * Execute the post REMOVE action if file exists and we aren't * updating the package. */ rv = xbps_pkg_exec_script(xhp, pkgd, "remove-script", "post", false); if (rv != 0) { xbps_set_cb_state(xhp, XBPS_STATE_REMOVE_FAIL, rv, pkgver, "%s: [remove] REMOVE script failed to execute " "post ACTION: %s", pkgver, strerror(rv)); goto out; } } softreplace: /* * Set package state to "half-removed". */ rv = xbps_set_pkg_state_installed(xhp, pkgver, XBPS_PKG_STATE_HALF_REMOVED); if (rv != 0) { xbps_set_cb_state(xhp, XBPS_STATE_REMOVE_FAIL, rv, pkgver, "%s: [remove] failed to set state to half-removed: %s", pkgver, strerror(rv)); goto out; } purge: /* * Execute the purge REMOVE action if file exists. */ if (pkgd) { rv = xbps_pkg_exec_script(xhp, pkgd, "remove-script", "purge", false); if (rv != 0) { xbps_set_cb_state(xhp, XBPS_STATE_REMOVE_FAIL, rv, pkgver, "%s: REMOVE script failed to execute " "purge ACTION: %s", pkgver, strerror(rv)); goto out; } xbps_object_release(pkgd); } /* * Remove package metadata plist. */ buf = xbps_xasprintf("%s/.%s.plist", xhp->metadir, pkgname); if (remove(buf) == -1) { if (errno != ENOENT) { xbps_set_cb_state(xhp, XBPS_STATE_REMOVE_FAIL, rv, pkgver, "%s: failed to remove metadata file: %s", pkgver, strerror(errno)); } } free(buf); /* * Unregister package from pkgdb. */ xbps_dictionary_remove(xhp->pkgdb, pkgname); if ((rv = xbps_pkgdb_update(xhp, true)) != 0) goto out; xbps_dbg_printf(xhp, "[remove] unregister %s returned %d\n", pkgver, rv); xbps_set_cb_state(xhp, XBPS_STATE_REMOVE_DONE, 0, pkgver, NULL); out: if (pkgname != NULL) free(pkgname); return rv; }
int xbps_init(struct xbps_handle *xhp) { struct utsname un; char cwd[PATH_MAX-1], *buf; const char *repodir, *native_arch; int rv; assert(xhp != NULL); /* get cwd */ if (getcwd(cwd, sizeof(cwd)) == NULL) return ENOTSUP; /* set conffile */ if (xhp->conffile[0] == '\0') { snprintf(xhp->conffile, sizeof(xhp->conffile), XBPS_CONF_DEF); } else { buf = strdup(xhp->conffile); snprintf(xhp->conffile, sizeof(xhp->conffile), "%s/%s", cwd, buf); free(buf); } /* Set rootdir */ if (xhp->rootdir[0] == '\0') { xhp->rootdir[0] = '/'; xhp->rootdir[1] = '\0'; } else if (xhp->rootdir[0] != '/') { buf = strdup(xhp->rootdir); snprintf(xhp->rootdir, sizeof(xhp->rootdir), "%s/%s", cwd, buf); free(buf); } /* parse configuration file */ xbps_dbg_printf(xhp, "%s\n", XBPS_RELVER); if ((rv = parse_file(xhp, cwd, xhp->conffile, false, false)) != 0) { xbps_dbg_printf(xhp, "Using built-in defaults\n"); } /* Set cachedir */ if (xhp->cachedir[0] == '\0') { snprintf(xhp->cachedir, sizeof(xhp->cachedir), "%s/%s", strcmp(xhp->rootdir, "/") ? xhp->rootdir : "", XBPS_CACHE_PATH); } else if (xhp->cachedir[0] != '/') { /* relative path */ buf = strdup(xhp->cachedir); snprintf(xhp->cachedir, sizeof(xhp->cachedir), "%s/%s", strcmp(xhp->rootdir, "/") ? xhp->rootdir : "", buf); free(buf); } /* Set metadir */ if (xhp->metadir[0] == '\0') { snprintf(xhp->metadir, sizeof(xhp->metadir), "%s/%s", strcmp(xhp->rootdir, "/") ? xhp->rootdir : "", XBPS_META_PATH); } else if (xhp->metadir[0] != '/') { /* relative path */ buf = strdup(xhp->metadir); snprintf(xhp->metadir, sizeof(xhp->metadir), "%s/%s", strcmp(xhp->rootdir, "/") ? xhp->rootdir : "", buf); free(buf); } /* process virtualpkg.d dirs */ if ((rv = parse_dir(xhp, cwd, XBPS_SYS_VPKG_PATH, XBPS_VPKG_PATH, true)) != 0) return rv; /* process repo.d dirs */ if ((rv = parse_dir(xhp, cwd, XBPS_SYS_REPOD_PATH, XBPS_REPOD_PATH, false)) != 0) return rv; /* process preserve.d dirs */ if ((rv = parse_dir(xhp, cwd, XBPS_SYS_PRESERVED_PATH, XBPS_PRESERVED_PATH, false)) != 0) return rv; xhp->target_arch = getenv("XBPS_TARGET_ARCH"); if ((native_arch = getenv("XBPS_ARCH")) != NULL) { strlcpy(xhp->native_arch, native_arch, sizeof(xhp->native_arch)); } else { uname(&un); strlcpy(xhp->native_arch, un.machine, sizeof(xhp->native_arch)); } assert(xhp->native_arch); xbps_fetch_set_cache_connection(XBPS_FETCH_CACHECONN, XBPS_FETCH_CACHECONN_HOST); xbps_dbg_printf(xhp, "rootdir=%s\n", xhp->rootdir); xbps_dbg_printf(xhp, "metadir=%s\n", xhp->metadir); xbps_dbg_printf(xhp, "cachedir=%s\n", xhp->cachedir); xbps_dbg_printf(xhp, "syslog=%s\n", xhp->flags & XBPS_FLAG_DISABLE_SYSLOG ? "false" : "true"); xbps_dbg_printf(xhp, "Architecture: %s\n", xhp->native_arch); xbps_dbg_printf(xhp, "Target Architecture: %s\n", xhp->target_arch); if (xhp->flags & XBPS_FLAG_DEBUG) { for (unsigned int i = 0; i < xbps_array_count(xhp->repositories); i++) { xbps_array_get_cstring_nocopy(xhp->repositories, i, &repodir); xbps_dbg_printf(xhp, "Repository[%u]=%s\n", i, repodir); } } /* Going back to old working directory */ if (chdir(cwd) == -1) xbps_dbg_printf(xhp, "%s: cannot chdir to %s: %s\n", __func__, cwd, strerror(errno)); return 0; }
static int parse_dir(struct xbps_handle *xhp, const char *cwd, const char *dir, const char *confdir, bool vpkg) { struct dirent **namelist; char *ext, ldir[PATH_MAX], conf[PATH_MAX]; int i, n, rv = 0; /* * Read all configuration files stored in the system * foo.d directory. */ snprintf(ldir, sizeof(ldir), "%s/%s", strcmp(xhp->rootdir, "/") ? xhp->rootdir : "", dir); xbps_dbg_printf(xhp, "Processing system directory: %s\n", ldir); if ((n = scandir(ldir, &namelist, 0, alphasort)) < 0) goto stage2; for (i = 0; i < n; i++) { if ((strcmp(namelist[i]->d_name, "..") == 0) || (strcmp(namelist[i]->d_name, ".") == 0)) { free(namelist[i]); continue; } /* only process .vpkg/.conf files, ignore something else */ if ((ext = strrchr(namelist[i]->d_name, '.')) == NULL) { free(namelist[i]); continue; } if (strcmp(ext, ".conf") && strcmp(ext, ".vpkg")) { xbps_dbg_printf(xhp, "%s: ignoring %s\n", ldir, namelist[i]->d_name); free(namelist[i]); continue; } /* if the same file exists in configuration directory, ignore it */ snprintf(conf, sizeof(conf), "%s/%s/%s", xhp->rootdir, confdir, namelist[i]->d_name); if (access(conf, R_OK) == 0) { xbps_dbg_printf(xhp, "%s: ignoring %s (exists in confdir)\n", ldir, namelist[i]->d_name); free(namelist[i]); continue; } /* parse conf file */ snprintf(conf, sizeof(conf), "%s/%s", ldir, namelist[i]->d_name); if ((rv = parse_file(xhp, cwd, conf, false, vpkg)) != 0) { free(namelist[i]); break; } } free(namelist); if (rv != 0) return rv; stage2: /* * Read all configuration files stored in the configuration foo.d directory. */ snprintf(ldir, sizeof(ldir), "%s%s", strcmp(xhp->rootdir, "/") ? xhp->rootdir : "", confdir); xbps_dbg_printf(xhp, "Processing configuration directory: %s\n", ldir); if ((n = scandir(ldir, &namelist, 0, alphasort)) < 0) return 0; for (i = 0; i < n; i++) { if ((strcmp(namelist[i]->d_name, "..") == 0) || (strcmp(namelist[i]->d_name, ".") == 0)) { free(namelist[i]); continue; } /* only process .vpkg/.conf files, ignore something else */ if ((ext = strrchr(namelist[i]->d_name, '.')) == NULL) { free(namelist[i]); continue; } if (strcmp(ext, ".conf") && strcmp(ext, ".vpkg")) { xbps_dbg_printf(xhp, "%s: ignoring %s\n", ldir, namelist[i]->d_name); free(namelist[i]); continue; } /* parse conf file */ snprintf(conf, sizeof(conf), "%s/%s", ldir, namelist[i]->d_name); if ((rv = parse_file(xhp, cwd, conf, false, vpkg)) != 0) { free(namelist[i]); break; } } free(namelist); return rv; }
static int parse_file(struct xbps_handle *xhp, const char *cwd, const char *path, bool nested, bool vpkgconf) { FILE *fp; char tmppath[XBPS_MAXPATH] = {0}; size_t len, nlines = 0; ssize_t nread; char *cfcwd, *line = NULL; int rv = 0; if ((fp = fopen(path, "r")) == NULL) { rv = errno; xbps_dbg_printf(xhp, "cannot read configuration file %s: %s\n", path, strerror(rv)); return rv; } if (!vpkgconf) { xbps_dbg_printf(xhp, "Parsing configuration file: %s\n", path); } while ((nread = getline(&line, &len, fp)) != -1) { char *p, *k, *v; nlines++; p = line; /* eat blanks */ while (isblank((unsigned char)*p)) p++; /* ignore comments or empty lines */ if (*p == '#' || *p == '\n') continue; if (!parse_option(p, &k, &v)) { xbps_dbg_printf(xhp, "%s: ignoring invalid option at " "line %zu\n", path, nlines); continue; } if (strcmp(k, "rootdir") == 0) { xbps_dbg_printf(xhp, "%s: rootdir set to %s\n", path, v); snprintf(xhp->rootdir, sizeof(xhp->rootdir), "%s", v); } else if (strcmp(k, "cachedir") == 0) { xbps_dbg_printf(xhp, "%s: cachedir set to %s\n", path, v); snprintf(xhp->cachedir, sizeof(xhp->cachedir), "%s", v); } else if (strcmp(k, "syslog") == 0) { if (strcasecmp(v, "true") == 0) { xhp->flags &= ~XBPS_FLAG_DISABLE_SYSLOG; xbps_dbg_printf(xhp, "%s: syslog enabled\n", path); } else { xhp->flags |= XBPS_FLAG_DISABLE_SYSLOG; xbps_dbg_printf(xhp, "%s: syslog disabled\n", path); } } else if (strcmp(k, "repository") == 0) { if (store_repo(xhp, v)) xbps_dbg_printf(xhp, "%s: added repository %s\n", path, v); } else if (strcmp(k, "virtualpkg") == 0) { store_vpkg(xhp, path, nlines, v); } else if (strcmp(k, "preserve") == 0) { store_preserved_file(xhp, v); } /* Avoid double-nested parsing, only allow it once */ if (nested) continue; if (strcmp(k, "include")) continue; /* cwd to the dir containing the config file */ strlcpy(tmppath, path, sizeof(tmppath)); cfcwd = dirname(tmppath); if (chdir(cfcwd) == -1) { rv = errno; xbps_dbg_printf(xhp, "cannot chdir to %s: %s\n", cfcwd, strerror(rv)); return rv; } if ((rv = parse_files_glob(xhp, cwd, v, true, false)) != 0) break; } free(line); fclose(fp); return rv; }