static int pkg_repo_binary_create_symlink(struct pkg *pkg, const char *fname, const char *dir) { const char *ext, *dest_fname; char link_dest_tmp[MAXPATHLEN], link_dest[MAXPATHLEN]; /* Create symlink from full pkgname */ ext = strrchr(fname, '.'); pkg_snprintf(link_dest, sizeof(link_dest), "%S/%n-%v%S", dir, pkg, pkg, ext ? ext : ""); snprintf(link_dest_tmp, sizeof(link_dest_tmp), "%s.new", link_dest); /* Ignore errors here */ (void)unlink(link_dest_tmp); /* Trim the path to just the filename. */ if ((dest_fname = strrchr(fname, '/')) != NULL) ++dest_fname; if (symlink(dest_fname, link_dest_tmp) == -1) { pkg_emit_errno("symlink", link_dest); return (EPKG_FATAL); } if (rename(link_dest_tmp, link_dest) == -1) { pkg_emit_errno("rename", link_dest); unlink(link_dest_tmp); return (EPKG_FATAL); } return (EPKG_OK); }
int pkg_repo_binary_get_cached_name(struct pkg_repo *repo, struct pkg *pkg, char *dest, size_t destlen) { const char *ext = NULL; const char *cachedir = NULL; const char *packagesite; struct stat st; cachedir = pkg_object_string(pkg_config_get("PKG_CACHEDIR")); packagesite = pkg_repo_url(repo); if (strncmp(packagesite, "file://", 7) == 0) { snprintf(dest, destlen, "%s/%s", packagesite + 7, pkg->repopath); return (EPKG_OK); } if (pkg->repopath != NULL) ext = strrchr(pkg->repopath, '.'); if (ext != NULL) { /* * The real naming scheme: * <cachedir>/<name>-<version>-<checksum>.txz */ pkg_snprintf(dest, destlen, "%S/%n-%v-%z%S", cachedir, pkg, pkg, pkg, ext); if (stat (dest, &st) == -1 || pkg->pkgsize != st.st_size) return (EPKG_FATAL); } else { pkg_snprintf(dest, destlen, "%S/%n-%v-%z", cachedir, pkg, pkg, pkg); } return (EPKG_OK); }
void pkg_repo_binary_get_cached_name(struct pkg_repo *repo, struct pkg *pkg, char *dest, size_t destlen) { const char *sum, *name, *version, *repourl, *ext = NULL; const char *cachedir = NULL; struct stat st; cachedir = pkg_object_string(pkg_config_get("PKG_CACHEDIR")); pkg_get(pkg, PKG_CKSUM, &sum, PKG_NAME, &name, PKG_VERSION, &version, PKG_REPOPATH, &repourl); if (repourl != NULL) ext = strrchr(repourl, '.'); if (ext != NULL) { /* * XXX: * This code tries to skip refetching but it should be removed as soon * as we transfer to new scheme. */ pkg_snprintf(dest, destlen, "%S/%n-%v-%z", cachedir, pkg, pkg, pkg); if (stat (dest, &st) != -1) return; /* * The real naming scheme: * <cachedir>/<name>-<version>-<checksum>.txz */ pkg_snprintf(dest, destlen, "%S/%n-%v-%z%S", cachedir, pkg, pkg, pkg, ext); } else { pkg_snprintf(dest, destlen, "%S/%n-%v-%z", cachedir, pkg, pkg, pkg); } }
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_register_old(struct pkg *pkg) { FILE *fp; char *content; const char *pkgdbdir, *tmp; char path[MAXPATHLEN]; struct sbuf *install_script = sbuf_new_auto(); struct sbuf *deinstall_script = sbuf_new_auto(); struct pkg_dep *dep = NULL; pkg_to_old(pkg); pkg_old_emit_content(pkg, &content); pkgdbdir = pkg_object_string(pkg_config_get("PKG_DBDIR")); pkg_snprintf(path, sizeof(path), "%S/%n-%v", pkgdbdir, pkg, pkg); mkdir(path, 0755); pkg_snprintf(path, sizeof(path), "%S/%n-%v/+CONTENTS", pkgdbdir, pkg, pkg); fp = fopen(path, "w"); fputs(content, fp); fclose(fp); pkg_snprintf(path, sizeof(path), "%S/%n-%v/+DESC", pkgdbdir, pkg, pkg); fp = fopen(path, "w"); pkg_fprintf(fp, "%e", pkg); fclose(fp); pkg_snprintf(path, sizeof(path), "%s/%n-%v/+COMMENT", pkgdbdir, pkg, pkg); fp = fopen(path, "w"); pkg_fprintf(fp, "%c\n", pkg); fclose(fp); if (pkg_has_message(pkg)) { pkg_snprintf(path, sizeof(path), "%s/%n-%v/+DISPLAY", pkgdbdir, pkg, pkg); fp = fopen(path, "w"); pkg_fprintf(fp, "%M", pkg); fclose(fp); } sbuf_clear(install_script); tmp = pkg_script_get(pkg, PKG_SCRIPT_PRE_INSTALL); if (tmp != NULL && *tmp != '\0') { if (sbuf_len(install_script) == 0) sbuf_cat(install_script, "#!/bin/sh\n\n"); sbuf_printf(install_script, "if [ \"$2\" = \"PRE-INSTALL\" ]; then\n" "%s\n" "fi\n", tmp); } tmp = pkg_script_get(pkg, PKG_SCRIPT_INSTALL); if (tmp != NULL && *tmp != '\0') { if (sbuf_len(install_script) == 0) sbuf_cat(install_script, "#!/bin/sh\n\n"); sbuf_cat(install_script, tmp); } tmp = pkg_script_get(pkg, PKG_SCRIPT_POST_INSTALL); if (tmp != NULL && *tmp != '\0') { if (sbuf_len(install_script) == 0) sbuf_cat(install_script, "#!/bin/sh\n\n"); sbuf_printf(install_script, "if [ \"$2\" = \"POST-INSTALL\" ]; then\n" "%s\n" "fi\n", tmp); } if (sbuf_len(install_script) > 0) { sbuf_finish(install_script); pkg_snprintf(path, sizeof(path), "%s/%n-%v/+INSTALL", pkgdbdir, pkg, pkg); fp = fopen(path, "w"); fputs(sbuf_data(install_script), fp); fclose(fp); } sbuf_clear(deinstall_script); tmp = pkg_script_get(pkg, PKG_SCRIPT_PRE_DEINSTALL); if (tmp != NULL && *tmp != '\0') { if (sbuf_len(deinstall_script) == 0) sbuf_cat(deinstall_script, "#!/bin/sh\n\n"); sbuf_printf(deinstall_script, "if [ \"$2\" = \"DEINSTALL\" ]; then\n" "%s\n" "fi\n", tmp); } tmp = pkg_script_get(pkg, PKG_SCRIPT_DEINSTALL); if (tmp != NULL && *tmp != '\0') { if (sbuf_len(deinstall_script) == 0) sbuf_cat(deinstall_script, "#!/bin/sh\n\n"); sbuf_cat(deinstall_script, tmp); } tmp = pkg_script_get(pkg, PKG_SCRIPT_POST_DEINSTALL); if (tmp != NULL && tmp[0] != '\0') { if (sbuf_len(deinstall_script) == 0) sbuf_cat(deinstall_script, "#!/bin/sh\n\n"); sbuf_printf(deinstall_script, "if [ \"$2\" = \"POST-DEINSTALL\" ]; then\n" "%s\n" "fi\n", tmp); } if (sbuf_len(deinstall_script) > 0) { sbuf_finish(deinstall_script); pkg_snprintf(path, sizeof(path), "%s/%n-%v/+DEINSTALL", pkgdbdir, pkg, pkg); fp = fopen(path, "w"); fputs(sbuf_data(deinstall_script), fp); fclose(fp); } while (pkg_deps(pkg, &dep)) { snprintf(path, sizeof(path), "%s/%s-%s/+REQUIRED_BY", pkgdbdir, pkg_dep_name(dep), pkg_dep_version(dep)); fp = fopen(path, "a"); pkg_fprintf(fp, "%n-%v\n", pkg, pkg); fclose(fp); } return (EPKG_OK); }
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); }
static int pkg_create_matches(int argc, char **argv, match_t match, pkg_formats fmt, const char * const outdir, bool overwrite) { int i, ret = EPKG_OK, retcode = EPKG_OK; struct pkg *pkg = NULL; struct pkgdb *db = NULL; struct pkgdb_it *it = NULL; int query_flags = PKG_LOAD_DEPS | PKG_LOAD_FILES | PKG_LOAD_CATEGORIES | PKG_LOAD_DIRS | PKG_LOAD_SCRIPTS | PKG_LOAD_OPTIONS | PKG_LOAD_LICENSES | PKG_LOAD_USERS | PKG_LOAD_GROUPS | PKG_LOAD_SHLIBS_REQUIRED | PKG_LOAD_PROVIDES | PKG_LOAD_REQUIRES | PKG_LOAD_SHLIBS_PROVIDED | PKG_LOAD_ANNOTATIONS; struct pkg_entry *e = NULL, *etmp; char pkgpath[MAXPATHLEN]; const char *format = NULL; bool foundone; if (pkgdb_open(&db, PKGDB_DEFAULT) != EPKG_OK) { pkgdb_close(db); return (EX_IOERR); } /* XXX: get rid of hardcoded timeouts */ if (pkgdb_obtain_lock(db, PKGDB_LOCK_READONLY) != EPKG_OK) { pkgdb_close(db); warnx("Cannot get a read lock on a database, it is locked by another process"); return (EX_TEMPFAIL); } switch (fmt) { case TXZ: format = "txz"; break; case TBZ: format = "tbz"; break; case TGZ: format = "tgz"; break; case TAR: format = "tar"; break; } for (i = 0; i < argc || match == MATCH_ALL; i++) { if (match == MATCH_ALL) { printf("Loading the package list...\n"); if ((it = pkgdb_query(db, NULL, match)) == NULL) goto cleanup; match = !MATCH_ALL; } else if ((it = pkgdb_query(db, argv[i], match)) == NULL) goto cleanup; foundone = false; while ((ret = pkgdb_it_next(it, &pkg, query_flags)) == EPKG_OK) { if ((e = malloc(sizeof(struct pkg_entry))) == NULL) err(1, "malloc(pkg_entry)"); e->pkg = pkg; pkg = NULL; DL_APPEND(pkg_head, e); foundone = true; } if (!foundone) { warnx("No installed package matching \"%s\" found\n", argv[i]); retcode++; } pkgdb_it_free(it); if (ret != EPKG_END) retcode++; } DL_FOREACH_SAFE(pkg_head, e, etmp) { DL_DELETE(pkg_head, e); if (!overwrite) { pkg_snprintf(pkgpath, sizeof(pkgpath), "%S/%n-%v.%S", outdir, e->pkg, e->pkg, format); if (access(pkgpath, F_OK) == 0) { pkg_printf("%n-%v already packaged, skipping...\n", e->pkg, e->pkg); pkg_free(e->pkg); free(e); continue; } } pkg_printf("Creating package for %n-%v\n", e->pkg, e->pkg); if (pkg_create_installed(outdir, fmt, e->pkg) != EPKG_OK) retcode++; pkg_free(e->pkg); free(e); }
/* --------------------------------------------------------------------- */ int netsnmp_swinst_arch_load( netsnmp_container *container, u_int flags) { DIR *d; struct dirent *dp; struct stat stat_buf; #ifdef HAVE_PKGINFO char *v, *c; #endif char buf[ BUFSIZ ]; unsigned char *cp; time_t install_time; size_t date_len; int i = 1; netsnmp_swinst_entry *entry; #ifdef HAVE_LIBPKG struct pkgdb *db = NULL; struct pkgdb_it *it = NULL; struct pkg *pkg = NULL; char pkgname[ SNMP_MAXPATH ]; char pkgdate[ BUFSIZ ]; int pkgng = 0; if (pkg_init(NULL, NULL)) { snmp_log( LOG_ERR, "SWInst: error initializing pkgng db\n" ); return 1; } if (pkgdb_open(&db, PKGDB_DEFAULT) != EPKG_OK) { snmp_log( LOG_ERR, "SWInst: error opening pkgng db\n" ); return 1; } if (pkg_status(NULL) == PKG_STATUS_ACTIVE) { pkgng = 1; } else { snmp_log( LOG_INFO, "SWInst: not a pkgng system\n" ); } /* if we are using FreeBSD's pkgng */ if (pkgng) { if ((it = pkgdb_query(db, NULL, MATCH_ALL)) == NULL) { snmp_log( LOG_ERR, "SWInst: error querying pkgng db\n" ); return 1; } while (pkgdb_it_next(it, &pkg, PKG_LOAD_BASIC) == EPKG_OK) { pkg_snprintf(pkgname, sizeof(pkgname), "%n-%v", pkg, pkg); pkg_snprintf(pkgdate, sizeof(pkgdate), "%t", pkg); entry = netsnmp_swinst_entry_create( i++ ); if (NULL == entry) continue; /* error already logged by function */ CONTAINER_INSERT(container, entry); entry->swName_len = snprintf( entry->swName, sizeof(entry->swName), "%s", pkgname ); if (entry->swName_len >= sizeof(entry->swName)) entry->swName_len = sizeof(entry->swName)-1; install_time = atoi(pkgdate); cp = date_n_time( &install_time, &date_len ); memcpy( entry->swDate, cp, date_len ); entry->swDate_len = date_len; } pkgdb_it_free(it); pkgdb_close(db); pkg_shutdown(); } else { #endif /* HAVE_LIBPKG */ if ( !pkg_directory[0] ) { return 1; /* Can't report installed packages if there isn't a list of them! */ } d = opendir( pkg_directory ); if (!d) return 1; while ((dp = readdir(d)) != NULL) { if ( '.' == dp->d_name[0] ) continue; snprintf( buf, BUFSIZ, "%s/%s", pkg_directory, dp->d_name ); if (stat( buf, &stat_buf ) < 0) continue; entry = netsnmp_swinst_entry_create( i++ ); if (NULL == entry) continue; /* error already logged by function */ CONTAINER_INSERT(container, entry); #ifdef HAVE_PKGINFO v = pkgparam( dp->d_name, "VERSION" ); c = pkgparam( dp->d_name, "CATEGORY" ); entry->swName_len = snprintf( entry->swName, sizeof(entry->swName), "%s-%s", dp->d_name, v ); if (entry->swName_len >= sizeof(entry->swName)) entry->swName_len = sizeof(entry->swName)-1; entry->swType = (NULL != strstr( c, "system")) ? 2 /* operatingSystem */ : 4; /* application */ /* Do we need to free 'v' & 'c' ??? */ #else entry->swName_len = snprintf( entry->swName, sizeof(entry->swName), "%s", dp->d_name ); if (entry->swName_len >= sizeof(entry->swName)) entry->swName_len = sizeof(entry->swName)-1; /* no information about O/S vs application packages ??? */ #endif install_time = stat_buf.st_mtime; cp = date_n_time( &install_time, &date_len ); memcpy( entry->swDate, cp, date_len ); entry->swDate_len = date_len; } closedir( d ); #ifdef HAVE_LIBPKG } #endif DEBUGMSGTL(("swinst:load:arch"," loaded %d entries\n", (int)CONTAINER_SIZE(container))); return 0; }
static int do_load(struct pkgdir *pkgdir, unsigned ldflags) { struct pndir *idx; struct pkg *pkg = NULL; struct pkg_offs pkgo; struct pkg_data *pkgd; struct tndb_it it; tn_stream *st; tn_array *ign_patterns = NULL; int rc, klen, vlen, nerr = 0; char key[TNDB_KEY_MAX + 1], path[PATH_MAX]; idx = pkgdir->mod_data; if (!tndb_it_start(idx->db, &it)) return 0; vf_url_slim(path, sizeof(path), pkgdir->idxpath, 0); if ((ldflags & PKGDIR_LD_DOIGNORE) && pkgdir->src && n_array_size(pkgdir->src->ign_patterns)) { ign_patterns = pkgdir->src->ign_patterns; } DBGF("ign_patterns %p\n", ign_patterns); st = tndb_it_stream(&it); while ((rc = tndb_it_get_begin(&it, key, &klen, &vlen)) > 0) { struct pkg kpkg; n_assert(klen > 0); if (*key == '%' && strncmp(key, "%__h_", 5) == 0) goto l_continue_loop; if (pndir_parse_pkgkey(key, klen, &kpkg) == NULL) { logn(LOGERR, "%s: parse error", key); nerr++; goto l_continue_loop; } if (ign_patterns) { char buf[512]; unsigned int i; pkg_snprintf(buf, sizeof(buf), &kpkg); for (i=0; i < n_array_size(ign_patterns); i++) { char *p = n_array_nth(ign_patterns, i); if (fnmatch(p, buf, 0) == 0) { msgn(3, "pndir: ignored %s", pkg_snprintf_s(pkg)); goto l_continue_loop; } } } pkg = pkg_restore_st(st, pkgdir->na, &kpkg, pkgdir->foreign_depdirs, ldflags, &pkgo, path); DBGF("%s -> %p\n", pkg_snprintf_s(&kpkg), pkg); if (pkg == NULL) { nerr++; goto l_continue_loop; } pkg->pkgdir = pkgdir; pkgd = pkg_data_malloc(pkgdir->na); pkgd->off_nodep_files = pkgo.nodep_files_offs; //pkgd->off_pkguinf = pkgo.pkguinf_offs; pkgd->db = tndb_ref(idx->db); if (idx->db_dscr_h) pkgd->db_dscr_h = n_ref(idx->db_dscr_h); if (pkgdir->langs) pkgd->langs = n_ref(pkgdir->langs); pkg->pkgdir_data = pkgd; pkg->pkgdir_data_free = pkg_data_free; pkg->load_pkguinf = pndir_m_load_pkguinf; pkg->load_nodep_fl = pndir_load_nodep_fl; n_array_push(pkgdir->pkgs, pkg); l_continue_loop: if (!tndb_it_get_end(&it) || nerr > 0) { logn(LOGERR, "%s: broken file", path); nerr++; break; } } if (nerr) n_array_clean(pkgdir->pkgs); return n_array_size(pkgdir->pkgs); }
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; } }
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; bool developer; struct stat st; char sha256[SHA256_DIGEST_LENGTH * 2 + 1]; int64_t flatsize = 0; const char *relocation; struct hardlinks *hardlinks = NULL; if (pkg_is_valid(pkg) != EPKG_OK) { pkg_emit_error("the package is not valid"); return (EPKG_FATAL); } relocation = pkg_kv_get(&pkg->annotations, "relocated"); if (relocation == NULL) relocation = ""; /* * Get / compute size / checksum if not provided in the manifest */ while (pkg_files(pkg, &file) == EPKG_OK) { snprintf(fpath, sizeof(fpath), "%s%s%s", root ? root : "", relocation, file->path); if (lstat(fpath, &st) == -1) { pkg_emit_error("file '%s' is missing", fpath); return (EPKG_FATAL); } if (file->size == 0) file->size = (int64_t)st.st_size; if (st.st_nlink == 1 || !check_for_hardlink(&hardlinks, &st)) { flatsize += file->size; } if (S_ISLNK(st.st_mode)) { if (file->sum[0] == '\0') { if (pkg_symlink_cksum(fpath, root, sha256) == EPKG_OK) strlcpy(file->sum, sha256, sizeof(file->sum)); else return (EPKG_FATAL); } } else { if (file->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->flatsize = flatsize; HASH_FREE(hardlinks, free); if (pkg->type == PKG_OLD_FILE) { char oldcomment[BUFSIZ]; pkg_old_emit_content(pkg, &m); packing_append_buffer(pkg_archive, m, "+CONTENTS", strlen(m)); free(m); packing_append_buffer(pkg_archive, pkg->desc, "+DESC", strlen(pkg->desc)); packing_append_buffer(pkg_archive, pkg->message, "+DISPLAY", strlen(pkg->message)); pkg_snprintf(oldcomment, sizeof(oldcomment), "%c\n", pkg); 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_analyse_files(NULL, 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); } while (pkg_files(pkg, &file) == EPKG_OK) { snprintf(fpath, sizeof(fpath), "%s%s%s", root ? root : "", relocation, file->path); ret = packing_append_file_attr(pkg_archive, fpath, file->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) { snprintf(fpath, sizeof(fpath), "%s%s%s", root ? root : "", relocation, dir->path); ret = packing_append_file_attr(pkg_archive, fpath, dir->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); }
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); }
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; int retcode = EPKG_OK; const char *sum, *name, *version, *reponame; struct pkg_repo *repo; assert((pkg->type & PKG_REMOTE) == PKG_REMOTE); if (pkg_config_string(PKG_CONFIG_CACHEDIR, &cachedir) != EPKG_OK) return (EPKG_FATAL); pkg_get(pkg, PKG_REPONAME, &reponame, PKG_CKSUM, &sum, PKG_NAME, &name, PKG_VERSION, &version); pkg_snprintf(dest, sizeof(dest), "%S/%R", cachedir, pkg); /* 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. */ repo = pkg_repo_find_name(reponame); 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); retcode = pkg_fetch_file(repo, 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); }