static int do_extract(struct archive *a, struct archive_entry *ae, const char *location, int nfiles, struct pkg *pkg, struct pkg *local) { int retcode = EPKG_OK; int ret = 0, cur_file = 0; char path[MAXPATHLEN], pathname[MAXPATHLEN], rpath[MAXPATHLEN]; struct stat st; const struct stat *aest; bool renamed = false; const struct pkg_file *rf; struct pkg_config_file *rcf; struct sbuf *newconf; bool automerge = pkg_object_bool(pkg_config_get("AUTOMERGE")); unsigned long set, clear; #ifndef HAVE_ARC4RANDOM srand(time(NULL)); #endif if (nfiles == 0) return (EPKG_OK); pkg_emit_extract_begin(pkg); pkg_emit_progress_start(NULL); newconf = sbuf_new_auto(); do { ret = ARCHIVE_OK; sbuf_clear(newconf); rf = NULL; rcf = NULL; pkg_absolutepath(archive_entry_pathname(ae), path, sizeof(path)); snprintf(pathname, sizeof(pathname), "%s%s%s", location ? location : "", *path == '/' ? "" : "/", path ); strlcpy(rpath, pathname, sizeof(rpath)); aest = archive_entry_stat(ae); archive_entry_fflags(ae, &set, &clear); if (lstat(rpath, &st) != -1) { /* * We have an existing file on the path, so handle it */ if (!S_ISDIR(aest->st_mode)) { pkg_debug(2, "Old version found, renaming"); pkg_add_file_random_suffix(rpath, sizeof(rpath), 12); renamed = true; } if (!S_ISDIR(st.st_mode) && S_ISDIR(aest->st_mode)) { if (S_ISLNK(st.st_mode)) { if (stat(rpath, &st) == -1) { pkg_emit_error("Dead symlink %s", rpath); } else { pkg_debug(2, "Directory is a symlink, use it"); pkg_emit_progress_tick(cur_file++, nfiles); continue; } } } } archive_entry_set_pathname(ae, rpath); /* load in memory the content of config files */ if (pkg_is_config_file(pkg, path, &rf, &rcf)) { pkg_debug(1, "Populating config_file %s", pathname); size_t len = archive_entry_size(ae); rcf->content = malloc(len); archive_read_data(a, rcf->content, len); if (renamed && (!automerge || local == NULL)) strlcat(pathname, ".pkgnew", sizeof(pathname)); } /* * check if the file is already provided by previous package */ if (!automerge) attempt_to_merge(renamed, rcf, local, pathname, path, newconf); if (sbuf_len(newconf) == 0 && (rcf == NULL || rcf->content == NULL)) { pkg_debug(1, "Extracting: %s", archive_entry_pathname(ae)); int install_as_user = (getenv("INSTALL_AS_USER") != NULL); int extract_flags = EXTRACT_ARCHIVE_FLAGS; if (install_as_user) { /* when installing as user don't try to set file ownership */ extract_flags &= ~ARCHIVE_EXTRACT_OWNER; } ret = archive_read_extract(a, ae, extract_flags); } else { if (sbuf_len(newconf) == 0) { sbuf_cat(newconf, rcf->content); sbuf_finish(newconf); } pkg_debug(2, "Writing conf in %s", pathname); unlink(rpath); FILE *f = fopen(rpath, "w+"); fprintf(f, "%s", sbuf_data(newconf)); fclose(f); } if (ret != ARCHIVE_OK) { /* * show error except when the failure is during * extracting a directory and that the directory already * exists. * this allow to install packages linux_base from * package for example */ if (archive_entry_filetype(ae) != AE_IFDIR || !is_dir(pathname)) { pkg_emit_error("archive_read_extract(): %s", archive_error_string(a)); retcode = EPKG_FATAL; goto cleanup; } } /* Reapply modes to the directories to work around a problem on FreeBSD 9 */ if (archive_entry_filetype(ae) == AE_IFDIR) chmod(pathname, aest->st_mode); pkg_emit_progress_tick(cur_file++, nfiles); /* Rename old file */ if (renamed) { pkg_debug(1, "Renaming %s -> %s", rpath, pathname); #ifdef HAVE_CHFLAGS bool old = false; if (set & NOCHANGESFLAGS) chflags(rpath, 0); if (lstat(pathname, &st) != -1) { old = true; if (st.st_flags & NOCHANGESFLAGS) chflags(pathname, 0); } #endif if (rename(rpath, pathname) == -1) { #ifdef HAVE_CHFLAGS /* restore flags */ if (old) chflags(pathname, st.st_flags); #endif pkg_emit_error("cannot rename %s to %s: %s", rpath, pathname, strerror(errno)); retcode = EPKG_FATAL; goto cleanup; } #ifdef HAVE_CHFLAGS /* Restore flags */ chflags(pathname, set); #endif } if (string_end_with(pathname, ".pkgnew")) pkg_emit_notice("New configuration file: %s", pathname); renamed = false; } while ((ret = archive_read_next_header(a, &ae)) == ARCHIVE_OK); if (ret != ARCHIVE_EOF) { pkg_emit_error("archive_read_next_header(): %s", archive_error_string(a)); retcode = EPKG_FATAL; } cleanup: pkg_emit_progress_tick(nfiles, nfiles); pkg_emit_extract_finished(pkg); if (renamed && retcode == EPKG_FATAL) { #ifdef HAVE_CHFLAGS if (set & NOCHANGESFLAGS) chflags(rpath, set & ~NOCHANGESFLAGS); #endif unlink(rpath); } return (retcode); }
int exec_which(int argc, char **argv) { struct pkgdb *db = NULL; struct pkgdb_it *it = NULL; struct pkg *pkg = NULL; char pathabs[MAXPATHLEN]; char *p, *path, *match, *savedpath; int ret = EPKG_OK, retcode = EX_SOFTWARE; int ch, i; int res, pathlen = 0; bool orig = false; bool glob = false; bool search = false; bool search_s = false; charlist patterns; struct option longopts[] = { { "glob", no_argument, NULL, 'g' }, { "origin", no_argument, NULL, 'o' }, { "path-search", no_argument, NULL, 'p' }, { "quiet", no_argument, NULL, 'q' }, { NULL, 0, NULL, 0 }, }; path = NULL; while ((ch = getopt_long(argc, argv, "+gopq", longopts, NULL)) != -1) { switch (ch) { case 'g': glob = true; break; case 'o': orig = true; break; case 'p': search_s = true; break; case 'q': quiet = true; break; default: usage_which(); return (EX_USAGE); } } argc -= optind; argv += optind; if (argc < 1) { usage_which(); return (EX_USAGE); } if (pkgdb_open(&db, PKGDB_DEFAULT) != EPKG_OK) { return (EX_IOERR); } 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); } if (search_s) { if ((path = getenv("PATH")) == NULL) { printf("$PATH is not set, falling back to non-search behaviour\n"); search_s = false; } else { pathlen = strlen(path) + 1; } } while (argc >= 1) { kv_init(patterns); retcode = EX_SOFTWARE; if (search_s) { if ((argv[0][0] == '.') || (argv[0][0] == '/')) { search = false; } else { search = true; if (strlen(argv[0]) >= FILENAME_MAX) { retcode = EX_USAGE; goto cleanup; } p = malloc(pathlen); if (p == NULL) { retcode = EX_OSERR; goto cleanup; } strlcpy(p, path, pathlen); match = NULL; savedpath=p; for (;;) { res = get_match(&match, &p, argv[0]); if (p == NULL) break; if (res == (EX_USAGE)) { printf("%s was not found in PATH, falling back to non-search behaviour\n", argv[0]); search = false; } else if (res == (EX_OSERR)) { retcode = EX_OSERR; free(savedpath); goto cleanup; } else { pkg_absolutepath(match, pathabs, sizeof(pathabs)); /* ensure not not append twice an entry if PATH is messy */ if (already_in_list(&patterns, pathabs)) continue; kv_push(char *, patterns, strdup(pathabs)); free(match); } } free(savedpath); } } if (!glob && !search) { pkg_absolutepath(argv[0], pathabs, sizeof(pathabs)); kv_push(char *, patterns, strdup(pathabs)); } else if (!search) { if (strlcpy(pathabs, argv[0], sizeof(pathabs)) >= sizeof(pathabs)) { retcode = EX_USAGE; goto cleanup; } } for (i = 0; i < kv_size(patterns); i++) { if ((it = pkgdb_query_which(db, kv_A(patterns, i), glob)) == NULL) { retcode = EX_IOERR; goto cleanup; } pkg = NULL; while ((ret = pkgdb_it_next(it, &pkg, PKG_LOAD_BASIC)) == EPKG_OK) { retcode = EX_OK; if (quiet && orig) pkg_printf("%o\n", pkg); else if (quiet && !orig) pkg_printf("%n-%v\n", pkg, pkg); else if (!quiet && orig) pkg_printf("%S was installed by package %o\n", kv_A(patterns, i), pkg); else if (!quiet && !orig) pkg_printf("%S was installed by package %n-%v\n", kv_A(patterns, i), pkg, pkg); } if (retcode != EX_OK && !quiet) printf("%s was not found in the database\n", kv_A(patterns, i)); pkg_free(pkg); pkgdb_it_free(it); } kv_destroy(patterns); argc--; argv++; } cleanup: pkgdb_release_lock(db, PKGDB_LOCK_READONLY); pkgdb_close(db); return (retcode); }