/** * Fetch repository calalogues. */ int pkgcli_update(bool force) { const char *packagesite = NULL; const char *repo_name; bool multi_repos = false; struct pkg_config_kv *repokv = NULL; int retcode = EPKG_FATAL; char name[MAXPATHLEN]; if (!quiet) printf("Updating repository catalogue\n"); pkg_config_bool(PKG_CONFIG_MULTIREPOS, &multi_repos); /* single repository */ if (!multi_repos) { /* * Single remote database */ pkg_config_string(PKG_CONFIG_REPO, &packagesite); if (packagesite == NULL) { warnx("PACKAGESITE is not defined."); return (1); } retcode = pkg_update("repo", packagesite, force); if (retcode == EPKG_UPTODATE) { if (!quiet) printf("Repository catalogue is up-to-date, " "no need to fetch fresh copy\n"); retcode = EPKG_OK; } } else { /* multiple repositories */ while (pkg_config_kvlist(PKG_CONFIG_REPOS, &repokv) == EPKG_OK) { repo_name = pkg_config_kv_get(repokv, PKG_CONFIG_KV_KEY); packagesite = pkg_config_kv_get(repokv, PKG_CONFIG_KV_VALUE); snprintf(name, MAXPATHLEN, "repo-%s", repo_name); retcode = pkg_update(name, packagesite, force); if (retcode == EPKG_UPTODATE) { if (!quiet) printf("%s repository catalogue is " "up-to-date, no need to fetch " "fresh copy\n", repo_name); retcode = EPKG_OK; } if (retcode != EPKG_OK) break; } } return (retcode); }
int pkg_update(const char *name, const char *packagesite, bool force) { char url[MAXPATHLEN]; struct archive *a = NULL; struct archive_entry *ae = NULL; char repofile[MAXPATHLEN]; char repofile_unchecked[MAXPATHLEN]; char tmp[MAXPATHLEN]; const char *dbdir = NULL; const char *repokey; unsigned char *sig = NULL; int siglen = 0; int fd, rc = EPKG_FATAL, ret; struct stat st; time_t t = 0; sqlite3 *sqlite; char *archreq = NULL; const char *myarch; int64_t res; const char *tmpdir; snprintf(url, MAXPATHLEN, "%s/repo.txz", packagesite); tmpdir = getenv("TMPDIR"); if (tmpdir == NULL) tmpdir = "/tmp"; strlcpy(tmp, tmpdir, sizeof(tmp)); strlcat(tmp, "/repo.txz.XXXXXX", sizeof(tmp)); fd = mkstemp(tmp); if (fd == -1) { pkg_emit_error("Could not create temporary file %s, " "aborting update.\n", tmp); return (EPKG_FATAL); } if (pkg_config_string(PKG_CONFIG_DBDIR, &dbdir) != EPKG_OK) { pkg_emit_error("Cant get dbdir config entry"); return (EPKG_FATAL); } snprintf(repofile, sizeof(repofile), "%s/%s.sqlite", dbdir, name); if (force) t = 0; /* Always fetch */ else { if (stat(repofile, &st) != -1) { t = st.st_mtime; /* add 1 minute to the timestamp because * repo.sqlite is always newer than repo.txz, * 1 minute should be enough. */ t += 60; } } rc = pkg_fetch_file_to_fd(url, fd, t); close(fd); if (rc != EPKG_OK) { goto cleanup; } if (eaccess(repofile, W_OK) == -1) { pkg_emit_error("Insufficient privilege to update %s\n", repofile); rc = EPKG_ENOACCESS; goto cleanup; } 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_unchecked, sizeof(repofile_unchecked), "%s.unchecked", repofile); archive_entry_set_pathname(ae, repofile_unchecked); /* * The repo should be owned by root and not writable */ archive_entry_set_uid(ae, 0); archive_entry_set_gid(ae, 0); archive_entry_set_perm(ae, 0644); 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 (pkg_config_string(PKG_CONFIG_REPOKEY, &repokey) != EPKG_OK) { free(sig); return (EPKG_FATAL); } if (repokey != NULL) { if (sig != NULL) { ret = rsa_verify(repofile_unchecked, repokey, sig, siglen - 1); if (ret != EPKG_OK) { pkg_emit_error("Invalid signature, " "removing repository.\n"); unlink(repofile_unchecked); free(sig); rc = EPKG_FATAL; goto cleanup; } free(sig); } else { pkg_emit_error("No signature found in the repository. " "Can not validate against %s key.", repokey); rc = EPKG_FATAL; unlink(repofile_unchecked); goto cleanup; } } /* check is the repository is for valid architecture */ sqlite3_initialize(); if (sqlite3_open(repofile_unchecked, &sqlite) != SQLITE_OK) { unlink(repofile_unchecked); pkg_emit_error("Corrupted repository"); rc = EPKG_FATAL; goto cleanup; } pkg_config_string(PKG_CONFIG_ABI, &myarch); archreq = sqlite3_mprintf("select count(arch) from packages " "where arch not GLOB '%q'", myarch); if (get_pragma(sqlite, archreq, &res) != EPKG_OK) { sqlite3_free(archreq); pkg_emit_error("Unable to query repository"); rc = EPKG_FATAL; sqlite3_close(sqlite); goto cleanup; } if (res > 0) { pkg_emit_error("At least one of the packages provided by" "the repository is not compatible with your abi: %s", myarch); rc = EPKG_FATAL; sqlite3_close(sqlite); goto cleanup; } sqlite3_close(sqlite); sqlite3_shutdown(); if (rename(repofile_unchecked, repofile) != 0) { pkg_emit_errno("rename", ""); rc = EPKG_FATAL; goto cleanup; } if ((rc = remote_add_indexes(name)) != EPKG_OK) goto cleanup; rc = EPKG_OK; cleanup: if (a != NULL) archive_read_finish(a); (void)unlink(tmp); return (rc); }
void print_jobs_summary(struct pkg_jobs *jobs, const char *msg, ...) { struct pkg *pkg = NULL; char path[MAXPATHLEN]; struct stat st; const char *oldversion, *cachedir, *why; int64_t dlsize, oldsize, newsize; int64_t flatsize, oldflatsize, pkgsize; char size[7]; va_list ap; pkg_jobs_t type; type = pkg_jobs_type(jobs); va_start(ap, msg); vprintf(msg, ap); va_end(ap); dlsize = oldsize = newsize = 0; flatsize = oldflatsize = pkgsize = 0; oldversion = NULL; pkg_config_string(PKG_CONFIG_CACHEDIR, &cachedir); while (pkg_jobs(jobs, &pkg) == EPKG_OK) { pkg_get(pkg, PKG_OLD_VERSION, &oldversion, PKG_FLATSIZE, &flatsize, PKG_OLD_FLATSIZE, &oldflatsize, PKG_PKGSIZE, &pkgsize, PKG_REASON, &why); if (pkg_is_locked(pkg)) { pkg_printf("\tPackage %n-%v is locked ", pkg, pkg); switch (type) { case PKG_JOBS_INSTALL: case PKG_JOBS_UPGRADE: /* If it's a new install, then it * cannot have been locked yet. */ if (oldversion != NULL) { switch(pkg_version_change(pkg)) { case PKG_UPGRADE: pkg_printf("and may not be upgraded to version %v\n", pkg); break; case PKG_REINSTALL: printf("and may not be reinstalled\n"); break; case PKG_DOWNGRADE: pkg_printf("and may not be downgraded to version %v\n", pkg); break; } continue; } break; case PKG_JOBS_DEINSTALL: case PKG_JOBS_AUTOREMOVE: printf("and may not be deinstalled\n"); continue; break; case PKG_JOBS_FETCH: printf("but a new package can still be fetched\n"); break; } } switch (type) { case PKG_JOBS_INSTALL: case PKG_JOBS_UPGRADE: pkg_snprintf(path, MAXPATHLEN, "%S/%R", cachedir, pkg); if (stat(path, &st) == -1 || pkgsize != st.st_size) /* file looks corrupted (wrong size), assume a checksum mismatch will occur later and the file will be fetched from remote again */ dlsize += pkgsize; if (oldversion != NULL) { switch (pkg_version_change(pkg)) { case PKG_DOWNGRADE: pkg_printf("\tDowngrading %n: %V -> %v", pkg, pkg, pkg); if (pkg_repos_count() > 1) pkg_printf(" [%N]", pkg); printf("\n"); break; case PKG_REINSTALL: pkg_printf("\tReinstalling %n-%v", pkg, pkg); if (pkg_repos_count() > 1) pkg_printf(" [%N]", pkg); if (why != NULL) printf(" (%s)", why); printf("\n"); break; case PKG_UPGRADE: pkg_printf("\tUpgrading %n: %V -> %v", pkg, pkg, pkg); if (pkg_repos_count() > 1) pkg_printf(" [%N]", pkg); printf("\n"); break; } oldsize += oldflatsize; newsize += flatsize; } else { newsize += flatsize; pkg_printf("\tInstalling %n: %v", pkg, pkg); if (pkg_repos_count() > 1) pkg_printf(" [%N]", pkg); printf("\n"); } break; case PKG_JOBS_DEINSTALL: case PKG_JOBS_AUTOREMOVE: oldsize += oldflatsize; newsize += flatsize; pkg_printf("\t%n-%v\n", pkg, pkg); break; case PKG_JOBS_FETCH: dlsize += pkgsize; pkg_snprintf(path, MAXPATHLEN, "%S/%R", cachedir, pkg); if (stat(path, &st) != -1) oldsize = st.st_size; else oldsize = 0; dlsize -= oldsize; humanize_number(size, sizeof(size), pkgsize, "B", HN_AUTOSCALE, 0); pkg_printf("\t%n-%v ", pkg, pkg); printf("(%" PRId64 "%% of %s)\n", 100 - (100 * oldsize)/pkgsize, size); break; } } if (oldsize > newsize) { humanize_number(size, sizeof(size), oldsize - newsize, "B", HN_AUTOSCALE, 0); switch (type) { case PKG_JOBS_INSTALL: printf("\nThe installation will free %s\n", size); break; case PKG_JOBS_UPGRADE: printf("\nThe upgrade will free %s\n", size); break; case PKG_JOBS_DEINSTALL: case PKG_JOBS_AUTOREMOVE: printf("\nThe deinstallation will free %s\n", size); break; case PKG_JOBS_FETCH: /* nothing to report here */ break; } } else if (newsize > oldsize) { humanize_number(size, sizeof(size), newsize - oldsize, "B", HN_AUTOSCALE, 0); switch (type) { case PKG_JOBS_INSTALL: printf("\nThe installation will require %s more space\n", size); break; case PKG_JOBS_UPGRADE: printf("\nThe upgrade will require %s more space\n", size); break; case PKG_JOBS_DEINSTALL: case PKG_JOBS_AUTOREMOVE: printf("\nThe deinstallation will require %s more space\n", size); break; case PKG_JOBS_FETCH: /* nothing to report here */ break; } } if ((type == PKG_JOBS_INSTALL) || (type == PKG_JOBS_FETCH) || (type == PKG_JOBS_UPGRADE)) { humanize_number(size, sizeof(size), dlsize, "B", HN_AUTOSCALE, 0); printf("\n%s to be downloaded\n", size); } }
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_sshserve(void) { struct stat st; char *line = NULL; char *file, *age; size_t linecap = 0, r; ssize_t linelen; time_t mtime = 0; const char *errstr; FILE *f; char buf[BUFSIZ]; char fpath[MAXPATHLEN]; const char *restricted = NULL; pkg_config_string(PKG_CONFIG_SSH_RESTRICT_DIR, &restricted); printf("ok: pkg "PKGVERSION"\n"); for (;;) { if ((linelen = getline(&line, &linecap, stdin)) <= 0) continue; /* trim cr */ if (line[linelen - 1] == '\n') line[linelen - 1] = '\0'; if (strcmp(line, "quit") == 0) return (EPKG_OK); if (strncmp(line, "get ", 4) != 0) { printf("ko: unknown command '%s'\n", line); continue; } file = line + 4; age = file; while (!isspace(*age)) { if (*age == '\0') { age = NULL; break; } age++; } if (age == NULL) { printf("ko: bad command get, expecting 'get file age'\n"); continue; } *age = '\0'; age++; while (isspace(*age)) { if (*age == '\0') { age = NULL; break; } age++; } if (age == NULL) { printf("ko: bad command get, expecting 'get file age'\n"); continue; } mtime = strtonum(age, 0, LONG_MAX, &errstr); if (errstr) { printf("ko: bad number %s: %s\n", age, errstr); continue; } if (restricted != NULL) { file = realpath(file, fpath); if (strncmp(file, restricted, strlen(restricted)) != 0) { printf("ko: file not found\n"); continue; } } if (stat(file, &st) == -1) { printf("ko: file not found\n"); continue; } if (!S_ISREG(st.st_mode)) { printf("ko: not a file\n"); continue; } if (st.st_mtime <= mtime) { printf("ok: 0\n"); continue; } printf("ok: %" PRIdMAX "\n", (intmax_t)st.st_size); f = fopen(file, "r"); while ((r = fread(buf, 1, sizeof(buf), f)) > 0) fwrite(buf, 1, r, stdout); fclose(f); } free(line); return (EPKG_OK); }
int pkg_update(struct pkg_repo *repo, bool force) { char repofile[MAXPATHLEN]; const char *dbdir = NULL; struct stat st; time_t t = 0; sqlite3 *sqlite = NULL; char *req = NULL; int64_t res; sqlite3_initialize(); if (pkg_config_string(PKG_CONFIG_DBDIR, &dbdir) != EPKG_OK) { pkg_emit_error("Cant get dbdir config entry"); return (EPKG_FATAL); } snprintf(repofile, sizeof(repofile), "%s/%s.sqlite", dbdir, pkg_repo_name(repo)); if (stat(repofile, &st) != -1) t = force ? 0 : st.st_mtime; if (t != 0) { if (sqlite3_open(repofile, &sqlite) != SQLITE_OK) { pkg_emit_error("Unable to open local database"); return (EPKG_FATAL); } if (get_pragma(sqlite, "SELECT count(name) FROM sqlite_master " "WHERE type='table' AND name='repodata';", &res) != EPKG_OK) { pkg_emit_error("Unable to query repository"); sqlite3_close(sqlite); return (EPKG_FATAL); } if (res != 1) { t = 0; if (sqlite != NULL) { sqlite3_close(sqlite); sqlite = NULL; } } } if (t != 0) { req = sqlite3_mprintf("select count(key) from repodata " "WHERE key = \"packagesite\" and value = '%q'", pkg_repo_url(repo)); if (get_pragma(sqlite, req, &res) != EPKG_OK) { sqlite3_free(req); pkg_emit_error("Unable to query repository"); sqlite3_close(sqlite); return (EPKG_FATAL); } sqlite3_free(req); if (res != 1) { t = 0; if (sqlite != NULL) { sqlite3_close(sqlite); sqlite = NULL; } unlink(repofile); } } res = pkg_update_incremental(repofile, repo, &t); if (res != EPKG_OK && res != EPKG_UPTODATE) { pkg_emit_notice("No digest falling back on legacy catalog format"); /* Still try to do full upgrade */ if ((res = pkg_update_full(repofile, repo, &t)) != EPKG_OK) goto cleanup; } res = EPKG_OK; cleanup: /* Set mtime from http request if possible */ if (t != 0) { struct timeval ftimes[2] = { { .tv_sec = t, .tv_usec = 0 }, { .tv_sec = t, .tv_usec = 0 } };
static int pkg_update_incremental(const char *name, struct pkg_repo *repo, time_t *mtime) { FILE *fmanifest = NULL, *fdigests = NULL; sqlite3 *sqlite = NULL; struct pkg *pkg = NULL; int rc = EPKG_FATAL; const char *origin, *digest, *offset; struct pkgdb_it *it = NULL; char *linebuf = NULL, *p; int updated = 0, removed = 0, added = 0, processed = 0; long num_offset; time_t local_t = *mtime; struct pkg_increment_task_item *ldel = NULL, *ladd = NULL, *item, *tmp_item; const char *myarch; struct pkg_manifest_parser *parser = NULL; size_t linecap = 0; ssize_t linelen; char *map = MAP_FAILED; size_t len = 0; pkg_debug(1, "Pkgrepo, begin incremental update of '%s'", name); if ((rc = pkgdb_repo_open(name, false, &sqlite, false)) != EPKG_OK) { return (EPKG_FATAL); } if ((rc = pkgdb_repo_init(sqlite, false)) != EPKG_OK) goto cleanup; if ((rc = pkg_register_repo(repo, sqlite)) != EPKG_OK) goto cleanup; it = pkgdb_repo_origins(sqlite); if (it == NULL) { rc = EPKG_FATAL; goto cleanup; } while (pkgdb_it_next(it, &pkg, PKG_LOAD_BASIC) == EPKG_OK) { pkg_get(pkg, PKG_ORIGIN, &origin, PKG_DIGEST, &digest); pkg_update_increment_item_new(&ldel, origin, digest, 4); } fdigests = repo_fetch_remote_extract_tmp(repo, repo_digests_archive, "txz", &local_t, &rc, repo_digests_file); if (fdigests == NULL) goto cleanup; local_t = *mtime; fmanifest = repo_fetch_remote_extract_tmp(repo, repo_packagesite_archive, "txz", &local_t, &rc, repo_packagesite_file); if (fmanifest == NULL) goto cleanup; *mtime = local_t; fseek(fmanifest, 0, SEEK_END); len = ftell(fmanifest); pkg_debug(1, "Pkgrepo, reading new packagesite.yaml for '%s'", name); /* load the while digests */ while ((linelen = getline(&linebuf, &linecap, fdigests)) > 0) { p = linebuf; origin = strsep(&p, ":"); digest = strsep(&p, ":"); offset = strsep(&p, ":"); if (origin == NULL || digest == NULL || offset == NULL) { pkg_emit_error("invalid digest file format"); assert(0); rc = EPKG_FATAL; goto cleanup; } errno = 0; num_offset = (long)strtoul(offset, NULL, 10); if (errno != 0) { pkg_emit_errno("strtoul", "digest format error"); rc = EPKG_FATAL; goto cleanup; } processed++; HASH_FIND_STR(ldel, __DECONST(char *, origin), item); if (item == NULL) { added++; pkg_update_increment_item_new(&ladd, origin, digest, num_offset); } else { if (strcmp(digest, item->digest) == 0) { free(item->origin); free(item->digest); HASH_DEL(ldel, item); free(item); item = NULL; } else { free(item->origin); free(item->digest); HASH_DEL(ldel, item); free(item); item = NULL; pkg_update_increment_item_new(&ladd, origin, digest, num_offset); updated++; } } } rc = EPKG_OK; pkg_debug(1, "Pkgrepo, removing old entries for '%s'", name); removed = HASH_COUNT(ldel) - updated; HASH_ITER(hh, ldel, item, tmp_item) { if (rc == EPKG_OK) { rc = pkgdb_repo_remove_package(item->origin); } free(item->origin); free(item->digest); HASH_DEL(ldel, item); free(item); } pkg_config_string(PKG_CONFIG_ABI, &myarch); pkg_debug(1, "Pkgrepo, pushing new entries for '%s'", name); pkg = NULL; if (len > 0 && len < SSIZE_MAX) { map = mmap(NULL, len, PROT_READ, MAP_SHARED, fileno(fmanifest), 0); fclose(fmanifest); } HASH_ITER(hh, ladd, item, tmp_item) { if (rc == EPKG_OK) { if (map != MAP_FAILED) { rc = pkg_add_from_manifest(NULL, map + item->offset, item->origin, len - item->offset, item->digest, myarch, sqlite, &parser, &pkg); } else { rc = pkg_add_from_manifest(fmanifest, NULL, item->origin, item->offset, item->digest, myarch, sqlite, &parser, &pkg); } } free(item->origin); free(item->digest); HASH_DEL(ladd, item); free(item); } pkg_manifest_parser_free(parser); pkg_emit_incremental_update(updated, removed, added, processed); cleanup: if (pkg != NULL) pkg_free(pkg); if (it != NULL) pkgdb_it_free(it); if (pkgdb_repo_close(sqlite, rc == EPKG_OK) != EPKG_OK) rc = EPKG_FATAL; if (map == MAP_FAILED && fmanifest) fclose(fmanifest); if (fdigests) fclose(fdigests); if (map != MAP_FAILED) munmap(map, len); return (rc); }
static void print_jobs_summary_pkg(struct pkg *pkg, pkg_jobs_t type, int64_t *oldsize, int64_t *newsize, int64_t *dlsize) { const char *oldversion, *cachedir, *why; char path[MAXPATHLEN]; struct stat st; int64_t flatsize, oldflatsize, pkgsize; char size[7]; flatsize = oldflatsize = pkgsize = 0; oldversion = NULL; pkg_config_string(PKG_CONFIG_CACHEDIR, &cachedir); pkg_get(pkg, PKG_OLD_VERSION, &oldversion, PKG_FLATSIZE, &flatsize, PKG_OLD_FLATSIZE, &oldflatsize, PKG_PKGSIZE, &pkgsize, PKG_REASON, &why); if (pkg_is_locked(pkg)) { pkg_printf("\tPackage %n-%v is locked ", pkg, pkg); switch (type) { case PKG_JOBS_INSTALL: case PKG_JOBS_UPGRADE: /* If it's a new install, then it * cannot have been locked yet. */ if (oldversion != NULL) { switch(pkg_version_change(pkg)) { case PKG_UPGRADE: pkg_printf("and may not be upgraded to version %v\n", pkg); break; case PKG_REINSTALL: printf("and may not be reinstalled\n"); break; case PKG_DOWNGRADE: pkg_printf("and may not be downgraded to version %v\n", pkg); break; } return; } break; case PKG_JOBS_DEINSTALL: case PKG_JOBS_AUTOREMOVE: printf("and may not be deinstalled\n"); return; break; case PKG_JOBS_FETCH: printf("but a new package can still be fetched\n"); break; } } switch (type) { case PKG_JOBS_INSTALL: case PKG_JOBS_UPGRADE: pkg_snprintf(path, MAXPATHLEN, "%S/%R", cachedir, pkg); if (stat(path, &st) == -1 || pkgsize != st.st_size) /* file looks corrupted (wrong size), assume a checksum mismatch will occur later and the file will be fetched from remote again */ *dlsize += pkgsize; if (oldversion != NULL) { switch (pkg_version_change(pkg)) { case PKG_DOWNGRADE: pkg_printf("\tDowngrading %n: %V -> %v", pkg, pkg, pkg); if (pkg_repos_total_count() > 1) pkg_printf(" [%N]", pkg); printf("\n"); break; case PKG_REINSTALL: pkg_printf("\tReinstalling %n-%v", pkg, pkg); if (pkg_repos_total_count() > 1) pkg_printf(" [%N]", pkg); if (why != NULL) printf(" (%s)", why); printf("\n"); break; case PKG_UPGRADE: pkg_printf("\tUpgrading %n: %V -> %v", pkg, pkg, pkg); if (pkg_repos_total_count() > 1) pkg_printf(" [%N]", pkg); printf("\n"); break; } *oldsize += oldflatsize; *newsize += flatsize; } else { *newsize += flatsize; pkg_printf("\tInstalling %n: %v", pkg, pkg); if (pkg_repos_total_count() > 1) pkg_printf(" [%N]", pkg); printf("\n"); } break; case PKG_JOBS_DEINSTALL: case PKG_JOBS_AUTOREMOVE: *oldsize += oldflatsize; *newsize += flatsize; pkg_printf("\tRemoving %n-%v\n", pkg, pkg); break; case PKG_JOBS_FETCH: *dlsize += pkgsize; pkg_snprintf(path, MAXPATHLEN, "%S/%R", cachedir, pkg); if (stat(path, &st) != -1) *oldsize = st.st_size; else *oldsize = 0; *dlsize -= *oldsize; humanize_number(size, sizeof(size), pkgsize, "B", HN_AUTOSCALE, 0); pkg_printf("\t%n-%v ", pkg, pkg); printf("(%" PRId64 "%% of %s)\n", 100 - (100 * (*oldsize))/pkgsize, size); break; } }
int pkg_fetch_file_to_fd(const char *url, int dest, time_t t) { FILE *remote = NULL; struct url *u; struct url_stat st; off_t done = 0; off_t r; int64_t max_retry, retry; time_t begin_dl; time_t now; time_t last = 0; char buf[10240]; char *doc; char docpath[MAXPATHLEN]; int retcode = EPKG_OK; bool srv = false; bool http = false; char zone[MAXHOSTNAMELEN + 13]; struct dns_srvinfo *srv_current = NULL; struct http_mirror *http_current = NULL; const char *mt; fetchTimeout = 30; if (pkg_config_int64(PKG_CONFIG_FETCH_RETRY, &max_retry) == EPKG_FATAL) max_retry = 3; retry = max_retry; u = fetchParseURL(url); doc = u->doc; while (remote == NULL) { if (retry == max_retry) { pkg_config_string(PKG_CONFIG_MIRRORS, &mt); if (mt != NULL && strncasecmp(mt, "srv", 3) == 0 && \ strcmp(u->scheme, "file") != 0) { srv = true; snprintf(zone, sizeof(zone), "_%s._tcp.%s", u->scheme, u->host); pthread_mutex_lock(&mirror_mtx); if (srv_mirrors != NULL) srv_mirrors = dns_getsrvinfo(zone); pthread_mutex_unlock(&mirror_mtx); srv_current = srv_mirrors; } else if (mt != NULL && strncasecmp(mt, "http", 4) == 0 && \ strcmp(u->scheme, "file") != 0 && \ strcmp(u->scheme, "ftp") != 0) { http = true; snprintf(zone, sizeof(zone), "%s://%s", u->scheme, u->host); pthread_mutex_lock(&mirror_mtx); if (STAILQ_EMPTY(&http_mirrors)) gethttpmirrors(zone); pthread_mutex_unlock(&mirror_mtx); http_current = STAILQ_FIRST(&http_mirrors); } } if (srv && srv_mirrors != NULL) strlcpy(u->host, srv_current->host, sizeof(u->host)); else if (http && !STAILQ_EMPTY(&http_mirrors)) { strlcpy(u->scheme, http_current->url->scheme, sizeof(u->scheme)); strlcpy(u->host, http_current->url->host, sizeof(u->host)); snprintf(docpath, MAXPATHLEN, "%s%s", http_current->url->doc, doc); u->doc = docpath; u->port = http_current->url->port; } remote = fetchXGet(u, &st, ""); if (remote == NULL) { --retry; if (retry <= 0) { pkg_emit_error("%s: %s", url, fetchLastErrString); retcode = EPKG_FATAL; goto cleanup; } if (srv && srv_mirrors != NULL) { srv_current = srv_current->next; if (srv_current == NULL) srv_current = srv_mirrors; } else if (http && !STAILQ_EMPTY(&http_mirrors)) { http_current = STAILQ_NEXT(http_current, next); if (http_current == NULL) http_current = STAILQ_FIRST(&http_mirrors); } else { sleep(1); } } } if (t != 0) { if (st.mtime <= t) { retcode = EPKG_UPTODATE; goto cleanup; } } begin_dl = time(NULL); while (done < st.size) { if ((r = fread(buf, 1, sizeof(buf), remote)) < 1) break; if (write(dest, buf, r) != r) { pkg_emit_errno("write", ""); retcode = EPKG_FATAL; goto cleanup; } done += r; now = time(NULL); /* Only call the callback every second */ if (now > last || done == st.size) { pkg_emit_fetching(url, st.size, done, (now - begin_dl)); last = now; } } if (ferror(remote)) { pkg_emit_error("%s: %s", url, fetchLastErrString); retcode = EPKG_FATAL; goto cleanup; } cleanup: if (remote != NULL) fclose(remote); /* restore original doc */ u->doc = doc; fetchFreeURL(u); return (retcode); }
int exec_clean(int argc, char **argv) { struct pkgdb *db = NULL; struct pkgdb_it *it = NULL; struct pkg *pkg = NULL; struct pkg *p = NULL; FTS *fts = NULL; FTSENT *ent = NULL; struct dl_head dl = STAILQ_HEAD_INITIALIZER(dl); const char *cachedir; char *paths[2]; char *repopath; bool dry_run = false; bool yes; int retcode = EX_SOFTWARE; int ret; int ch; pkg_config_bool(PKG_CONFIG_ASSUME_ALWAYS_YES, &yes); while ((ch = getopt(argc, argv, "nqy")) != -1) { switch (ch) { case 'n': dry_run = true; break; case 'q': quiet = true; break; case 'y': yes = true; break; default: usage_clean(); return (EX_USAGE); } } argc -= optind; argv += optind; if (pkg_config_string(PKG_CONFIG_CACHEDIR, &cachedir) != EPKG_OK) { warnx("Cannot get cachedir config entry"); return 1; } paths[0] = __DECONST(char*, cachedir); paths[1] = NULL; if (pkgdb_open(&db, PKGDB_REMOTE) != EPKG_OK) { goto cleanup; } if ((fts = fts_open(paths, FTS_PHYSICAL, NULL)) == NULL) { warn("fts_open(%s)", cachedir); goto cleanup; } /* Build the list of out-of-date or obsolete packages */ while ((ent = fts_read(fts)) != NULL) { const char *origin, *pkgrepopath; if (ent->fts_info != FTS_F) continue; repopath = ent->fts_path + strlen(cachedir); if (repopath[0] == '/') repopath++; if (pkg_open(&pkg, ent->fts_path) != EPKG_OK) { if (!quiet) warnx("skipping %s", ent->fts_path); continue; } pkg_get(pkg, PKG_ORIGIN, &origin); it = pkgdb_search(db, origin, MATCH_EXACT, FIELD_ORIGIN, FIELD_NONE, NULL); if (it == NULL) { if (!quiet) warnx("skipping %s", ent->fts_path); continue; } if ((ret = pkgdb_it_next(it, &p, PKG_LOAD_BASIC)) == EPKG_FATAL) { if (!quiet) warnx("skipping %s", ent->fts_path); continue; } pkg_get(p, PKG_REPOPATH, &pkgrepopath); if (ret == EPKG_END) { ret = add_to_dellist(&dl, REMOVED, ent->fts_path, origin, NULL, NULL); } else if (strcmp(repopath, pkgrepopath)) { const char *newname; const char *newversion; pkg_get(p, PKG_NAME, &newname, PKG_VERSION, &newversion); ret = add_to_dellist(&dl, OUT_OF_DATE, ent->fts_path, origin, newname, newversion); } else { char local_cksum[SHA256_DIGEST_LENGTH * 2 +1]; const char *cksum; pkg_get(p, PKG_CKSUM, &cksum); if (hash_file(ent->fts_path, local_cksum) == EPKG_OK) { if (strcmp(cksum, local_cksum) != 0) { ret = add_to_dellist(&dl, CKSUM_MISMATCH, ent->fts_path, origin, NULL, NULL); } } } if (ret != EPKG_OK && ret != EPKG_END) { retcode = EX_OSERR; /* out of memory */ goto cleanup; } pkgdb_it_free(it); } if (STAILQ_EMPTY(&dl)) { if (!quiet) printf("Nothing to do.\n"); retcode = EX_OK; goto cleanup; } if (dry_run || !yes || !quiet) display_dellist(&dl, cachedir); if (!dry_run) { if (!yes) yes = query_yesno( "\nProceed with cleaning cache [y/N]: "); if (yes) retcode = delete_dellist(&dl); } else retcode = EX_OK; cleanup: free_dellist(&dl); pkg_free(pkg); pkg_free(p); if (fts != NULL) fts_close(fts); if (db != NULL) pkgdb_close(db); return (retcode); }
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_update(int argc, char **argv) { char url[MAXPATHLEN]; const char *packagesite = NULL; const char *repo_name; struct pkg_config_kv *repokv = NULL; int retcode = EPKG_OK; bool multi_repos = false; (void)argv; if (argc != 1) { usage_update(); return (EX_USAGE); } if (geteuid() != 0) { warnx("updating the remote database can only be done as root"); return (EX_NOPERM); } /* * Fetch remote databases. */ pkg_config_bool(PKG_CONFIG_MULTIREPOS, &multi_repos); /* single repository */ if (!multi_repos) { /* * Single remote database */ pkg_config_string(PKG_CONFIG_REPO, &packagesite); if (packagesite == NULL) { warnx("PACKAGESITE is not defined."); return (1); } if (packagesite[strlen(packagesite) - 1] == '/') snprintf(url, MAXPATHLEN, "%srepo.txz", packagesite); else snprintf(url, MAXPATHLEN, "%s/repo.txz", packagesite); retcode = update_from_remote_repo("repo", url); } else { /* multiple repositories */ while (pkg_config_list(PKG_CONFIG_REPOS, &repokv) == EPKG_OK) { repo_name = pkg_config_kv_get(repokv, PKG_CONFIG_KV_KEY); packagesite = pkg_config_kv_get(repokv, PKG_CONFIG_KV_VALUE); if (packagesite[strlen(packagesite) - 1] == '/') snprintf(url, MAXPATHLEN, "%srepo.txz", packagesite); else snprintf(url, MAXPATHLEN, "%s/repo.txz", packagesite); retcode = update_from_remote_repo(repo_name, url); } } 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); }
void print_info(struct pkg * const pkg, unsigned int options) { struct pkg_category *cat = NULL; struct pkg_dep *dep = NULL; struct pkg_dir *dir = NULL; struct pkg_file *file = NULL; struct pkg_group *group = NULL; struct pkg_license *lic = NULL; struct pkg_option *option = NULL; struct pkg_shlib *shlib = NULL; struct pkg_user *user = NULL; bool multirepos_enabled = false; bool print_tag = false; bool show_locks = false; char size[7]; const char *name, *version, *prefix, *origin, *reponame, *repourl; const char *maintainer, *www, *comment, *desc, *message, *arch; const char *repopath; const char *tab; char *m; unsigned opt; int64_t flatsize, newflatsize, newpkgsize; lic_t licenselogic; bool locked; int cout = 0; /* Number of characters output */ int info_num; /* Number of different data items to print */ pkg_config_bool(PKG_CONFIG_MULTIREPOS, &multirepos_enabled); pkg_get(pkg, PKG_NAME, &name, PKG_VERSION, &version, PKG_PREFIX, &prefix, PKG_ORIGIN, &origin, PKG_REPONAME, &reponame, PKG_REPOURL, &repourl, PKG_MAINTAINER, &maintainer, PKG_WWW, &www, PKG_COMMENT, &comment, PKG_DESC, &desc, PKG_FLATSIZE, &flatsize, PKG_NEW_FLATSIZE, &newflatsize, PKG_NEW_PKGSIZE, &newpkgsize, PKG_LICENSE_LOGIC, &licenselogic, PKG_MESSAGE, &message, PKG_ARCH, &arch, PKG_REPOPATH, &repopath, PKG_LOCKED, &locked); if (!multirepos_enabled) pkg_config_string(PKG_CONFIG_REPO, &repourl); if (options & INFO_RAW) { /* Not for remote packages */ if (pkg_type(pkg) != PKG_REMOTE) { pkg_emit_manifest(pkg, &m); printf("%s\n", m); free(m); } return; } /* Show locking status when requested to display it and the package is locally installed */ if (pkg_type(pkg) == PKG_INSTALLED && (options & INFO_LOCKED) != 0) show_locks = true; if (!quiet) { /* Print a tag-line identifying the package -- either NAMEVER, ORIGIN or NAME (in that order of preference). This may be the only output from this function */ if (options & INFO_TAG_NAMEVER) cout = printf("%s-%s", name, version); else if (options & INFO_TAG_ORIGIN) cout = printf("%s", origin); else if (options & INFO_TAG_NAME) cout = printf("%s", name); } /* Don't display a tab if quiet, retains compatibility. */ tab = quiet ? "" : "\t"; /* If we printed a tag, and there are no other items to print, then just return now. If there's only one single-line item to print, show it at column 32 on the same line. If there's one multi-line item to print, start a new line. If there is more than one item to print per pkg, use 'key : value' style to show on a new line. */ info_num = 0; for (opt = 0x1U; opt <= INFO_LASTFIELD; opt <<= 1) if ((opt & options) != 0) info_num++; if (info_num == 0 && cout > 0) { printf("\n"); return; } if (info_num == 1) { /* Only one item to print */ print_tag = false; if (!quiet) { if (options & INFO_MULTILINE) printf(":\n"); else { if (cout < 31) cout = 31 - cout; else cout = 1; printf("%*s", cout, " "); } } } else { /* Several items to print */ print_tag = true; if (!quiet) printf("\n"); } for (opt = 0x1; opt <= INFO_LASTFIELD; opt <<= 1) { if ((opt & options) == 0) continue; switch (opt) { case INFO_NAME: if (print_tag) printf("%-15s: ", "Name"); printf("%s\n", name); break; case INFO_VERSION: if (print_tag) printf("%-15s: ", "Version"); printf("%s\n", version); break; case INFO_ORIGIN: if (print_tag) printf("%-15s: ", "Origin"); printf("%s\n", origin); break; case INFO_PREFIX: if (print_tag) printf("%-15s: ", "Prefix"); printf("%s\n", prefix); break; case INFO_REPOSITORY: if (pkg_type(pkg) == PKG_REMOTE && repourl != NULL && repourl[0] != '\0') { if (print_tag) printf("%-15s: ", "Repository"); printf("%s [%s]\n", reponame, repourl); } else if (!print_tag) printf("\n"); break; case INFO_CATEGORIES: if (pkg_list_count(pkg, PKG_CATEGORIES) > 0) { if (print_tag) printf("%-15s: ", "Categories"); if (pkg_categories(pkg, &cat) == EPKG_OK) printf("%s", pkg_category_name(cat)); while (pkg_categories(pkg, &cat) == EPKG_OK) printf(" %s", pkg_category_name(cat)); printf("\n"); } else if (!print_tag) printf("\n"); break; case INFO_LICENSES: if (pkg_list_count(pkg, PKG_LICENSES) > 0) { if (print_tag) printf("%-15s: ", "Licenses"); if (pkg_licenses(pkg, &lic) == EPKG_OK) printf("%s", pkg_license_name(lic)); while (pkg_licenses(pkg, &lic) == EPKG_OK) { if (licenselogic != 1) printf(" %c", licenselogic); printf(" %s", pkg_license_name(lic)); } printf("\n"); } else if (!print_tag) printf("\n"); break; case INFO_MAINTAINER: if (print_tag) printf("%-15s: ", "Maintainer"); printf("%s\n", maintainer); break; case INFO_WWW: if (print_tag) printf("%-15s: ", "WWW"); printf("%s\n", www); break; case INFO_COMMENT: if (print_tag) printf("%-15s: ", "Comment"); printf("%s\n", comment); break; case INFO_OPTIONS: if (pkg_list_count(pkg, PKG_OPTIONS) > 0) { if (print_tag) printf("%-15s:\n", "Options"); while (pkg_options(pkg, &option) == EPKG_OK) printf("%s%-15s: %s\n", tab, pkg_option_opt(option), pkg_option_value(option)); } break; case INFO_SHLIBS_REQUIRED: if (pkg_list_count(pkg, PKG_SHLIBS_REQUIRED) > 0) { if (print_tag) printf("%-15s:\n", "Shared Libs required"); while (pkg_shlibs_required(pkg, &shlib) == EPKG_OK) printf("%s%s\n", tab, pkg_shlib_name(shlib)); } break; case INFO_SHLIBS_PROVIDED: if (pkg_list_count(pkg, PKG_SHLIBS_PROVIDED) > 0) { if (print_tag) printf("%-15s:\n", "Shared Libs provided"); while (pkg_shlibs_provided(pkg, &shlib) == EPKG_OK) printf("%s%s\n", tab, pkg_shlib_name(shlib)); } break; case INFO_FLATSIZE: if (pkg_type(pkg) == PKG_INSTALLED || pkg_type(pkg) == PKG_FILE) humanize_number(size, sizeof(size), flatsize,"B", HN_AUTOSCALE, 0); else humanize_number(size, sizeof(size), newflatsize,"B", HN_AUTOSCALE, 0); if (print_tag) printf("%-15s: ", "Flat size"); printf("%s\n", size); break; case INFO_PKGSIZE: /* Remote pkgs only */ if (pkg_type(pkg) == PKG_REMOTE) { humanize_number(size, sizeof(size), newpkgsize,"B", HN_AUTOSCALE, 0); if (print_tag) printf("%-15s: ", "Pkg size"); printf("%s\n", size); } else if (!print_tag) printf("\n"); break; case INFO_DESCR: if (print_tag) printf("%-15s:\n", "Description"); printf("%s\n", desc); break; case INFO_MESSAGE: if (message) { if (print_tag) printf("%-15s:\n", "Message"); printf("%s\n", message); } break; case INFO_DEPS: if (pkg_list_count(pkg, PKG_DEPS) > 0) { if (print_tag) printf("%-15s:\n", "Depends on"); while (pkg_deps(pkg, &dep) == EPKG_OK) { printf("%s%s-%s", tab, pkg_dep_name(dep), pkg_dep_version(dep)); if (show_locks && pkg_dep_is_locked(dep)) printf(" (*)"); printf("\n"); } } break; case INFO_RDEPS: if (pkg_list_count(pkg, PKG_RDEPS) > 0) { if (print_tag) printf("%-15s:\n", "Required by"); while (pkg_rdeps(pkg, &dep) == EPKG_OK) { printf("%s%s-%s", tab, pkg_dep_name(dep), pkg_dep_version(dep)); if (show_locks && pkg_dep_is_locked(dep)) printf(" (*)"); printf("\n"); } } break; case INFO_FILES: /* Installed pkgs only */ if (pkg_type(pkg) != PKG_REMOTE && pkg_list_count(pkg, PKG_FILES) > 0) { if (print_tag) printf("%-15s:\n", "Files"); while (pkg_files(pkg, &file) == EPKG_OK) printf("%s%s\n", tab, pkg_file_path(file)); } break; case INFO_DIRS: /* Installed pkgs only */ if (pkg_type(pkg) != PKG_REMOTE && pkg_list_count(pkg, PKG_DIRS) > 0) { if (print_tag) printf("%-15s:\n", "Directories"); while (pkg_dirs(pkg, &dir) == EPKG_OK) printf("%s%s\n", tab, pkg_dir_path(dir)); } break; case INFO_USERS: /* Installed pkgs only */ if (pkg_type(pkg) != PKG_REMOTE && pkg_list_count(pkg, PKG_USERS) > 0) { if (print_tag) printf("%-15s: ", "Users"); if (pkg_users(pkg, &user) == EPKG_OK) printf("%s", pkg_user_name(user)); while (pkg_users(pkg, &user) == EPKG_OK) printf(" %s", pkg_user_name(user)); printf("\n"); } break; case INFO_GROUPS: /* Installed pkgs only */ if (pkg_type(pkg) != PKG_REMOTE && pkg_list_count(pkg, PKG_GROUPS) > 0) { if (print_tag) printf("%-15s: ", "Groups"); if (pkg_groups(pkg, &group) == EPKG_OK) printf("%s", pkg_group_name(group)); while (pkg_groups(pkg, &group) == EPKG_OK) printf(" %s", pkg_group_name(group)); printf("\n"); } break; case INFO_ARCH: if (print_tag) printf("%-15s: ", "Architecture"); printf("%s\n", arch); break; case INFO_REPOURL: if (pkg_type(pkg) == PKG_REMOTE && repourl != NULL && repourl[0] != '\0') { if (print_tag) printf("%-15s: ", "Pkg URL"); if (repourl[strlen(repourl) -1] == '/') printf("%s%s\n", repourl, repopath); else printf("%s/%s\n", repourl, repopath); } else if (!print_tag) printf("\n"); break; case INFO_LOCKED: if (print_tag) printf("%-15s: ", "Locked"); printf("%s\n", locked ? "yes" : "no"); break; } } }
static int pkg_update_full(const char *repofile, struct pkg_repo *repo, time_t *mtime) { char repofile_unchecked[MAXPATHLEN]; int fd = -1, rc = EPKG_FATAL; sqlite3 *sqlite = NULL; char *req = NULL; char *bad_abis = NULL; const char *myarch; snprintf(repofile_unchecked, sizeof(repofile_unchecked), "%s.unchecked", repofile); /* If the repo.sqlite file exists, test that we can write to it. If it doesn't exist, assume we can create it */ if (eaccess(repofile, F_OK) == 0 && eaccess(repofile, W_OK) == -1) { pkg_emit_error("Insufficient privilege to update %s\n", repofile); rc = EPKG_ENOACCESS; goto cleanup; } if ((fd = repo_fetch_remote_tmp(repo, repo_db_archive, "txz", mtime, &rc)) == -1) { goto cleanup; } if ((rc = repo_archive_extract_file(fd, repo_db_file, repofile_unchecked, repo->pubkey, -1)) != EPKG_OK) { goto cleanup; } /* check if the repository is for valid architecture */ if (access(repofile_unchecked, R_OK|W_OK) == -1) { pkg_emit_error("Archive file does not have repo.sqlite file"); rc = EPKG_FATAL; goto cleanup; } if (sqlite3_open(repofile_unchecked, &sqlite) != SQLITE_OK) { unlink(repofile_unchecked); pkg_emit_error("Corrupted repository"); rc = EPKG_FATAL; goto cleanup; } pkg_config_string(PKG_CONFIG_ABI, &myarch); req = sqlite3_mprintf("select group_concat(arch, ', ') from " "(select distinct arch from packages " "where arch not GLOB '%q')", myarch); if (get_sql_string(sqlite, req, &bad_abis) != EPKG_OK) { sqlite3_free(req); pkg_emit_error("Unable to query repository"); rc = EPKG_FATAL; sqlite3_close(sqlite); goto cleanup; } if (bad_abis != NULL) { pkg_emit_error("At least one of the packages provided by " "the repository is not compatible with your ABI:\n" " Your ABI: %s\n" " Incompatible ABIs found: %s", myarch, bad_abis); rc = EPKG_FATAL; sqlite3_close(sqlite); goto cleanup; } /* register the packagesite */ if (pkg_register_repo(repo, sqlite) != EPKG_OK) { sqlite3_close(sqlite); goto cleanup; } sqlite3_close(sqlite); sqlite3_shutdown(); if (rename(repofile_unchecked, repofile) != 0) { pkg_emit_errno("rename", ""); rc = EPKG_FATAL; goto cleanup; } if ((rc = remote_add_indexes(pkg_repo_ident(repo))) != EPKG_OK) goto cleanup; rc = EPKG_OK; cleanup: if (fd != -1) (void)close(fd); return (rc); }
void print_jobs_summary(struct pkg_jobs *jobs, const char *msg, ...) { struct pkg *pkg = NULL; char path[MAXPATHLEN]; struct stat st; const char *name, *version, *newversion, *pkgrepopath, *cachedir; int64_t dlsize, oldsize, newsize; int64_t flatsize, newflatsize, pkgsize; bool locked; char size[7]; va_list ap; pkg_jobs_t type; type = pkg_jobs_type(jobs); va_start(ap, msg); vprintf(msg, ap); va_end(ap); dlsize = oldsize = newsize = 0; flatsize = newflatsize = pkgsize = 0; name = version = newversion = NULL; pkg_config_string(PKG_CONFIG_CACHEDIR, &cachedir); while (pkg_jobs(jobs, &pkg) == EPKG_OK) { pkg_get(pkg, PKG_NEWVERSION, &newversion, PKG_NAME, &name, PKG_VERSION, &version, PKG_FLATSIZE, &flatsize, PKG_NEW_FLATSIZE, &newflatsize, PKG_NEW_PKGSIZE, &pkgsize, PKG_REPOPATH, &pkgrepopath, PKG_LOCKED, &locked); if (locked) { printf("\tPackage %s-%s is locked ", name, version); switch (type) { case PKG_JOBS_INSTALL: case PKG_JOBS_UPGRADE: /* If it's a new install, then it * cannot have been locked yet. */ if (newversion != NULL) { switch(pkg_version_cmp(version, newversion)) { case -1: printf("and may not be upgraded to version %s\n", newversion); break; case 0: printf("and may not be reinstalled\n"); break; case 1: printf("and may not be downgraded to version %s\n", newversion); break; } continue; } break; case PKG_JOBS_DEINSTALL: case PKG_JOBS_AUTOREMOVE: printf("and may not be deinstalled\n"); continue; break; case PKG_JOBS_FETCH: printf("but a new package can still be fetched\n"); break; } } switch (type) { case PKG_JOBS_INSTALL: case PKG_JOBS_UPGRADE: snprintf(path, MAXPATHLEN, "%s/%s", cachedir, pkgrepopath); if (stat(path, &st) == -1 || pkgsize != st.st_size) /* file looks corrupted (wrong size), assume a checksum mismatch will occur later and the file will be fetched from remote again */ dlsize += pkgsize; if (newversion != NULL) { switch (pkg_version_cmp(version, newversion)) { case 1: printf("\tDowngrading %s: %s -> %s\n", name, version, newversion); break; case 0: printf("\tReinstalling %s-%s\n", name, version); break; case -1: printf("\tUpgrading %s: %s -> %s\n", name, version, newversion); break; } oldsize += flatsize; newsize += newflatsize; } else { newsize += flatsize; printf("\tInstalling %s: %s\n", name, version); } break; case PKG_JOBS_DEINSTALL: case PKG_JOBS_AUTOREMOVE: oldsize += flatsize; newsize += newflatsize; printf("\t%s-%s\n", name, version); break; case PKG_JOBS_FETCH: dlsize += pkgsize; snprintf(path, MAXPATHLEN, "%s/%s", cachedir, pkgrepopath); if (stat(path, &st) != -1) oldsize = st.st_size; else oldsize = 0; dlsize -= oldsize; humanize_number(size, sizeof(size), pkgsize, "B", HN_AUTOSCALE, 0); printf("\t%s-%s (%" PRId64 "%% of %s)\n", name, newversion, 100 - (100 * oldsize)/pkgsize, size); break; } } if (oldsize > newsize) { humanize_number(size, sizeof(size), oldsize - newsize, "B", HN_AUTOSCALE, 0); switch (type) { case PKG_JOBS_INSTALL: printf("\nThe installation will free %s\n", size); break; case PKG_JOBS_UPGRADE: printf("\nThe upgrade will free %s\n", size); break; case PKG_JOBS_DEINSTALL: case PKG_JOBS_AUTOREMOVE: printf("\nThe deinstallation will free %s\n", size); break; case PKG_JOBS_FETCH: /* nothing to report here */ break; } } else if (newsize > oldsize) { humanize_number(size, sizeof(size), newsize - oldsize, "B", HN_AUTOSCALE, 0); switch (type) { case PKG_JOBS_INSTALL: printf("\nThe installation will require %s more space\n", size); break; case PKG_JOBS_UPGRADE: printf("\nThe upgrade will require %s more space\n", size); break; case PKG_JOBS_DEINSTALL: case PKG_JOBS_AUTOREMOVE: printf("\nThe deinstallation will require %s more space\n", size); break; case PKG_JOBS_FETCH: /* nothing to report here */ break; } } if ((type == PKG_JOBS_INSTALL) || (type == PKG_JOBS_FETCH) || (type == PKG_JOBS_UPGRADE)) { humanize_number(size, sizeof(size), dlsize, "B", HN_AUTOSCALE, 0); printf("\n%s to be downloaded\n", size); } }
int pkg_register_old(struct pkg *pkg) { FILE *fp; char *name, *version, *content, *buf; const char *pkgdbdir, *tmp; char path[MAXPATHLEN]; struct sbuf *install_script = sbuf_new_auto(); struct sbuf *deinstall_script = sbuf_new_auto(); struct pkg_dep *dep = NULL; pkg_to_old(pkg); pkg_get(pkg, PKG_NAME, &name, PKG_VERSION, &version); pkg_old_emit_content(pkg, &content); pkg_config_string(PKG_CONFIG_DBDIR, &pkgdbdir); snprintf(path, sizeof(path), "%s/%s-%s", pkgdbdir, name, version); mkdir(path, 0755); snprintf(path, sizeof(path), "%s/%s-%s/+CONTENTS", pkgdbdir, name, version); fp = fopen(path, "w"); fputs(content, fp); fclose(fp); pkg_get(pkg, PKG_DESC, &buf); snprintf(path, sizeof(path), "%s/%s-%s/+DESC", pkgdbdir, name, version); fp = fopen(path, "w"); fputs(buf, fp); fclose(fp); pkg_get(pkg, PKG_COMMENT, &buf); snprintf(path, sizeof(path), "%s/%s-%s/+COMMENT", pkgdbdir, name, version); fp = fopen(path, "w"); fprintf(fp, "%s\n", buf); fclose(fp); pkg_get(pkg, PKG_MESSAGE, &buf); if (buf != NULL && *buf != '\0') { snprintf(path, sizeof(path), "%s/%s-%s/+DISPLAY", pkgdbdir, name, version); fp = fopen(path, "w"); fputs(buf, fp); fclose(fp); } sbuf_clear(install_script); tmp = pkg_script_get(pkg, PKG_SCRIPT_PRE_INSTALL); if (tmp != NULL && *tmp != '\0') { if (sbuf_len(install_script) == 0) sbuf_cat(install_script, "#!/bin/sh\n\n"); sbuf_printf(install_script, "if [ \"$2\" = \"PRE-INSTALL\" ]; then\n" "%s\n" "fi\n", tmp); } tmp = pkg_script_get(pkg, PKG_SCRIPT_INSTALL); if (tmp != NULL && *tmp != '\0') { if (sbuf_len(install_script) == 0) sbuf_cat(install_script, "#!/bin/sh\n\n"); sbuf_cat(install_script, tmp); } tmp = pkg_script_get(pkg, PKG_SCRIPT_POST_INSTALL); if (tmp != NULL && *tmp != '\0') { if (sbuf_len(install_script) == 0) sbuf_cat(install_script, "#!/bin/sh\n\n"); sbuf_printf(install_script, "if [ \"$2\" = \"POST-INSTALL\" ]; then\n" "%s\n" "fi\n", tmp); } if (sbuf_len(install_script) > 0) { sbuf_finish(install_script); snprintf(path, sizeof(path), "%s/%s-%s/+INSTALL", pkgdbdir, name, version); fp = fopen(path, "w"); fputs(sbuf_data(install_script), fp); fclose(fp); } sbuf_clear(deinstall_script); tmp = pkg_script_get(pkg, PKG_SCRIPT_PRE_DEINSTALL); if (tmp != NULL && *tmp != '\0') { if (sbuf_len(deinstall_script) == 0) sbuf_cat(deinstall_script, "#!/bin/sh\n\n"); sbuf_printf(deinstall_script, "if [ \"$2\" = \"DEINSTALL\" ]; then\n" "%s\n" "fi\n", tmp); } tmp = pkg_script_get(pkg, PKG_SCRIPT_DEINSTALL); if (tmp != NULL && *tmp != '\0') { if (sbuf_len(deinstall_script) == 0) sbuf_cat(deinstall_script, "#!/bin/sh\n\n"); sbuf_cat(deinstall_script, tmp); } tmp = pkg_script_get(pkg, PKG_SCRIPT_POST_DEINSTALL); if (tmp != NULL && tmp[0] != '\0') { if (sbuf_len(deinstall_script) == 0) sbuf_cat(deinstall_script, "#!/bin/sh\n\n"); sbuf_printf(deinstall_script, "if [ \"$2\" = \"POST-DEINSTALL\" ]; then\n" "%s\n" "fi\n", tmp); } if (sbuf_len(deinstall_script) > 0) { sbuf_finish(deinstall_script); snprintf(path, sizeof(path), "%s/%s-%s/+DEINSTALL", pkgdbdir, name, version); fp = fopen(path, "w"); fputs(sbuf_data(deinstall_script), fp); fclose(fp); } while (pkg_deps(pkg, &dep)) { snprintf(path, sizeof(path), "%s/%s-%s/+REQUIRED_BY", pkgdbdir, pkg_dep_name(dep), pkg_dep_version(dep)); fp = fopen(path, "a"); fprintf(fp, "%s-%s\n", name, version); fclose(fp); } return (EPKG_OK); }