ATF_TC_BODY(pkg_matches_filters_not_installed, tc) { struct pkg *local; struct pkg *remote; PkBitfield filter; filter = pk_bitfield_from_enums(PK_FILTER_ENUM_NOT_INSTALLED, -1); /* Locally installed -> reject */ local = gen_pkg(PKG_INSTALLED); ATF_REQUIRE(local != NULL); ATF_CHECK(!pkgutils_pkg_matches_filters(local, filter)); pkg_free(local); remote = gen_pkg(PKG_REMOTE); ATF_REQUIRE(remote != NULL); /* Old version newer -> reject */ pkg_set(remote, PKG_OLD_VERSION, "1.2.3"); ATF_CHECK(pkgutils_pkg_matches_filters(remote, filter)); /* Old version the same -> accept */ pkg_set(remote, PKG_OLD_VERSION, "1.1.4"); ATF_CHECK(!pkgutils_pkg_matches_filters(remote, filter)); /* Old version older -> reject */ pkg_set(remote, PKG_OLD_VERSION, "1.0.0"); ATF_CHECK(pkgutils_pkg_matches_filters(remote, filter)); pkg_free(remote); }
static int pkg_string(struct pkg *pkg, ucl_object_t *obj, int attr) { int ret = EPKG_OK; const char *str; str = ucl_object_tostring_forced(obj); switch (attr) { case PKG_LICENSE_LOGIC: if (!strcmp(str, "single")) pkg_set(pkg, PKG_LICENSE_LOGIC, (int64_t) LICENSE_SINGLE); else if (!strcmp(str, "or") || !strcmp(str, "dual")) pkg_set(pkg, PKG_LICENSE_LOGIC, (int64_t)LICENSE_OR); else if (!strcmp(str, "and") || !strcmp(str, "multi")) pkg_set(pkg, PKG_LICENSE_LOGIC, (int64_t)LICENSE_AND); else { pkg_emit_error("Unknown license logic: %s", str); ret = EPKG_FATAL; } break; default: if (attr == PKG_DESC) ret = urldecode(str, &pkg->fields[attr]); else ret = pkg_set(pkg, attr, str); break; } return (ret); }
static int pkg_repo_binary_add_from_manifest(char *buf, const char *origin, const char *digest, long offset, sqlite3 *sqlite, struct pkg_manifest_key **keys, struct pkg **p, bool is_legacy, struct pkg_repo *repo) { int rc = EPKG_OK; struct pkg *pkg; const char *local_origin, *pkg_arch; if (*p == NULL) { rc = pkg_new(p, PKG_REMOTE); if (rc != EPKG_OK) return (EPKG_FATAL); } else { pkg_reset(*p, PKG_REMOTE); } pkg = *p; pkg_manifest_keys_new(keys); rc = pkg_parse_manifest(pkg, buf, offset, *keys); if (rc != EPKG_OK) { goto cleanup; } rc = pkg_is_valid(pkg); if (rc != EPKG_OK) { goto cleanup; } /* Ensure that we have a proper origin and arch*/ pkg_get(pkg, PKG_ORIGIN, &local_origin, PKG_ARCH, &pkg_arch); if (local_origin == NULL || strcmp(local_origin, origin) != 0) { pkg_emit_error("manifest contains origin %s while we wanted to add origin %s", local_origin ? local_origin : "NULL", origin); rc = EPKG_FATAL; goto cleanup; } if (pkg_arch == NULL || !is_valid_abi(pkg_arch, true)) { rc = EPKG_FATAL; pkg_emit_error("repository %s contains packages with wrong ABI: %s", repo->name, pkg_arch); goto cleanup; } pkg_set(pkg, PKG_REPONAME, repo->name); if (is_legacy) { pkg_set(pkg, PKG_OLD_DIGEST, digest); pkg_checksum_calculate(pkg, NULL); } else { pkg_set(pkg, PKG_DIGEST, digest); } rc = pkg_repo_binary_add_pkg(pkg, NULL, sqlite, true); cleanup: return (rc); }
int pkg_old_load_from_path(struct pkg *pkg, const char *path) { char *desc; char *www; char fpath[MAXPATHLEN]; regex_t preg; regmatch_t pmatch[2]; int i; size_t size; char myarch[BUFSIZ]; if (!is_dir(path)) return (EPKG_FATAL); snprintf(fpath, sizeof(fpath), "%s/+CONTENTS", path); if (ports_parse_plist(pkg, fpath, NULL) != EPKG_OK) return (EPKG_FATAL); snprintf(fpath, sizeof(fpath), "%s/+COMMENT", path); if (access(fpath, F_OK) == 0) pkg_set_from_file(pkg, PKG_COMMENT, fpath, true); snprintf(fpath, sizeof(fpath), "%s/+DESC", path); if (access(fpath, F_OK) == 0) pkg_set_from_file(pkg, PKG_DESC, fpath, false); snprintf(fpath, sizeof(fpath), "%s/+DISPLAY", path); if (access(fpath, F_OK) == 0) pkg_set_from_file(pkg, PKG_MESSAGE, fpath, false); snprintf(fpath, sizeof(fpath), "%s/+MTREE_DIRS", path); 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", path, scripts[i]); if (access(fpath, F_OK) == 0) pkg_addscript_file(pkg, fpath); } pkg_get_myarch(myarch, BUFSIZ); pkg_set(pkg, PKG_ARCH, myarch); pkg_set(pkg, PKG_MAINTAINER, "unknown"); 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); return (EPKG_OK); }
static int setprefix(struct plist *p, char *line, struct file_attr *a) { char *pkgprefix; /* if no arguments then set default prefix */ if (line[0] == '\0') { pkg_get(p->pkg, PKG_PREFIX, &pkgprefix); strlcpy(p->prefix, pkgprefix, sizeof(p->prefix)); } else strlcpy(p->prefix, line, sizeof(p->prefix)); pkg_get(p->pkg, PKG_PREFIX, &pkgprefix); if (pkgprefix == NULL || *pkgprefix == '\0') pkg_set(p->pkg, PKG_PREFIX, line); p->slash = p->prefix[strlen(p->prefix) -1] == '/' ? "" : "/"; exec_append(p->post_install_buf, "cd %s\n", p->prefix); pre_unexec_append(p->pre_deinstall_buf, "cd %s\n", p->prefix); post_unexec_append(p->post_deinstall_buf, "cd %s\n", p->prefix); free(a); return (EPKG_OK); }
static int pkg_set_licenselogic_from_node(struct pkg *pkg, yaml_node_t *val, __unused yaml_document_t *doc, __unused int attr) { if (!strcmp(val->data.scalar.value, "single")) pkg_set(pkg, PKG_LICENSE_LOGIC, (int64_t) LICENSE_SINGLE); else if (!strcmp(val->data.scalar.value, "or") || !strcmp(val->data.scalar.value, "dual")) pkg_set(pkg, PKG_LICENSE_LOGIC, (int64_t)LICENSE_OR); else if (!strcmp(val->data.scalar.value, "and") || !strcmp(val->data.scalar.value, "multi")) pkg_set(pkg, PKG_LICENSE_LOGIC, (int64_t)LICENSE_AND); else { pkg_emit_error("Unknown license logic: %s", val->data.scalar.value); return (EPKG_FATAL); } return (EPKG_OK); }
ATF_TC_BODY(pkg_current_state_local, tc) { struct pkg *package; package = gen_pkg(PKG_INSTALLED); ATF_REQUIRE(package != NULL); pkg_set(package, PKG_OLD_VERSION, "1.2.3"); ATF_CHECK_EQ(pkgutils_pkg_current_state(package), PK_INFO_ENUM_INSTALLED); pkg_free(package); }
ATF_TC_BODY(pkg_current_state_remote, tc) { struct pkg *package; package = gen_pkg(PKG_REMOTE); ATF_REQUIRE(package != NULL); /* Old version newer -> available */ pkg_set(package, PKG_OLD_VERSION, "1.2.3"); ATF_CHECK_EQ(pkgutils_pkg_current_state(package), PK_INFO_ENUM_AVAILABLE); /* Old version the same -> installed */ pkg_set(package, PKG_OLD_VERSION, "1.1.4"); ATF_CHECK_EQ(pkgutils_pkg_current_state(package), PK_INFO_ENUM_INSTALLED); /* Old version older -> available */ pkg_set(package, PKG_OLD_VERSION, "1.0.0"); ATF_CHECK_EQ(pkgutils_pkg_current_state(package), PK_INFO_ENUM_AVAILABLE); pkg_free(package); }
static int pkg_set_flatsize_from_node(struct pkg *pkg, yaml_node_t *val, __unused yaml_document_t *doc, __unused int attr) { int64_t flatsize; const char *errstr = NULL; flatsize = strtonum(val->data.scalar.value, 0, INT64_MAX, &errstr); if (errstr) { pkg_emit_error("Unable to convert %s to int64: %s", val->data.scalar.value, errstr); return (EPKG_FATAL); } return (pkg_set(pkg, PKG_FLATSIZE, flatsize)); }
ATF_TC_BODY(pkg_install_state, tc) { struct pkg *package; package = gen_pkg(PKG_REMOTE); ATF_REQUIRE(package != NULL); /* Old version newer -> downgrading */ pkg_set(package, PKG_OLD_VERSION, "1.2.3"); ATF_CHECK_EQ(pkgutils_pkg_install_state(package), PK_INFO_ENUM_DOWNGRADING); /* Old version the same -> reinstalling */ pkg_set(package, PKG_OLD_VERSION, "1.1.4"); ATF_CHECK_EQ(pkgutils_pkg_install_state(package), PK_INFO_ENUM_REINSTALLING); /* Old version older -> updating */ pkg_set(package, PKG_OLD_VERSION, "1.0.0"); ATF_CHECK_EQ(pkgutils_pkg_install_state(package), PK_INFO_ENUM_UPDATING); pkg_free(package); }
/* The "no concessions to old pkg_tools" variant: just get everything * from the manifest */ int pkg_create_from_manifest(const char *outdir, pkg_formats format, const char *rootdir, const char *manifest, bool old) { struct pkg *pkg = NULL; struct packing *pkg_archive = NULL; char arch[BUFSIZ]; int ret = ENOMEM; char *buf; struct pkg_manifest_key *keys = NULL; pkg_debug(1, "Creating package from stage directory: '%s'", rootdir); if(pkg_new(&pkg, old ? PKG_OLD_FILE : PKG_FILE) != EPKG_OK) { ret = EPKG_FATAL; goto cleanup; } pkg_manifest_keys_new(&keys); if ((ret = pkg_parse_manifest_file(pkg, manifest, keys)) != EPKG_OK) { ret = EPKG_FATAL; goto cleanup; } /* if no arch autodetermine it */ pkg_get(pkg, PKG_ARCH, &buf); if (buf == NULL) { pkg_get_myarch(arch, BUFSIZ); pkg_set(pkg, PKG_ARCH, arch); } /* Create the archive */ pkg_archive = pkg_create_archive(outdir, pkg, format, 0); if (pkg_archive == NULL) { ret = EPKG_FATAL; /* XXX do better */ goto cleanup; } pkg_create_from_dir(pkg, rootdir, pkg_archive); ret = EPKG_OK; cleanup: free(pkg); pkg_manifest_keys_free(keys); if (ret == EPKG_OK) ret = packing_finish(pkg_archive); return (ret); }
static int name_key(struct plist *p, char *line, struct file_attr *a) { char *name; char *tmp; pkg_get(p->pkg, PKG_NAME, &name); if (name != NULL && *name != '\0') { free(a); return (EPKG_OK); } tmp = strrchr(line, '-'); tmp[0] = '\0'; tmp++; pkg_set(p->pkg, PKG_NAME, line, PKG_VERSION, tmp); free(a); return (EPKG_OK); }
static int setprefix(struct plist *p, char *line, struct file_attr *a) { char *pkgprefix; /* if no arguments then set default prefix */ if (line[0] == '\0') pkg_get(p->pkg, PKG_PREFIX, &p->prefix); else p->prefix = line; pkg_get(p->pkg, PKG_PREFIX, &pkgprefix); if (pkgprefix == NULL || *pkgprefix == '\0') pkg_set(p->pkg, PKG_PREFIX, line); p->slash = p->prefix[strlen(p->prefix) -1] == '/' ? "" : "/"; free(a); return (EPKG_OK); }
int exec_register(int argc, char **argv) { struct pkg *pkg = NULL; struct pkgdb *db = NULL; regex_t preg; regmatch_t pmatch[2]; int ch; char *plist = NULL; char *arch = NULL; char myarch[BUFSIZ]; char *mdir = NULL; char *www = NULL; char *input_path = NULL; char fpath[MAXPATHLEN + 1]; const char *message; const char *desc = NULL; size_t size; bool legacy = false; bool developer = false; int i; int ret = EPKG_OK, retcode = EX_OK; if (geteuid() != 0) { warnx("registering packages can only be done as root"); return (EX_NOPERM); } pkg_config_bool(PKG_CONFIG_DEVELOPER_MODE, &developer); pkg_new(&pkg, PKG_INSTALLED); while ((ch = getopt(argc, argv, "f:m:i:ld")) != -1) { switch (ch) { case 'f': if ((plist = strdup(optarg)) == NULL) err(1, "cannot allocate memory"); break; case 'm': if ((mdir = strdup(optarg)) == NULL) err(1, "cannot allocate memory"); break; case 'd': pkg_set(pkg, PKG_AUTOMATIC, true); break; case 'i': if ((input_path = strdup(optarg)) == NULL) err(1, "cannot allocate memory"); break; case 'l': legacy = true; break; default: printf("%c\n", ch); usage_register(); return (EX_USAGE); } } if (plist == NULL) errx(EX_USAGE, "missing -f flag"); if (mdir == NULL) errx(EX_USAGE, "missing -m flag"); snprintf(fpath, sizeof(fpath), "%s/+MANIFEST", mdir); if ((ret = pkg_load_manifest_file(pkg, fpath)) != EPKG_OK) { return (EX_IOERR); } snprintf(fpath, sizeof(fpath), "%s/+DESC", mdir); pkg_set_from_file(pkg, PKG_DESC, fpath); snprintf(fpath, sizeof(fpath), "%s/+DISPLAY", mdir); if (access(fpath, F_OK) == 0) pkg_set_from_file(pkg, PKG_MESSAGE, fpath); snprintf(fpath, sizeof(fpath), "%s/+MTREE_DIRS", mdir); if (access(fpath, F_OK) == 0) pkg_set_from_file(pkg, PKG_MTREE, fpath); 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 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); } else { pkg_set(pkg, PKG_WWW, www); free(www); } ret += ports_parse_plist(pkg, plist, input_path); if (ret != EPKG_OK) { return (EX_IOERR); } if (plist != NULL) free(plist); if (pkgdb_open(&db, PKGDB_DEFAULT) != EPKG_OK) { return (EX_IOERR); } pkg_analyse_files(db, pkg); 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 (input_path != NULL) { pkg_copy_tree(pkg, input_path, "/"); free(input_path); } if (pkgdb_register_ports(db, pkg) != EPKG_OK) retcode = EX_SOFTWARE; pkg_get(pkg, PKG_MESSAGE, &message); if (message != NULL && !legacy) printf("%s\n", message); pkgdb_close(db); pkg_free(pkg); return (retcode); }
void read_pkg_file(void *data) { struct thd_data *d = (struct thd_data*) data; struct pkg_result *r; struct pkg_manifest_key *keys = NULL; FTSENT *fts_ent = NULL; char fts_accpath[MAXPATHLEN + 1]; char fts_path[MAXPATHLEN + 1]; char fts_name[MAXPATHLEN + 1]; off_t st_size; int fts_info, flags; char *ext = NULL; char *pkg_path; pkg_manifest_keys_new(&keys); for (;;) { fts_ent = NULL; /* * Get a file to read from. * Copy the data we need from the fts entry localy because as soon as * we unlock the fts_m mutex, we can not access it. */ pthread_mutex_lock(&d->fts_m); if (!d->stop) fts_ent = fts_read(d->fts); if (fts_ent != NULL) { strlcpy(fts_accpath, fts_ent->fts_accpath, sizeof(fts_accpath)); strlcpy(fts_path, fts_ent->fts_path, sizeof(fts_path)); strlcpy(fts_name, fts_ent->fts_name, sizeof(fts_name)); st_size = fts_ent->fts_statp->st_size; fts_info = fts_ent->fts_info; } pthread_mutex_unlock(&d->fts_m); // There is no more jobs, exit the main loop. if (fts_ent == NULL) break; /* skip everything that is not a file */ if (fts_info != FTS_F) continue; ext = strrchr(fts_name, '.'); if (ext == NULL) continue; if (strcmp(ext, ".tgz") != 0 && strcmp(ext, ".tbz") != 0 && strcmp(ext, ".txz") != 0 && strcmp(ext, ".tar") != 0) continue; *ext = '\0'; if (strcmp(fts_name, repo_db_archive) == 0 || strcmp(fts_name, repo_packagesite_archive) == 0 || strcmp(fts_name, repo_filesite_archive) == 0 || strcmp(fts_name, repo_digests_archive) == 0) continue; *ext = '.'; pkg_path = fts_path; pkg_path += strlen(d->root_path); while (pkg_path[0] == '/') pkg_path++; r = calloc(1, sizeof(struct pkg_result)); strlcpy(r->path, pkg_path, sizeof(r->path)); if (d->read_files) flags = PKG_OPEN_MANIFEST_ONLY; else flags = PKG_OPEN_MANIFEST_ONLY | PKG_OPEN_MANIFEST_COMPACT; if (pkg_open(&r->pkg, fts_accpath, keys, flags) != EPKG_OK) { r->retcode = EPKG_WARN; } else { sha256_file(fts_accpath, r->cksum); pkg_set(r->pkg, PKG_CKSUM, r->cksum, PKG_REPOPATH, pkg_path, PKG_PKGSIZE, st_size); } /* Add result to the FIFO and notify */ pthread_mutex_lock(&d->results_m); while (d->num_results >= d->max_results) { pthread_cond_wait(&d->has_room, &d->results_m); } LL_APPEND(d->results, r); d->num_results++; pthread_cond_signal(&d->has_result); pthread_mutex_unlock(&d->results_m); } /* * This thread is about to exit. * Notify the main thread that we are done. */ pthread_mutex_lock(&d->results_m); d->thd_finished++; pthread_cond_signal(&d->has_result); pthread_mutex_unlock(&d->results_m); pkg_manifest_keys_free(keys); }
static int pkg_create_from_dir(struct pkg *pkg, const char *root, struct packing *pkg_archive) { char fpath[MAXPATHLEN]; struct pkg_file *file = NULL; struct pkg_dir *dir = NULL; char *m; int ret; const char *mtree; bool developer; struct stat st; char sha256[SHA256_DIGEST_LENGTH * 2 + 1]; int64_t flatsize = 0; ucl_object_t *obj; if (pkg_is_valid(pkg) != EPKG_OK) { pkg_emit_error("the package is not valid"); return (EPKG_FATAL); } obj = pkg_annotation_lookup(pkg, "relocated"); /* * Get / compute size / checksum if not provided in the manifest */ while (pkg_files(pkg, &file) == EPKG_OK) { const char *pkg_path = pkg_file_path(file); const char *pkg_sum = pkg_file_cksum(file); snprintf(fpath, sizeof(fpath), "%s%s%s", root ? root : "", obj ? pkg_object_string(obj) : "", pkg_path); if (lstat(fpath, &st) != 0 || S_ISLNK(st.st_mode)) continue; if (file->size == 0) file->size = (int64_t)st.st_size; flatsize += file->size; if (pkg_sum == NULL || pkg_sum[0] == '\0') { if (pkg->type == PKG_OLD_FILE) { if (md5_file(fpath, sha256) != EPKG_OK) return (EPKG_FATAL); } else { if (sha256_file(fpath, sha256) != EPKG_OK) return (EPKG_FATAL); } strlcpy(file->sum, sha256, sizeof(file->sum)); } } pkg_set(pkg, PKG_FLATSIZE, flatsize); if (pkg->type == PKG_OLD_FILE) { const char *desc, *display, *comment; char oldcomment[BUFSIZ]; pkg_old_emit_content(pkg, &m); packing_append_buffer(pkg_archive, m, "+CONTENTS", strlen(m)); free(m); pkg_get(pkg, PKG_DESC, &desc, PKG_MESSAGE, &display, PKG_COMMENT, &comment); packing_append_buffer(pkg_archive, desc, "+DESC", strlen(desc)); packing_append_buffer(pkg_archive, display, "+DISPLAY", strlen(display)); snprintf(oldcomment, sizeof(oldcomment), "%s\n", comment); packing_append_buffer(pkg_archive, oldcomment, "+COMMENT", strlen(oldcomment)); } else { /* * Register shared libraries used by the package if * SHLIBS enabled in conf. Deletes shlib info if not. */ struct sbuf *b = sbuf_new_auto(); pkg_register_shlibs(pkg, root); pkg_emit_manifest_sbuf(pkg, b, PKG_MANIFEST_EMIT_COMPACT, NULL); packing_append_buffer(pkg_archive, sbuf_data(b), "+COMPACT_MANIFEST", sbuf_len(b)); sbuf_clear(b); pkg_emit_manifest_sbuf(pkg, b, 0, NULL); sbuf_finish(b); packing_append_buffer(pkg_archive, sbuf_data(b), "+MANIFEST", sbuf_len(b)); sbuf_delete(b); } pkg_get(pkg, PKG_MTREE, &mtree); if (mtree != NULL) packing_append_buffer(pkg_archive, mtree, "+MTREE_DIRS", strlen(mtree)); while (pkg_files(pkg, &file) == EPKG_OK) { const char *pkg_path = pkg_file_path(file); snprintf(fpath, sizeof(fpath), "%s%s%s", root ? root : "", obj ? pkg_object_string(obj) : "", pkg_path); ret = packing_append_file_attr(pkg_archive, fpath, pkg_path, file->uname, file->gname, file->perm); developer = pkg_object_bool(pkg_config_get("DEVELOPER_MODE")); if (developer && ret != EPKG_OK) return (ret); } while (pkg_dirs(pkg, &dir) == EPKG_OK) { const char *pkg_path = pkg_dir_path(dir); snprintf(fpath, sizeof(fpath), "%s%s%s", root ? root : "", obj ? pkg_object_string(obj) : "", pkg_path); ret = packing_append_file_attr(pkg_archive, fpath, pkg_path, dir->uname, dir->gname, dir->perm); developer = pkg_object_bool(pkg_config_get("DEVELOPER_MODE")); if (developer && ret != EPKG_OK) return (ret); } return (EPKG_OK); }
int exec_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 pkg_add(struct pkgdb *db, const char *path, unsigned flags) { const char *arch; const char *myarch; const char *origin; struct archive *a; struct archive_entry *ae; struct pkg *pkg = NULL; struct pkg_dep *dep = NULL; struct pkg *pkg_inst = NULL; bool extract = true; bool handle_rc = false; char dpath[MAXPATHLEN + 1]; const char *basedir; const char *ext; char *mtree; char *prefix; int retcode = EPKG_OK; int ret; assert(path != NULL); /* * Open the package archive file, read all the meta files and set the * current archive_entry to the first non-meta file. * If there is no non-meta files, EPKG_END is returned. */ ret = pkg_open2(&pkg, &a, &ae, path); if (ret == EPKG_END) extract = false; else if (ret != EPKG_OK) { retcode = ret; goto cleanup; } if ((flags & PKG_ADD_UPGRADE) == 0) pkg_emit_install_begin(pkg); if (pkg_is_valid(pkg) != EPKG_OK) { pkg_emit_error("the package is not valid"); return (EPKG_FATAL); } if (flags & PKG_ADD_AUTOMATIC) pkg_set(pkg, PKG_AUTOMATIC, true); /* * Check the architecture */ pkg_config_string(PKG_CONFIG_ABI, &myarch); pkg_get(pkg, PKG_ARCH, &arch, PKG_ORIGIN, &origin); if (fnmatch(myarch, arch, FNM_CASEFOLD) == FNM_NOMATCH && strncmp(arch, myarch, strlen(myarch)) != 0) { pkg_emit_error("wrong architecture: %s instead of %s", arch, myarch); if ((flags & PKG_ADD_FORCE) == 0) { retcode = EPKG_FATAL; goto cleanup; } } /* * Check if the package is already installed */ ret = pkg_try_installed(db, origin, &pkg_inst, PKG_LOAD_BASIC); if (ret == EPKG_OK) { pkg_emit_already_installed(pkg_inst); retcode = EPKG_INSTALLED; goto cleanup; } else if (ret != EPKG_END) { retcode = ret; goto cleanup; } /* * Check for dependencies */ basedir = dirname(path); if ((ext = strrchr(path, '.')) == NULL) { pkg_emit_error("%s has no extension", path); retcode = EPKG_FATAL; goto cleanup; } while (pkg_deps(pkg, &dep) == EPKG_OK) { if (pkg_is_installed(db, pkg_dep_origin(dep)) != EPKG_OK) { const char *dep_name = pkg_dep_name(dep); const char *dep_ver = pkg_dep_version(dep); snprintf(dpath, sizeof(dpath), "%s/%s-%s%s", basedir, dep_name, dep_ver, ext); if ((flags & PKG_ADD_UPGRADE) == 0 && access(dpath, F_OK) == 0) { ret = pkg_add(db, dpath, PKG_ADD_AUTOMATIC); if (ret != EPKG_OK) { retcode = EPKG_FATAL; goto cleanup; } } else { retcode = EPKG_FATAL; pkg_emit_missing_dep(pkg, dep); goto cleanup; } } } /* register the package before installing it in case there are * problems that could be caught here. */ if ((flags & PKG_ADD_UPGRADE) == 0) retcode = pkgdb_register_pkg(db, pkg, 0); else retcode = pkgdb_register_pkg(db, pkg, 1); if (retcode != EPKG_OK) goto cleanup; pkg_get(pkg, PKG_PREFIX, &prefix, PKG_MTREE, &mtree); if ((retcode = do_extract_mtree(mtree, prefix)) != EPKG_OK) goto cleanup_reg; /* * Execute pre-install scripts */ if ((flags & (PKG_ADD_NOSCRIPT | PKG_ADD_USE_UPGRADE_SCRIPTS)) == 0) pkg_script_run(pkg, PKG_SCRIPT_PRE_INSTALL); /* add the user and group if necessary */ /* pkg_add_user_group(pkg); */ /* * Extract the files on disk. */ if (extract && (retcode = do_extract(a, ae)) != EPKG_OK) { /* If the add failed, clean up */ pkg_delete_files(pkg, 1); pkg_delete_dirs(db, pkg, 1); goto cleanup_reg; } /* * Execute post install scripts */ if ((flags & PKG_ADD_NOSCRIPT) == 0) { if (flags & PKG_ADD_USE_UPGRADE_SCRIPTS) pkg_script_run(pkg, PKG_SCRIPT_POST_UPGRADE); else pkg_script_run(pkg, PKG_SCRIPT_POST_INSTALL); } /* * start the different related services if the users do want that * and that the service is running */ pkg_config_bool(PKG_CONFIG_HANDLE_RC_SCRIPTS, &handle_rc); if (handle_rc) pkg_start_stop_rc_scripts(pkg, PKG_RC_START); cleanup_reg: if ((flags & PKG_ADD_UPGRADE) == 0) pkgdb_register_finale(db, retcode); if (retcode == EPKG_OK && (flags & PKG_ADD_UPGRADE) == 0) pkg_emit_install_finished(pkg); cleanup: if (a != NULL) archive_read_free(a); pkg_free(pkg); pkg_free(pkg_inst); return (retcode); }
int pkgdb_it_next(struct pkgdb_it *it, struct pkg **pkg_p, int flags) { struct pkg *pkg; int ret; if (it == NULL) return (ERROR_BAD_ARG("it")); switch (sqlite3_step(it->stmt)) { case SQLITE_ROW: if (*pkg_p == NULL) pkg_new(pkg_p, PKG_INSTALLED); else pkg_reset(*pkg_p, PKG_INSTALLED); pkg = *pkg_p; pkg->rowid = sqlite3_column_int64(it->stmt, 0); pkg_set(pkg, PKG_ORIGIN, sqlite3_column_text(it->stmt, 1)); pkg_set(pkg, PKG_NAME, sqlite3_column_text(it->stmt, 2)); pkg_set(pkg, PKG_VERSION, sqlite3_column_text(it->stmt, 3)); pkg_set(pkg, PKG_COMMENT, sqlite3_column_text(it->stmt, 4)); pkg_set(pkg, PKG_DESC, sqlite3_column_text(it->stmt, 5)); pkg_set(pkg, PKG_MESSAGE, sqlite3_column_text(it->stmt, 6)); pkg_set(pkg, PKG_ARCH, sqlite3_column_text(it->stmt, 7)); pkg_set(pkg, PKG_OSVERSION, sqlite3_column_text(it->stmt, 8)); pkg_set(pkg, PKG_MAINTAINER, sqlite3_column_text(it->stmt, 9)); pkg_set(pkg, PKG_WWW, sqlite3_column_text(it->stmt, 10)); pkg_set(pkg, PKG_PREFIX, sqlite3_column_text(it->stmt, 11)); pkg_setflatsize(pkg, sqlite3_column_int64(it->stmt, 12)); if (it->type == IT_UPGRADE) { pkg->type = PKG_UPGRADE; pkg_set(pkg, PKG_NEWVERSION, sqlite3_column_text(it->stmt, 13)); pkg_setnewflatsize(pkg, sqlite3_column_int64(it->stmt, 14)); pkg_setnewpkgsize(pkg, sqlite3_column_int64(it->stmt, 15)); pkg_set(pkg, PKG_REPOPATH, sqlite3_column_text(it->stmt, 16)); } if (flags & PKG_LOAD_DEPS) if ((ret = pkgdb_loaddeps(it->db, pkg)) != EPKG_OK) return (ret); if (flags & PKG_LOAD_RDEPS) if ((ret = pkgdb_loadrdeps(it->db, pkg)) != EPKG_OK) return (ret); if (flags & PKG_LOAD_CONFLICTS) if ((ret = pkgdb_loadconflicts(it->db, pkg)) != EPKG_OK) return (ret); if (flags & PKG_LOAD_FILES) if ((ret = pkgdb_loadfiles(it->db, pkg)) != EPKG_OK) return (ret); if (flags & PKG_LOAD_SCRIPTS) if ((ret = pkgdb_loadscripts(it->db, pkg)) != EPKG_OK) return (ret); if (flags & PKG_LOAD_OPTIONS) if ((ret = pkgdb_loadoptions(it->db, pkg)) != EPKG_OK) return (ret); if (flags & PKG_LOAD_MTREE) if ((ret = pkgdb_loadmtree(it->db, pkg)) != EPKG_OK) return (ret); return (EPKG_OK); case SQLITE_DONE: return (EPKG_END); default: return (ERROR_SQLITE(it->db->sqlite)); } }
static int pkg_repo_binary_try_fetch(struct pkg_repo *repo, struct pkg *pkg, bool already_tried, bool mirror, const char *destdir) { char dest[MAXPATHLEN]; char url[MAXPATHLEN]; char *dir = NULL; int fetched = 0; char cksum[SHA256_DIGEST_LENGTH * 2 +1]; int64_t pkgsize; struct stat st; char *path = NULL; const char *packagesite = NULL, *repourl; int retcode = EPKG_OK; const char *name, *version, *sum; assert((pkg->type & PKG_REMOTE) == PKG_REMOTE); pkg_get(pkg, PKG_CKSUM, &sum, PKG_NAME, &name, PKG_VERSION, &version, PKG_PKGSIZE, &pkgsize, PKG_REPOPATH, &repourl); if (mirror) { const char *cachedir; if (destdir != NULL) cachedir = destdir; else cachedir = pkg_object_string(pkg_config_get("PKG_CACHEDIR")); snprintf(dest, sizeof(dest), "%s/%s", cachedir, repourl); } else pkg_repo_binary_get_cached_name(repo, pkg, dest, sizeof(dest)); /* If it is already in the local cachedir, dont bother to * download it */ if (access(dest, F_OK) == 0) goto checksum; /* Create the dirs in cachedir */ dir = strdup(dest); if (dir == NULL || (path = dirname(dir)) == NULL) { pkg_emit_errno("dirname", dest); retcode = EPKG_FATAL; goto cleanup; } if ((retcode = mkdirs(path)) != EPKG_OK) goto cleanup; /* * In multi-repos the remote URL is stored in pkg[PKG_REPOURL] * For a single attached database the repository URL should be * defined by PACKAGESITE. */ packagesite = pkg_repo_url(repo); if (packagesite == NULL || packagesite[0] == '\0') { pkg_emit_error("PACKAGESITE is not defined"); retcode = 1; goto cleanup; } if (packagesite[strlen(packagesite) - 1] == '/') pkg_snprintf(url, sizeof(url), "%S%R", packagesite, pkg); else pkg_snprintf(url, sizeof(url), "%S/%R", packagesite, pkg); if (!mirror && strncasecmp(packagesite, "file://", 7) == 0) { pkg_set(pkg, PKG_REPOPATH, url + 7); return (EPKG_OK); } retcode = pkg_fetch_file(repo, url, dest, 0); fetched = 1; if (retcode != EPKG_OK) goto cleanup; checksum: /* checksum calculation is expensive, if size does not match, skip it and assume failed checksum. */ if (stat(dest, &st) == -1 || pkgsize != st.st_size) { if (already_tried) { pkg_emit_error("cached package %s-%s: " "size mismatch, cannot continue", name, version); retcode = EPKG_FATAL; goto cleanup; } unlink(dest); pkg_emit_error("cached package %s-%s: " "size mismatch, fetching from remote", name, version); return (pkg_repo_binary_try_fetch(repo, pkg, true, mirror, destdir)); } retcode = sha256_file(dest, cksum); if (retcode == EPKG_OK) { if (strcmp(cksum, sum)) { if (already_tried || fetched == 1) { pkg_emit_error("%s-%s failed checksum " "from repository", name, version); retcode = EPKG_FATAL; } else { pkg_emit_error("cached package %s-%s: " "checksum mismatch, fetching from remote", name, version); unlink(dest); return (pkg_repo_binary_try_fetch(repo, pkg, true, mirror, destdir)); } } } cleanup: if (retcode != EPKG_OK) unlink(dest); else if (!mirror && path != NULL) { (void)pkg_repo_binary_create_symlink(pkg, dest, path); } /* allowed even if dir is NULL */ free(dir); return (retcode); }
static int pkg_int(struct pkg *pkg, ucl_object_t *obj, int attr) { return (pkg_set(pkg, attr, ucl_object_toint(obj))); }
int exec_audit(int argc, char **argv) { struct pkg_audit *audit; struct pkgdb *db = NULL; struct pkgdb_it *it = NULL; struct pkg *pkg = NULL; const char *db_dir; char *name; char *version; char audit_file_buf[MAXPATHLEN]; char *audit_file = audit_file_buf; unsigned int vuln = 0; bool fetch = false, recursive = false; int ch, i; int ret = EX_OK; const char *portaudit_site = NULL; struct sbuf *sb; kh_pkgs_t *check = NULL; db_dir = pkg_object_string(pkg_config_get("PKG_DBDIR")); snprintf(audit_file_buf, sizeof(audit_file_buf), "%s/vuln.xml", db_dir); struct option longopts[] = { { "fetch", no_argument, NULL, 'F' }, { "file", required_argument, NULL, 'f' }, { "recursive", no_argument, NULL, 'r' }, { "quiet", no_argument, NULL, 'q' }, { NULL, 0, NULL, 0 }, }; while ((ch = getopt_long(argc, argv, "+Ff:qr", longopts, NULL)) != -1) { switch (ch) { case 'F': fetch = true; break; case 'f': audit_file = optarg; break; case 'q': quiet = true; break; case 'r': recursive = true; break; default: usage_audit(); return(EX_USAGE); } } argc -= optind; argv += optind; audit = pkg_audit_new(); if (fetch == true) { portaudit_site = pkg_object_string(pkg_config_get("VULNXML_SITE")); if (pkg_audit_fetch(portaudit_site, audit_file) != EPKG_OK) { pkg_audit_free(audit); return (EX_IOERR); } } if (pkg_audit_load(audit, audit_file) != EPKG_OK) { if (errno == ENOENT) warnx("vulnxml file %s does not exist. " "Try running 'pkg audit -F' first", audit_file); else warn("unable to open vulnxml file %s", audit_file); pkg_audit_free(audit); return (EX_DATAERR); } check = kh_init_pkgs(); if (argc >= 1) { for (i = 0; i < argc; i ++) { name = argv[i]; version = strrchr(name, '-'); if (version != NULL) { version[0] = '\0'; version++; } if (pkg_new(&pkg, PKG_FILE) != EPKG_OK) err(EX_OSERR, "malloc"); if (version != NULL) pkg_set(pkg, PKG_NAME, name, PKG_VERSION, version); else pkg_set(pkg, PKG_NAME, name); /* Fake uniqueid */ pkg_set(pkg, PKG_UNIQUEID, name); add_to_check(check, pkg); pkg = NULL; } } else { /* * if the database doesn't exist it just means there are no * packages to audit. */ ret = pkgdb_access(PKGDB_MODE_READ, PKGDB_DB_LOCAL); if (ret == EPKG_ENODB) { pkg_audit_free(audit); kh_destroy_pkgs(check); return (EX_OK); } else if (ret == EPKG_ENOACCESS) { warnx("Insufficient privileges to read the package database"); pkg_audit_free(audit); kh_destroy_pkgs(check); return (EX_NOPERM); } else if (ret != EPKG_OK) { warnx("Error accessing the package database"); pkg_audit_free(audit); kh_destroy_pkgs(check); return (EX_IOERR); } if (pkgdb_open(&db, PKGDB_DEFAULT) != EPKG_OK) { pkg_audit_free(audit); kh_destroy_pkgs(check); return (EX_IOERR); } if (pkgdb_obtain_lock(db, PKGDB_LOCK_READONLY) != EPKG_OK) { pkgdb_close(db); pkg_audit_free(audit); kh_destroy_pkgs(check); warnx("Cannot get a read lock on a database, it is locked by another process"); return (EX_TEMPFAIL); } if ((it = pkgdb_query(db, NULL, MATCH_ALL)) == NULL) { warnx("Error accessing the package database"); ret = EX_IOERR; } else { while ((ret = pkgdb_it_next(it, &pkg, PKG_LOAD_BASIC|PKG_LOAD_RDEPS)) == EPKG_OK) { add_to_check(check, pkg); pkg = NULL; } ret = EX_OK; } if (db != NULL) { pkgdb_it_free(it); pkgdb_release_lock(db, PKGDB_LOCK_READONLY); pkgdb_close(db); } if (ret != EX_OK) { pkg_audit_free(audit); kh_destroy_pkgs(check); return (ret); } } /* Now we have vulnxml loaded and check list formed */ #ifdef HAVE_CAPSICUM if (cap_enter() < 0 && errno != ENOSYS) { warn("cap_enter() failed"); pkg_audit_free(audit); kh_destroy_pkgs(check); return (EPKG_FATAL); } #endif if (pkg_audit_process(audit) == EPKG_OK) { kh_foreach_value(check, pkg, { if (pkg_audit_is_vulnerable(audit, pkg, quiet, &sb)) { vuln ++; printf("%s", sbuf_data(sb)); if (recursive) { const char *name; kh_pkgs_t *seen = kh_init_pkgs(); pkg_get(pkg, PKG_NAME, &name); sbuf_clear(sb); sbuf_printf(sb, "Packages that depend on %s: ", name); print_recursive_rdeps(check, pkg , sb, seen, true); sbuf_finish(sb); printf("%s\n\n", sbuf_data(sb)); kh_destroy_pkgs(seen); } sbuf_delete(sb); } pkg_free(pkg); });
int pkg_create_staged(const char *outdir, pkg_formats format, const char *rootdir, const char *md_dir, char *plist, bool old) { struct pkg *pkg = NULL; struct pkg_file *file = NULL; struct pkg_dir *dir = NULL; struct packing *pkg_archive = NULL; char *manifest = NULL; char path[MAXPATHLEN]; char arch[BUFSIZ]; int ret = ENOMEM; char *buf; int i; regex_t preg; regmatch_t pmatch[2]; size_t size; char *www = NULL; struct pkg_manifest_key *keys = NULL; pkg_debug(1, "Creating package from stage directory: '%s'", rootdir); /* Load the manifest from the metadata directory */ if (snprintf(path, sizeof(path), "%s/+MANIFEST", md_dir) == -1) goto cleanup; if(pkg_new(&pkg, old ? PKG_OLD_FILE : PKG_FILE) != EPKG_OK) { ret = EPKG_FATAL; goto cleanup; } pkg_manifest_keys_new(&keys); if ((ret = pkg_parse_manifest_file(pkg, path, keys)) != EPKG_OK) { ret = EPKG_FATAL; goto cleanup; } /* if no descriptions provided then try to get it from a file */ pkg_get(pkg, PKG_DESC, &buf); if (buf == NULL) { if (snprintf(path, sizeof(path), "%s/+DESC", md_dir) == -1) goto cleanup; if (access(path, F_OK) == 0) { pkg_debug(1, "Taking description from: '%s'", path); pkg_set_from_file(pkg, PKG_DESC, path, false); } } /* if no message try to get it from a file */ pkg_get(pkg, PKG_MESSAGE, &buf); if (buf == NULL) { ret = snprintf(path, sizeof(path), "%s/+DISPLAY", md_dir); if (ret == -1) goto cleanup; if (access(path, F_OK) == 0) { pkg_debug(1, "Taking message from: '%s'", path); pkg_set_from_file(pkg, PKG_MESSAGE, path, false); } } /* if no arch autodetermine it */ pkg_get(pkg, PKG_ARCH, &buf); if (buf == NULL) { pkg_get_myarch(arch, BUFSIZ); pkg_set(pkg, PKG_ARCH, arch); } /* if no mtree try to get it from a file */ pkg_get(pkg, PKG_MTREE, &buf); if (buf == NULL) { ret = snprintf(path, sizeof(path), "%s/+MTREE_DIRS", md_dir); if (ret == -1) goto cleanup; if (access(path, F_OK) == 0) { pkg_debug(1, "Taking mtree definition from: '%s'", path); pkg_set_from_file(pkg, PKG_MTREE, path, false); } } for (i = 0; scripts[i] != NULL; i++) { snprintf(path, sizeof(path), "%s/%s", md_dir, scripts[i]); if (access(path, F_OK) == 0) pkg_addscript_file(pkg, path); } if (plist != NULL && ports_parse_plist(pkg, plist, rootdir) != EPKG_OK) { ret = EPKG_FATAL; goto cleanup; } /* if www is not given then try to determine it from description */ if (www != NULL) { pkg_set(pkg, PKG_WWW, www); free(www); } pkg_get(pkg, PKG_WWW, &www); if (www == NULL) { pkg_get(pkg, PKG_DESC, &buf); if (buf == NULL) { pkg_emit_error("No www or desc defined in manifest"); ret = EPKG_FATAL; goto cleanup; } regcomp(&preg, "^WWW:[[:space:]]*(.*)$", REG_EXTENDED|REG_ICASE|REG_NEWLINE); if (regexec(&preg, buf, 2, pmatch, 0) == 0) { size = pmatch[1].rm_eo - pmatch[1].rm_so; www = strndup(&buf[pmatch[1].rm_so], size); pkg_set(pkg, PKG_WWW, www); free(www); } else { pkg_set(pkg, PKG_WWW, "UNKNOWN"); } regfree(&preg); } /* Create the archive */ pkg_archive = pkg_create_archive(outdir, pkg, format, 0); if (pkg_archive == NULL) { ret = EPKG_FATAL; /* XXX do better */ goto cleanup; } /* XXX: autoplist support doesn't work right with meta-ports */ if (0 && pkg_files(pkg, &file) != EPKG_OK && pkg_dirs(pkg, &dir) != EPKG_OK) { /* Now traverse the file directories, adding to the archive */ packing_append_tree(pkg_archive, md_dir, NULL); packing_append_tree(pkg_archive, rootdir, "/"); } else { pkg_create_from_dir(pkg, rootdir, pkg_archive); } ret = EPKG_OK; cleanup: free(pkg); free(manifest); pkg_manifest_keys_free(keys); if (ret == EPKG_OK) ret = packing_finish(pkg_archive); return ret; }
int pkg_add(struct pkgdb *db, const char *path, unsigned flags, struct pkg_manifest_key *keys) { const char *arch; const char *origin; const char *name; struct archive *a; struct archive_entry *ae; struct pkg *pkg = NULL; struct pkg_dep *dep = NULL; struct pkg *pkg_inst = NULL; bool extract = true; bool handle_rc = false; bool disable_mtree; char dpath[MAXPATHLEN]; const char *basedir; const char *ext; char *mtree; char *prefix; int retcode = EPKG_OK; int ret; assert(path != NULL); /* * Open the package archive file, read all the meta files and set the * current archive_entry to the first non-meta file. * If there is no non-meta files, EPKG_END is returned. */ ret = pkg_open2(&pkg, &a, &ae, path, keys, 0); if (ret == EPKG_END) extract = false; else if (ret != EPKG_OK) { retcode = ret; goto cleanup; } if ((flags & PKG_ADD_UPGRADE) == 0) pkg_emit_install_begin(pkg); if (pkg_is_valid(pkg) != EPKG_OK) { pkg_emit_error("the package is not valid"); return (EPKG_FATAL); } if (flags & PKG_ADD_AUTOMATIC) pkg_set(pkg, PKG_AUTOMATIC, (int64_t)true); /* * Check the architecture */ pkg_get(pkg, PKG_ARCH, &arch, PKG_ORIGIN, &origin, PKG_NAME, &name); if (!is_valid_abi(arch, true)) { if ((flags & PKG_ADD_FORCE) == 0) { retcode = EPKG_FATAL; goto cleanup; } } /* * Check if the package is already installed */ ret = pkg_try_installed(db, origin, &pkg_inst, PKG_LOAD_BASIC); if (ret == EPKG_OK) { if ((flags & PKG_FLAG_FORCE) == 0) { pkg_emit_already_installed(pkg_inst); retcode = EPKG_INSTALLED; pkg_free(pkg_inst); pkg_inst = NULL; goto cleanup; } else { pkg_emit_notice("package %s is already installed, forced install", name); pkg_free(pkg_inst); pkg_inst = NULL; } } else if (ret != EPKG_END) { retcode = ret; goto cleanup; } /* * Check for dependencies by searching the same directory as * the package archive we're reading. Of course, if we're * reading from a file descriptor or a unix domain socket or * somesuch, there's no valid directory to search. */ if (pkg_type(pkg) == PKG_FILE) { basedir = dirname(path); if ((ext = strrchr(path, '.')) == NULL) { pkg_emit_error("%s has no extension", path); retcode = EPKG_FATAL; goto cleanup; } } else { basedir = NULL; ext = NULL; } while (pkg_deps(pkg, &dep) == EPKG_OK) { if (pkg_is_installed(db, pkg_dep_origin(dep)) == EPKG_OK) continue; if (basedir != NULL) { const char *dep_name = pkg_dep_name(dep); const char *dep_ver = pkg_dep_version(dep); snprintf(dpath, sizeof(dpath), "%s/%s-%s%s", basedir, dep_name, dep_ver, ext); if ((flags & PKG_ADD_UPGRADE) == 0 && access(dpath, F_OK) == 0) { ret = pkg_add(db, dpath, PKG_ADD_AUTOMATIC, keys); if (ret != EPKG_OK) { retcode = EPKG_FATAL; goto cleanup; } } else { pkg_emit_error("Missing dependency matching '%s'", pkg_dep_get(dep, PKG_DEP_ORIGIN)); retcode = EPKG_FATAL; goto cleanup; } } else { retcode = EPKG_FATAL; pkg_emit_missing_dep(pkg, dep); goto cleanup; } } /* register the package before installing it in case there are * problems that could be caught here. */ retcode = pkgdb_register_pkg(db, pkg, flags & PKG_ADD_UPGRADE, flags & PKG_FLAG_FORCE); if (retcode != EPKG_OK) goto cleanup; /* MTREE replicates much of the standard functionality * inplicit in the way pkg works. It has to remain available * in the ports for compatibility with the old pkg_tools, but * ultimately, MTREE should be made redundant. Use this for * experimantal purposes and to develop MTREE-free versions of * packages. */ pkg_config_bool(PKG_CONFIG_DISABLE_MTREE, &disable_mtree); if (!disable_mtree) { pkg_get(pkg, PKG_PREFIX, &prefix, PKG_MTREE, &mtree); if ((retcode = do_extract_mtree(mtree, prefix)) != EPKG_OK) goto cleanup_reg; } /* * Execute pre-install scripts */ if ((flags & (PKG_ADD_NOSCRIPT | PKG_ADD_USE_UPGRADE_SCRIPTS)) == 0) pkg_script_run(pkg, PKG_SCRIPT_PRE_INSTALL); /* add the user and group if necessary */ /* pkg_add_user_group(pkg); */ /* * Extract the files on disk. */ if (extract && (retcode = do_extract(a, ae)) != EPKG_OK) { /* If the add failed, clean up (silently) */ pkg_delete_files(pkg, 2); pkg_delete_dirs(db, pkg, 1); goto cleanup_reg; } /* * Execute post install scripts */ if ((flags & PKG_ADD_NOSCRIPT) == 0) { if ((flags & PKG_ADD_USE_UPGRADE_SCRIPTS) == PKG_ADD_USE_UPGRADE_SCRIPTS) pkg_script_run(pkg, PKG_SCRIPT_POST_UPGRADE); else pkg_script_run(pkg, PKG_SCRIPT_POST_INSTALL); } /* * start the different related services if the users do want that * and that the service is running */ pkg_config_bool(PKG_CONFIG_HANDLE_RC_SCRIPTS, &handle_rc); if (handle_rc) pkg_start_stop_rc_scripts(pkg, PKG_RC_START); cleanup_reg: if ((flags & PKG_ADD_UPGRADE) == 0) pkgdb_register_finale(db, retcode); if (retcode == EPKG_OK && (flags & PKG_ADD_UPGRADE) == 0) pkg_emit_install_finished(pkg); cleanup: if (a != NULL) { archive_read_close(a); archive_read_free(a); } pkg_free(pkg); if (pkg_inst != NULL) pkg_free(pkg_inst); return (retcode); }
int exec_register(int argc, char **argv) { struct pkg *pkg; struct pkgdb *db; struct utsname u; regex_t preg; regmatch_t pmatch[2]; int ch; char *plist = NULL; char *v = NULL; char *arch = NULL; char *mdir = NULL; char *www = NULL; char *input_path = NULL; char fpath[MAXPATHLEN]; const char *desc = NULL; size_t size; bool heuristic = false; bool legacy = false; int retcode = 0; int ret = 0; if (geteuid() != 0) { warnx("registering packages can only be done as root"); return (EX_NOPERM); } pkg_new(&pkg, PKG_INSTALLED); while ((ch = getopt(argc, argv, "a:f:m:i:l")) != -1) { switch (ch) { case 'f': if ((plist = strdup(optarg)) == NULL) errx(1, "cannot allocate memory"); break; case 'm': mdir = strdup(optarg); break; case 'a': arch = strdup(optarg); break; case 'i': if ((input_path = strdup(optarg)) == NULL) errx(1, "cannot allocate memory"); break; case 'l': legacy = true; break; default: printf("%c\n", ch); usage_register(); return (-1); } } if (ret != 0) { pkg_error_warn("can not parse arguments"); return (1); } if (plist == NULL) errx(EX_USAGE, "missing -f flag"); uname(&u); if (arch == NULL) { pkg_set(pkg, PKG_ARCH, u.machine); } else { pkg_set(pkg, PKG_ARCH, arch); free(arch); } if (mdir == NULL) errx(EX_USAGE, "missing -m flag"); snprintf(fpath, MAXPATHLEN, "%s/+MANIFEST", mdir); if ((ret = pkg_load_manifest_file(pkg, fpath)) != EPKG_OK) { pkg_error_warn("can not parse manifest %s", fpath); return (EX_SOFTWARE); } snprintf(fpath, MAXPATHLEN, "%s/+DESC", mdir); pkg_set_from_file(pkg, PKG_DESC, fpath); snprintf(fpath, MAXPATHLEN, "%s/+DISPLAY", mdir); pkg_set_from_file(pkg, PKG_MESSAGE, fpath); snprintf(fpath, MAXPATHLEN, "%s/+MTREE_DIR", mdir); pkg_set_from_file(pkg, PKG_MTREE, mdir); snprintf(fpath, MAXPATHLEN, "%s/+INSTALL", mdir); pkg_addscript(pkg, fpath); snprintf(fpath, MAXPATHLEN, "%s/+PRE_INSTALL", mdir); pkg_addscript(pkg, fpath); snprintf(fpath, MAXPATHLEN, "%s/+POST_INSTALL", mdir); pkg_addscript(pkg, fpath); snprintf(fpath, MAXPATHLEN, "%s/+DEINSTALL", mdir); pkg_addscript(pkg, fpath); snprintf(fpath, MAXPATHLEN, "%s/+PRE_DEINSTALL", mdir); pkg_addscript(pkg, fpath); snprintf(fpath, MAXPATHLEN, "%s/+POST_DEINSTALL", mdir); pkg_addscript(pkg, fpath); snprintf(fpath, MAXPATHLEN, "%s/+UPGRADE", mdir); pkg_addscript(pkg, fpath); snprintf(fpath, MAXPATHLEN, "%s/+PRE_UPGRADE", mdir); pkg_addscript(pkg, fpath); snprintf(fpath, MAXPATHLEN, "%s/+POST_UPGRADE", mdir); pkg_addscript(pkg, fpath); snprintf(fpath, MAXPATHLEN, "%s/pkg-install", mdir); pkg_addscript(pkg, fpath); snprintf(fpath, MAXPATHLEN, "%s/pkg-pre-install", mdir); pkg_addscript(pkg, fpath); snprintf(fpath, MAXPATHLEN, "%s/pkg-post-install", mdir); pkg_addscript(pkg, fpath); snprintf(fpath, MAXPATHLEN, "%s/pkg-pre-deinstall", mdir); pkg_addscript(pkg, fpath); snprintf(fpath, MAXPATHLEN, "%s/pkg-post-deinstall", mdir); pkg_addscript(pkg, fpath); snprintf(fpath, MAXPATHLEN, "%s/pkg-upgrade", mdir); pkg_addscript(pkg, fpath); snprintf(fpath, MAXPATHLEN, "%s/pkg-pre-deupgrade", mdir); pkg_addscript(pkg, fpath); snprintf(fpath, MAXPATHLEN, "%s/pkg-post-deupgrade", mdir); pkg_addscript(pkg, fpath); /* if www is not given then try to determine it from description */ if (www == NULL) { desc = pkg_get(pkg, PKG_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); } else { pkg_set(pkg, PKG_WWW, www); free(www); } if (strstr(u.release, "RELEASE") == NULL) { asprintf(&v, "%s-%d", u.release, __FreeBSD_version); pkg_set(pkg, PKG_OSVERSION, v); free(v); } else { pkg_set(pkg, PKG_OSVERSION, u.release); } /* TODO: missing osversion get it from uname*/ ret += ports_parse_plist(pkg, plist); if (ret != 0) { pkg_error_warn("can not parse plist file"); return (-1); } if (plist != NULL) free(plist); if (pkgdb_open(&db, PKGDB_DEFAULT, R_OK|W_OK) != EPKG_OK) { pkg_error_warn("can not open database"); return (-1); } if (heuristic) pkg_analyse_files(db, pkg); if (input_path != NULL) { pkg_copy_tree(pkg, input_path, "/"); free(input_path); } if (pkgdb_register_pkg(db, pkg) != EPKG_OK) { pkg_error_warn("can not register package"); retcode = 1; } pkgdb_register_finale(db, ret); if (ret != EPKG_OK) { pkg_error_warn("can not register package"); retcode = 1; } if (pkg_get(pkg, PKG_MESSAGE) != NULL && !legacy) printf("%s\n", pkg_get(pkg, PKG_MESSAGE)); pkgdb_close(db); pkg_free(pkg); return (retcode); }
int exec_register(int argc, char **argv) { struct pkg *pkg = NULL; struct pkgdb *db = NULL; const char *plist = NULL; const char *mdir = NULL; const char *mfile = NULL; const char *input_path = NULL; const char *location = NULL; bool legacy = false; bool testing_mode = false; int ch; int ret = EPKG_OK; int retcode = EX_OK; /* options descriptor */ struct option longopts[] = { { "automatic", no_argument, NULL, 'A' }, { "debug", no_argument, NULL, 'd' }, { "legacy", no_argument, NULL, 'l' }, { "manifest", required_argument, NULL, 'M' }, { "metadata", required_argument, NULL, 'm' }, { "plist", required_argument, NULL, 'f' }, { "relocate", required_argument, NULL, 1 }, { "root", required_argument, NULL, 'i' }, { "test", no_argument, NULL, 't' }, { NULL, 0, NULL, 0}, }; if (pkg_new(&pkg, PKG_INSTALLED) != EPKG_OK) err(EX_OSERR, "malloc"); while ((ch = getopt_long(argc, argv, "+Adf:i:lM:m:t", 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': mfile = optarg; break; case 'm': mdir = optarg; break; case 't': testing_mode = true; break; case 1: location = optarg; break; default: warnx("Unrecognised option -%c\n", ch); usage_register(); pkg_free(pkg); return (EX_USAGE); } } 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"); pkg_free(pkg); return (EX_NOPERM); } else if (retcode != EPKG_OK) { pkg_free(pkg); 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(); pkg_free(pkg); return (EX_USAGE); } if (mfile == NULL && mdir == NULL) { warnx("One of either -m or -M flags is required"); usage_register(); pkg_free(pkg); return (EX_USAGE); } if (testing_mode && input_path != NULL) { warnx("-i incompatible with -t option"); usage_register(); pkg_free(pkg); return (EX_USAGE); } ret = pkg_load_metadata(pkg, mfile, mdir, plist, input_path, testing_mode); if (ret != EPKG_OK) { pkg_free(pkg); return (EX_IOERR); } if (pkgdb_open(&db, PKGDB_DEFAULT) != EPKG_OK) { pkg_free(pkg); return (EX_IOERR); } if (pkgdb_obtain_lock(db, PKGDB_LOCK_EXCLUSIVE) != EPKG_OK) { pkgdb_close(db); pkg_free(pkg); warnx("Cannot get an exclusive lock on a database, it is locked by another process"); return (EX_TEMPFAIL); } retcode = pkg_add_port(db, pkg, input_path, location, testing_mode); if (!legacy && retcode == EPKG_OK && messages != NULL) { printf("%s\n", utstring_body(messages)); } pkg_free(pkg); return (retcode != EPKG_OK ? EX_SOFTWARE : EX_OK); }