int exec_add(int argc, char **argv) { struct pkgdb *db = NULL; struct sbuf *failedpkgs = sbuf_new_auto(); char path[MAXPATHLEN + 1]; char *file; int retcode = EPKG_OK; int i; int failedpkgcount = 0; struct pkg *p = NULL; if (argc < 2) { usage_add(); return (EX_USAGE); } if (geteuid() != 0) { warnx("adding packages can only be done as root"); return (EX_NOPERM); } if (pkgdb_open(&db, PKGDB_DEFAULT) != EPKG_OK) { return (EX_IOERR); } for (i = 1; i < argc; i++) { if (is_url(argv[i]) == EPKG_OK) { snprintf(path, sizeof(path), "./%s", basename(argv[i])); if ((retcode = pkg_fetch_file(argv[i], path)) != EPKG_OK) break; file = path; } else file = argv[i]; pkg_open(&p, file, NULL); if ((retcode = pkg_add(db, file, 0)) != EPKG_OK) { sbuf_cat(failedpkgs, argv[i]); if (i != argc - 1) sbuf_printf(failedpkgs, ", "); failedpkgcount++; } } pkgdb_close(db); if(failedpkgcount > 0) { sbuf_finish(failedpkgs); printf("Failed to install the following %d package(s): %s.\n", failedpkgcount, sbuf_data(failedpkgs)); } sbuf_delete(failedpkgs); return (retcode == EPKG_OK ? EX_OK : EX_SOFTWARE); }
int pkg_repo_fetch(struct pkg *pkg) { char dest[MAXPATHLEN + 1]; char url[MAXPATHLEN + 1]; int fetched = 0; char cksum[SHA256_DIGEST_LENGTH * 2 +1]; char *path = NULL; const char *packagesite = NULL; const char *cachedir = NULL; bool multirepos_enabled = false; int retcode = EPKG_OK; const char *repopath, *repourl, *sum, *name, *version; assert((pkg->type & PKG_REMOTE) == PKG_REMOTE); if (pkg_config_string(PKG_CONFIG_CACHEDIR, &cachedir) != EPKG_OK) return (EPKG_FATAL); pkg_get(pkg, PKG_REPOPATH, &repopath, PKG_REPOURL, &repourl, PKG_CKSUM, &sum, PKG_NAME, &name, PKG_VERSION, &version); snprintf(dest, sizeof(dest), "%s/%s", cachedir, repopath); /* 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 */ if ((path = dirname(dest)) == 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. */ pkg_config_bool(PKG_CONFIG_MULTIREPOS, &multirepos_enabled); if (multirepos_enabled) { packagesite = repourl; } else { pkg_config_string(PKG_CONFIG_REPO, &packagesite); } if (packagesite == NULL || packagesite[0] == '\0') { pkg_emit_error("PACKAGESITE is not defined"); retcode = 1; goto cleanup; } if (packagesite[strlen(packagesite) - 1] == '/') snprintf(url, sizeof(url), "%s%s", packagesite, repopath); else snprintf(url, sizeof(url), "%s/%s", packagesite, repopath); retcode = pkg_fetch_file(url, dest, 0); fetched = 1; if (retcode != EPKG_OK) goto cleanup; checksum: retcode = sha256_file(dest, cksum); if (retcode == EPKG_OK) if (strcmp(cksum, sum)) { if (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_fetch(pkg)); } } cleanup: if (retcode != EPKG_OK) unlink(dest); return (retcode); }
int pkg_repo_fetch(struct pkg *pkg) { char dest[MAXPATHLEN + 1]; char url[MAXPATHLEN + 1]; int fetched = 0; char cksum[SHA256_DIGEST_LENGTH * 2 +1]; char *path = NULL; const char *packagesite = NULL; int retcode = EPKG_OK; assert((pkg->type & PKG_REMOTE) == PKG_REMOTE); if ((packagesite = pkg_config("PACKAGESITE")) == NULL) { pkg_emit_error("pkg_repo_fetch(): %s", "PACKAGESITE is not defined"); return (EPKG_FATAL); } snprintf(dest, sizeof(dest), "%s/%s", pkg_config("PKG_CACHEDIR"), pkg_get(pkg, PKG_REPOPATH)); /* 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 */ if ((path = dirname(dest)) == NULL) { pkg_emit_errno("dirname", dest); retcode = EPKG_FATAL; goto cleanup; } if ((retcode = mkdirs(path)) != 0) goto cleanup; if (packagesite[strlen(packagesite) - 1] == '/') snprintf(url, sizeof(url), "%s%s", packagesite, pkg_get(pkg, PKG_REPOPATH)); else snprintf(url, sizeof(url), "%s/%s", packagesite, pkg_get(pkg, PKG_REPOPATH)); retcode = pkg_fetch_file(url, dest); fetched = 1; if (retcode != EPKG_OK) goto cleanup; checksum: retcode = sha256_file(dest, cksum); if (retcode == EPKG_OK) if (strcmp(cksum, pkg_get(pkg, PKG_CKSUM))) { if (fetched == 1) { pkg_emit_error("%s-%s failed checksum from repository", pkg_get(pkg, PKG_NAME), pkg_get(pkg, PKG_VERSION)); retcode = EPKG_FATAL; } else { pkg_emit_error("cached package %s-%s: checksum mismatch, fetching from remote", pkg_get(pkg, PKG_NAME), pkg_get(pkg, PKG_VERSION)); unlink(dest); return (pkg_repo_fetch(pkg)); } } cleanup: if (retcode != EPKG_OK) unlink(dest); return (retcode); }
static int pkg_repo_binary_try_fetch(struct pkg_repo *repo, struct pkg *pkg, bool already_tried, bool mirror, const char *destdir) { char dest[MAXPATHLEN]; char url[MAXPATHLEN]; char *dir = NULL; bool fetched = false; struct stat st; char *path = NULL; const char *packagesite = NULL; ssize_t offset = -1; int retcode = EPKG_OK; assert((pkg->type & PKG_REMOTE) == PKG_REMOTE); if (mirror) { const char *cachedir; if (destdir != NULL) cachedir = destdir; else cachedir = pkg_object_string(pkg_config_get("PKG_CACHEDIR")); snprintf(dest, sizeof(dest), "%s/%s", cachedir, pkg->repopath); } else pkg_repo_binary_get_cached_name(repo, pkg, dest, sizeof(dest)); /* If it is already in the local cachedir, dont bother to * download it */ if (stat(dest, &st) == 0) { /* try to resume */ if (pkg->pkgsize > st.st_size) { offset = st.st_size; pkg_debug(1, "Resuming fetch"); } else { goto checksum; } } /* Create the dirs in cachedir */ dir = strdup(dest); if (dir == NULL || (path = dirname(dir)) == NULL) { pkg_emit_errno("dirname", dest); retcode = EPKG_FATAL; goto cleanup; } if ((retcode = mkdirs(path)) != EPKG_OK) goto cleanup; /* * In multi-repos the remote URL is stored in pkg[PKG_REPOURL] * For a single attached database the repository URL should be * defined by URL. */ packagesite = pkg_repo_url(repo); if (packagesite == NULL || packagesite[0] == '\0') { pkg_emit_error("URL is not defined"); retcode = 1; goto cleanup; } if (packagesite[strlen(packagesite) - 1] == '/') pkg_snprintf(url, sizeof(url), "%S%R", packagesite, pkg); else pkg_snprintf(url, sizeof(url), "%S/%R", packagesite, pkg); if (!mirror && strncasecmp(packagesite, "file://", 7) == 0) { free(dir); return (EPKG_OK); } retcode = pkg_fetch_file(repo, url, dest, 0, offset, pkg->pkgsize); fetched = true; if (retcode != EPKG_OK) goto cleanup; checksum: /* checksum calculation is expensive, if size does not match, skip it and assume failed checksum. */ if (stat(dest, &st) == -1 || pkg->pkgsize != st.st_size) { if (already_tried) { pkg_emit_error("cached package %s-%s: " "size mismatch, cannot continue", pkg->name, pkg->version); retcode = EPKG_FATAL; goto cleanup; } unlink(dest); free(dir); pkg_emit_error("cached package %s-%s: " "size mismatch, fetching from remote", pkg->name, pkg->version); return (pkg_repo_binary_try_fetch(repo, pkg, true, mirror, destdir)); } if (pkg_checksum_validate_file(dest, pkg->sum) != 0) { if (already_tried || fetched) { pkg_emit_error("%s-%s failed checksum " "from repository", pkg->name, pkg->version); retcode = EPKG_FATAL; } else { pkg_emit_error("cached package %s-%s: " "checksum mismatch, fetching from remote", pkg->name, pkg->version); unlink(dest); return (pkg_repo_binary_try_fetch(repo, pkg, true, mirror, destdir)); } } cleanup: if (retcode != EPKG_OK) unlink(dest); else if (!mirror && path != NULL) { (void)pkg_repo_binary_create_symlink(pkg, dest, path); } /* allowed even if dir is NULL */ free(dir); return (retcode); }
int exec_add(int argc, char **argv) { struct pkgdb *db = NULL; struct sbuf *failedpkgs = NULL; char path[MAXPATHLEN]; char *file; int retcode; int ch; int i; int failedpkgcount = 0; pkg_flags f = PKG_FLAG_NONE; struct pkg_manifest_key *keys = NULL; const char *location = NULL; /* options descriptor */ struct option longopts[] = { { "no-scripts", no_argument, NULL, 'I' }, { "automatic", no_argument, NULL, 'A' }, { "force", no_argument, NULL, 'f' }, { "accept-missing", no_argument, NULL, 'M' }, { "quiet", no_argument, NULL, 'q' }, { "relocate", required_argument, NULL, 1 }, { NULL, 0, NULL, 0 } }; while ((ch = getopt_long(argc, argv, "IAfqM", longopts, NULL)) != -1) { switch (ch) { case 'I': f |= PKG_ADD_NOSCRIPT; break; case 'A': f |= PKG_ADD_AUTOMATIC; break; case 'f': f |= PKG_ADD_FORCE; force = true; break; case 'M': f |= PKG_ADD_FORCE_MISSING; break; case 'q': quiet = true; break; case 1: location = optarg; break; default: usage_add(); return (EX_USAGE); } } argc -= optind; argv += optind; if (argc < 1) { usage_add(); 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 add packages"); return (EX_NOPERM); } else if (retcode != EPKG_OK) return (EX_IOERR); 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); } failedpkgs = sbuf_new_auto(); pkg_manifest_keys_new(&keys); for (i = 0; i < argc; i++) { if (is_url(argv[i]) == EPKG_OK) { snprintf(path, sizeof(path), "%s/%s.XXXXX", getenv("TMPDIR") != NULL ? getenv("TMPDIR") : "/tmp", basename(argv[i])); if ((retcode = pkg_fetch_file(NULL, argv[i], path, 0)) != EPKG_OK) break; file = path; } else { file = argv[i]; /* Special case: treat a filename of "-" as meaning 'read from stdin.' It doesn't make sense to have a filename of "-" more than once per command line, but we aren't testing for that at the moment */ if (strcmp(file, "-") != 0 && access(file, F_OK) != 0) { warn("%s", file); if (errno == ENOENT) warnx("Was 'pkg install %s' meant?", file); sbuf_cat(failedpkgs, argv[i]); if (i != argc - 1) sbuf_printf(failedpkgs, ", "); failedpkgcount++; continue; } } if ((retcode = pkg_add(db, file, f, keys, location)) != EPKG_OK) { sbuf_cat(failedpkgs, argv[i]); if (i != argc - 1) sbuf_printf(failedpkgs, ", "); failedpkgcount++; } if (is_url(argv[i]) == EPKG_OK) unlink(file); } pkg_manifest_keys_free(keys); pkgdb_release_lock(db, PKGDB_LOCK_EXCLUSIVE); pkgdb_close(db); if(failedpkgcount > 0) { sbuf_finish(failedpkgs); printf("\nFailed to install the following %d package(s): %s\n", failedpkgcount, sbuf_data(failedpkgs)); retcode = EPKG_FATAL; } sbuf_delete(failedpkgs); if (messages != NULL) { sbuf_finish(messages); printf("%s", sbuf_data(messages)); } return (retcode == EPKG_OK ? EX_OK : EX_SOFTWARE); }
static int update_from_remote_repo(const char *name, const char *url) { struct archive *a = NULL; struct archive_entry *ae = NULL; char repofile[MAXPATHLEN]; char repofile_unchecked[MAXPATHLEN]; char tmp[21]; const char *dbdir = NULL; unsigned char *sig = NULL; int siglen = 0; int rc = EPKG_OK; (void)strlcpy(tmp, "/tmp/repo.txz.XXXXXX", sizeof(tmp)); if (mktemp(tmp) == NULL) { warnx("Could not create temporary file %s, aborting update.\n", tmp); return (EPKG_FATAL); } if (pkg_config_string(PKG_CONFIG_DBDIR, &dbdir) != EPKG_OK) { warnx("Cant get dbdir config entry"); return (EPKG_FATAL); } if (pkg_fetch_file(url, tmp) != EPKG_OK) { /* * No need to unlink(tmp) here as it is already * done in pkg_fetch_file() in case fetch failed. */ return (EPKG_FATAL); } a = archive_read_new(); archive_read_support_compression_all(a); archive_read_support_format_tar(a); archive_read_open_filename(a, tmp, 4096); while (archive_read_next_header(a, &ae) == ARCHIVE_OK) { if (strcmp(archive_entry_pathname(ae), "repo.sqlite") == 0) { snprintf(repofile, sizeof(repofile), "%s/%s.sqlite", dbdir, name); snprintf(repofile_unchecked, sizeof(repofile_unchecked), "%s.unchecked", repofile); archive_entry_set_pathname(ae, repofile_unchecked); archive_read_extract(a, ae, EXTRACT_ARCHIVE_FLAGS); } if (strcmp(archive_entry_pathname(ae), "signature") == 0) { siglen = archive_entry_size(ae); sig = malloc(siglen); archive_read_data(a, sig, siglen); } } if (sig != NULL) { if (pkg_repo_verify(repofile_unchecked, sig, siglen - 1) != EPKG_OK) { warnx("Invalid signature, removing repository.\n"); unlink(repofile_unchecked); free(sig); rc = EPKG_FATAL; goto cleanup; } } rename(repofile_unchecked, repofile); cleanup: if (a != NULL) archive_read_finish(a); (void)unlink(tmp); return (rc); }
int exec_add(int argc, char **argv) { struct pkgdb *db = NULL; struct sbuf *failedpkgs = NULL; char path[MAXPATHLEN + 1]; char *file; int retcode; int ch; int i; int failedpkgcount = 0; pkg_flags f = PKG_FLAG_NONE; struct pkg_manifest_key *keys = NULL; while ((ch = getopt(argc, argv, "IAfq")) != -1) { switch (ch) { case 'I': f |= PKG_ADD_NOSCRIPT; break; case 'A': f |= PKG_FLAG_AUTOMATIC; break; case 'f': f |= PKG_FLAG_FORCE; break; case 'q': quiet = true; break; default: usage_add(); return (EX_USAGE); } } argc -= optind; argv += optind; if (argc < 1) { usage_add(); return (EX_USAGE); } retcode = pkgdb_access(PKGDB_MODE_READ | PKGDB_MODE_WRITE | PKGDB_MODE_CREATE, PKGDB_DB_LOCAL); if (retcode == EPKG_ENOACCESS) { warnx("Insufficient privilege to add packages"); return (EX_NOPERM); } else if (retcode != EPKG_OK) return (EX_IOERR); if (pkgdb_open(&db, PKGDB_DEFAULT) != EPKG_OK) return (EX_IOERR); failedpkgs = sbuf_new_auto(); pkg_manifest_keys_new(&keys); for (i = 0; i < argc; i++) { if (is_url(argv[i]) == EPKG_OK) { snprintf(path, sizeof(path), "./%s", basename(argv[i])); if ((retcode = pkg_fetch_file(NULL, argv[i], path, 0)) != EPKG_OK) break; file = path; } else { file = argv[i]; if (access(file, F_OK) != 0) { warn("%s",file); if (errno == ENOENT) warnx("Did you mean 'pkg install %s'?", file); sbuf_cat(failedpkgs, argv[i]); if (i != argc - 1) sbuf_printf(failedpkgs, ", "); failedpkgcount++; continue; } } if ((retcode = pkg_add(db, file, f, keys)) != EPKG_OK) { sbuf_cat(failedpkgs, argv[i]); if (i != argc - 1) sbuf_printf(failedpkgs, ", "); failedpkgcount++; } } pkg_manifest_keys_free(keys); pkgdb_close(db); if(failedpkgcount > 0) { sbuf_finish(failedpkgs); printf("\nFailed to install the following %d package(s): %s\n", failedpkgcount, sbuf_data(failedpkgs)); retcode = EPKG_FATAL; } sbuf_delete(failedpkgs); if (messages != NULL) { sbuf_finish(messages); printf("%s", sbuf_data(messages)); } return (retcode == EPKG_OK ? EX_OK : EX_SOFTWARE); }
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); }