From e967bfd71a068d6c3f5831cfa93de92d78136065 Mon Sep 17 00:00:00 2001 From: Richard Hughes Date: Mon, 16 Jun 2008 14:43:03 -0400 Subject: Autoconfify razor. --- src/.gitignore | 5 + src/Makefile.am | 26 ++ src/import-rpmdb.c | 157 ++++++++++ src/import-yum.c | 337 ++++++++++++++++++++ src/main.c | 804 +++++++++++++++++++++++++++++++++++++++++++++++ src/rpm.c | 897 +++++++++++++++++++++++++++++++++++++++++++++++++++++ src/test-driver.c | 458 +++++++++++++++++++++++++++ src/test.xml | 858 ++++++++++++++++++++++++++++++++++++++++++++++++++ 8 files changed, 3542 insertions(+) create mode 100644 src/.gitignore create mode 100644 src/Makefile.am create mode 100644 src/import-rpmdb.c create mode 100644 src/import-yum.c create mode 100644 src/main.c create mode 100644 src/rpm.c create mode 100644 src/test-driver.c create mode 100644 src/test.xml (limited to 'src') diff --git a/src/.gitignore b/src/.gitignore new file mode 100644 index 0000000..25f606c --- /dev/null +++ b/src/.gitignore @@ -0,0 +1,5 @@ +.deps +.libs +razor +rpm-razor + diff --git a/src/Makefile.am b/src/Makefile.am new file mode 100644 index 0000000..58f7788 --- /dev/null +++ b/src/Makefile.am @@ -0,0 +1,26 @@ +## Process this file with automake to produce Makefile.in + +INCLUDES = \ + $(CURL_CFLAGS) \ + $(EXPAT_CFLAGS) \ + $(RPM_CFLAGS) \ + -I$(top_builddir)/src -I$(top_srcdir)/src \ + -I$(top_srcdir)/librazor \ + -DPACKAGE_LIBEXEC_DIR=\""$(libexecdir)"\" \ + -DPACKAGE_SYSCONF_DIR=\""$(sysconfdir)"\" \ + -DPACKAGE_DATA_DIR=\""$(datadir)"\" \ + -DPACKAGE_BIN_DIR=\""$(bindir)"\" \ + -DPACKAGE_LOCALSTATEDIR=\""$(localstatedir)"\" \ + -DPACKAGE_LOCALE_DIR=\""$(localedir)"\" + +bin_PROGRAMS = razor rpm + +razor_SOURCES = main.c import-rpmdb.c import-yum.c +razor_LDADD = $(RPM_LIBS) $(EXPAT_LIBS) $(CURL_LIBS) $(top_builddir)/librazor/librazor.la + +rpm_SOURCES = rpm.c +rpm_LDADD = $(top_builddir)/librazor/librazor.la + +clean-local : + rm -f *~ + diff --git a/src/import-rpmdb.c b/src/import-rpmdb.c new file mode 100644 index 0000000..ddfed9e --- /dev/null +++ b/src/import-rpmdb.c @@ -0,0 +1,157 @@ +/* + * Copyright (C) 2008 Kristian Høgsberg + * Copyright (C) 2008 Red Hat, Inc + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License along + * with this program; if not, write to the Free Software Foundation, Inc., + * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. + */ + +#include +#include +#include +#include +#include +#include + +#include "razor.h" + +union rpm_entry { + void *p; + char *string; + char **list; + uint_32 *flags; + uint_32 integer; +}; + +static enum razor_version_relation +rpm_to_razor_flags (uint_32 flags) +{ + switch (flags & (RPMSENSE_LESS | RPMSENSE_EQUAL | RPMSENSE_GREATER)) { + case RPMSENSE_LESS: + return RAZOR_VERSION_LESS; + case RPMSENSE_LESS|RPMSENSE_EQUAL: + return RAZOR_VERSION_LESS_OR_EQUAL; + case RPMSENSE_EQUAL: + return RAZOR_VERSION_EQUAL; + case RPMSENSE_GREATER|RPMSENSE_EQUAL: + return RAZOR_VERSION_GREATER_OR_EQUAL; + case RPMSENSE_GREATER: + return RAZOR_VERSION_GREATER; + } + + /* FIXME? */ + return RAZOR_VERSION_EQUAL; +} + +static void +add_properties(struct razor_importer *importer, + enum razor_property_type property_type, + Header h, int_32 name_tag, int_32 version_tag, int_32 flags_tag) +{ + union rpm_entry names, versions, flags; + int_32 i, type, count; + + headerGetEntry(h, name_tag, &type, &names.p, &count); + headerGetEntry(h, version_tag, &type, &versions.p, &count); + headerGetEntry(h, flags_tag, &type, &flags.p, &count); + + for (i = 0; i < count; i++) + razor_importer_add_property(importer, + names.list[i], + rpm_to_razor_flags (flags.flags[i]), + versions.list[i], + property_type); +} + +struct razor_set * +razor_set_create_from_rpmdb(void) +{ + struct razor_importer *importer; + rpmdbMatchIterator iter; + Header h; + int_32 type, count, i; + union rpm_entry name, epoch, version, release, arch; + union rpm_entry basenames, dirnames, dirindexes; + char filename[PATH_MAX], evr[128], buf[16]; + rpmdb db; + + rpmReadConfigFiles(NULL, NULL); + + if (rpmdbOpen("", &db, O_RDONLY, 0644) != 0) { + fprintf(stderr, "cannot open rpm database\n"); + exit(1); + } + + importer = razor_importer_new(); + + iter = rpmdbInitIterator(db, 0, NULL, 0); + while (h = rpmdbNextIterator(iter), h != NULL) { + headerGetEntry(h, RPMTAG_NAME, &type, &name.p, &count); + headerGetEntry(h, RPMTAG_EPOCH, &type, &epoch.p, &count); + headerGetEntry(h, RPMTAG_VERSION, &type, &version.p, &count); + headerGetEntry(h, RPMTAG_RELEASE, &type, &release.p, &count); + headerGetEntry(h, RPMTAG_ARCH, &type, &arch.p, &count); + + if (epoch.flags != NULL) { + snprintf(buf, sizeof buf, "%u", *epoch.flags); + razor_build_evr(evr, sizeof evr, + buf, version.string, release.string); + } else { + razor_build_evr(evr, sizeof evr, + NULL, version.string, release.string); + } + + razor_importer_begin_package(importer, + name.string, evr, arch.string); + + add_properties(importer, RAZOR_PROPERTY_REQUIRES, h, + RPMTAG_REQUIRENAME, + RPMTAG_REQUIREVERSION, + RPMTAG_REQUIREFLAGS); + + add_properties(importer, RAZOR_PROPERTY_PROVIDES, h, + RPMTAG_PROVIDENAME, + RPMTAG_PROVIDEVERSION, + RPMTAG_PROVIDEFLAGS); + + add_properties(importer, RAZOR_PROPERTY_OBSOLETES, h, + RPMTAG_OBSOLETENAME, + RPMTAG_OBSOLETEVERSION, + RPMTAG_OBSOLETEFLAGS); + + add_properties(importer, RAZOR_PROPERTY_CONFLICTS, h, + RPMTAG_CONFLICTNAME, + RPMTAG_CONFLICTVERSION, + RPMTAG_CONFLICTFLAGS); + + headerGetEntry(h, RPMTAG_BASENAMES, &type, + &basenames.p, &count); + headerGetEntry(h, RPMTAG_DIRNAMES, &type, + &dirnames.p, &count); + headerGetEntry(h, RPMTAG_DIRINDEXES, &type, + &dirindexes.p, &count); + for (i = 0; i < count; i++) { + snprintf(filename, sizeof filename, "%s%s", + dirnames.list[dirindexes.flags[i]], + basenames.list[i]); + razor_importer_add_file(importer, filename); + } + + razor_importer_finish_package(importer); + } + + rpmdbClose(db); + + return razor_importer_finish(importer); +} diff --git a/src/import-yum.c b/src/import-yum.c new file mode 100644 index 0000000..c461a15 --- /dev/null +++ b/src/import-yum.c @@ -0,0 +1,337 @@ +/* + * Copyright (C) 2008 Kristian Høgsberg + * Copyright (C) 2008 Red Hat, Inc + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License along + * with this program; if not, write to the Free Software Foundation, Inc., + * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. + */ + +#define _GNU_SOURCE + +#include +#include +#include +#include +#include +#include +#include + +#include +#include +#include "razor.h" + +/* Import a yum filelist as a razor package set. */ + +enum { + YUM_STATE_BEGIN, + YUM_STATE_PACKAGE_NAME, + YUM_STATE_PACKAGE_ARCH, + YUM_STATE_CHECKSUM, + YUM_STATE_REQUIRES, + YUM_STATE_PROVIDES, + YUM_STATE_OBSOLETES, + YUM_STATE_CONFLICTS, + YUM_STATE_FILE +}; + +struct yum_context { + XML_Parser primary_parser; + XML_Parser filelists_parser; + XML_Parser current_parser; + + struct razor_importer *importer; + struct import_property_context *current_property_context; + char name[256], arch[64], buffer[512], *p; + char pkgid[128]; + int state; +}; + +static enum razor_version_relation +yum_to_razor_flags (const char *flags) +{ + /* FIXME? */ + if (!flags) + return RAZOR_VERSION_EQUAL; + + if (flags[0] == 'L') { + if (flags[1] == 'T') + return RAZOR_VERSION_LESS; + else + return RAZOR_VERSION_LESS_OR_EQUAL; + } else if (flags[0] == 'G') { + if (flags[1] == 'T') + return RAZOR_VERSION_GREATER; + else + return RAZOR_VERSION_GREATER_OR_EQUAL; + } else + return RAZOR_VERSION_EQUAL; +} + +static void +yum_primary_start_element(void *data, const char *name, const char **atts) +{ + struct yum_context *ctx = data; + const char *n, *epoch, *version, *release, *flags; + char buffer[128]; + int i; + + if (strcmp(name, "name") == 0) { + ctx->state = YUM_STATE_PACKAGE_NAME; + ctx->p = ctx->name; + } else if (strcmp(name, "arch") == 0) { + ctx->state = YUM_STATE_PACKAGE_ARCH; + ctx->p = ctx->arch; + } else if (strcmp(name, "version") == 0) { + epoch = NULL; + version = NULL; + release = NULL; + for (i = 0; atts[i]; i += 2) { + if (strcmp(atts[i], "epoch") == 0) + epoch = atts[i + 1]; + else if (strcmp(atts[i], "ver") == 0) + version = atts[i + 1]; + else if (strcmp(atts[i], "rel") == 0) + release = atts[i + 1]; + } + if (version == NULL || release == NULL) { + fprintf(stderr, "invalid version tag, " + "missing version or release attribute\n"); + return; + } + + razor_build_evr(buffer, sizeof buffer, epoch, version, release); + razor_importer_begin_package(ctx->importer, + ctx->name, buffer, ctx->arch); + } else if (strcmp(name, "checksum") == 0) { + ctx->p = ctx->pkgid; + ctx->state = YUM_STATE_CHECKSUM; + } else if (strcmp(name, "rpm:requires") == 0) { + ctx->state = YUM_STATE_REQUIRES; + } else if (strcmp(name, "rpm:provides") == 0) { + ctx->state = YUM_STATE_PROVIDES; + } else if (strcmp(name, "rpm:obsoletes") == 0) { + ctx->state = YUM_STATE_OBSOLETES; + } else if (strcmp(name, "rpm:conflicts") == 0) { + ctx->state = YUM_STATE_CONFLICTS; + } else if (strcmp(name, "rpm:entry") == 0 && + ctx->state != YUM_STATE_BEGIN) { + n = NULL; + epoch = NULL; + version = NULL; + release = NULL; + flags = NULL; + for (i = 0; atts[i]; i += 2) { + if (strcmp(atts[i], "name") == 0) + n = atts[i + 1]; + else if (strcmp(atts[i], "epoch") == 0) + epoch = atts[i + 1]; + else if (strcmp(atts[i], "ver") == 0) + version = atts[i + 1]; + else if (strcmp(atts[i], "rel") == 0) + release = atts[i + 1]; + else if (strcmp(atts[i], "flags") == 0) + flags = atts[i + 1]; + } + + if (n == NULL) { + fprintf(stderr, "invalid rpm:entry, " + "missing name or version attributes\n"); + return; + } + + razor_build_evr(buffer, sizeof buffer, epoch, version, release); + switch (ctx->state) { + case YUM_STATE_REQUIRES: + razor_importer_add_property(ctx->importer, n, + yum_to_razor_flags (flags), + buffer, + RAZOR_PROPERTY_REQUIRES); + break; + case YUM_STATE_PROVIDES: + razor_importer_add_property(ctx->importer, n, + yum_to_razor_flags (flags), + buffer, + RAZOR_PROPERTY_PROVIDES); + break; + case YUM_STATE_OBSOLETES: + razor_importer_add_property(ctx->importer, n, + yum_to_razor_flags (flags), + buffer, + RAZOR_PROPERTY_OBSOLETES); + break; + case YUM_STATE_CONFLICTS: + razor_importer_add_property(ctx->importer, n, + yum_to_razor_flags (flags), + buffer, + RAZOR_PROPERTY_CONFLICTS); + break; + } + } +} + +static void +yum_primary_end_element (void *data, const char *name) +{ + struct yum_context *ctx = data; + + switch (ctx->state) { + case YUM_STATE_PACKAGE_NAME: + case YUM_STATE_PACKAGE_ARCH: + case YUM_STATE_CHECKSUM: + case YUM_STATE_FILE: + ctx->state = YUM_STATE_BEGIN; + break; + } + + if (strcmp(name, "package") == 0) { + XML_StopParser(ctx->current_parser, XML_TRUE); + ctx->current_parser = ctx->filelists_parser; + } +} + +static void +yum_character_data (void *data, const XML_Char *s, int len) +{ + struct yum_context *ctx = data; + + switch (ctx->state) { + case YUM_STATE_PACKAGE_NAME: + case YUM_STATE_PACKAGE_ARCH: + case YUM_STATE_CHECKSUM: + case YUM_STATE_FILE: + memcpy(ctx->p, s, len); + ctx->p += len; + *ctx->p = '\0'; + break; + } +} + +static void +yum_filelists_start_element(void *data, const char *name, const char **atts) +{ + struct yum_context *ctx = data; + const char *pkg, *pkgid; + int i; + + if (strcmp(name, "package") == 0) { + pkg = NULL; + pkgid = NULL; + for (i = 0; atts[i]; i += 2) { + if (strcmp(atts[i], "name") == 0) + pkg = atts[i + 1]; + else if (strcmp(atts[i], "pkgid") == 0) + pkgid = atts[i + 1]; + } + if (strcmp(pkgid, ctx->pkgid) != 0) + fprintf(stderr, "primary.xml and filelists.xml " + "mismatch for %s: %s vs %s", + pkg, pkgid, ctx->pkgid); + } else if (strcmp(name, "file") == 0) { + ctx->state = YUM_STATE_FILE; + ctx->p = ctx->buffer; + } +} + + +static void +yum_filelists_end_element (void *data, const char *name) +{ + struct yum_context *ctx = data; + + ctx->state = YUM_STATE_BEGIN; + if (strcmp(name, "package") == 0) { + XML_StopParser(ctx->current_parser, XML_TRUE); + ctx->current_parser = ctx->primary_parser; + razor_importer_finish_package(ctx->importer); + } else if (strcmp(name, "file") == 0) + razor_importer_add_file(ctx->importer, ctx->buffer); + +} + +#define XML_BUFFER_SIZE 4096 + +struct razor_set * +razor_set_create_from_yum(void) +{ + struct yum_context ctx; + void *buf; + int len, ret; + gzFile primary, filelists; + XML_ParsingStatus status; + + ctx.importer = razor_importer_new(); + ctx.state = YUM_STATE_BEGIN; + + ctx.primary_parser = XML_ParserCreate(NULL); + XML_SetUserData(ctx.primary_parser, &ctx); + XML_SetElementHandler(ctx.primary_parser, + yum_primary_start_element, + yum_primary_end_element); + XML_SetCharacterDataHandler(ctx.primary_parser, + yum_character_data); + + ctx.filelists_parser = XML_ParserCreate(NULL); + XML_SetUserData(ctx.filelists_parser, &ctx); + XML_SetElementHandler(ctx.filelists_parser, + yum_filelists_start_element, + yum_filelists_end_element); + XML_SetCharacterDataHandler(ctx.filelists_parser, + yum_character_data); + + primary = gzopen("primary.xml.gz", "rb"); + if (primary == NULL) + return NULL; + filelists = gzopen("filelists.xml.gz", "rb"); + if (filelists == NULL) + return NULL; + + ctx.current_parser = ctx.primary_parser; + + do { + XML_GetParsingStatus(ctx.current_parser, &status); + switch (status.parsing) { + case XML_SUSPENDED: + ret = XML_ResumeParser(ctx.current_parser); + break; + case XML_PARSING: + case XML_INITIALIZED: + buf = XML_GetBuffer(ctx.current_parser, + XML_BUFFER_SIZE); + if (ctx.current_parser == ctx.primary_parser) + len = gzread(primary, buf, XML_BUFFER_SIZE); + else + len = gzread(filelists, buf, XML_BUFFER_SIZE); + if (len < 0) { + fprintf(stderr, + "couldn't read input: %s\n", + strerror(errno)); + return NULL; + } + + XML_ParseBuffer(ctx.current_parser, len, len == 0); + break; + case XML_FINISHED: + break; + } + } while (status.parsing != XML_FINISHED); + + + XML_ParserFree(ctx.primary_parser); + XML_ParserFree(ctx.filelists_parser); + + gzclose(primary); + gzclose(filelists); + + return razor_importer_finish(ctx.importer); +} diff --git a/src/main.c b/src/main.c new file mode 100644 index 0000000..772231b --- /dev/null +++ b/src/main.c @@ -0,0 +1,804 @@ +/* + * Copyright (C) 2008 Kristian Høgsberg + * Copyright (C) 2008 Red Hat, Inc + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License along + * with this program; if not, write to the Free Software Foundation, Inc., + * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. + */ + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include "razor.h" + +static const char system_repo_filename[] = "system.repo"; +static const char next_repo_filename[] = "system-next.repo"; +static const char rawhide_repo_filename[] = "rawhide.repo"; +static const char updated_repo_filename[] = "system-updated.repo"; +static const char install_root[] = "install"; +static const char *repo_filename = system_repo_filename; +static const char *yum_url; + +static int +command_list(int argc, const char *argv[]) +{ + struct razor_set *set; + struct razor_package_iterator *pi; + struct razor_package *package; + const char *pattern, *name, *version, *arch; + int only_names = 0, i = 0; + + if (i < argc && strcmp(argv[i], "--only-names") == 0) { + only_names = 1; + i++; + } + + pattern = argv[i]; + set = razor_set_open(repo_filename); + pi = razor_package_iterator_create(set); + while (razor_package_iterator_next(pi, &package, + &name, &version, &arch)) { + if (pattern && fnmatch(pattern, name, 0) != 0) + continue; + + if (only_names) + printf("%s\n", name); + else + printf("%s-%s.%s\n", name, version, arch); + } + razor_package_iterator_destroy(pi); + razor_set_destroy(set); + + return 0; +} + +static int +list_properties(const char *package_name, + enum razor_property_type required_type) +{ + static const char *relation_string[] = { "<", "<=", "=", ">=", ">" }; + struct razor_set *set; + struct razor_property *property; + struct razor_package *package; + struct razor_property_iterator *pi; + const char *name, *version; + enum razor_property_type type; + enum razor_version_relation relation; + + set = razor_set_open(repo_filename); + if (package_name) + package = razor_set_get_package(set, package_name); + else + package = NULL; + + pi = razor_property_iterator_create(set, package); + while (razor_property_iterator_next(pi, &property, + &name, &relation, &version, + &type)) { + if (type != required_type) + continue; + if (version[0] == '\0') + printf("%s\n", name); + else + printf("%s %s %s\n", name, + relation_string[relation], version); + } + razor_property_iterator_destroy(pi); + + razor_set_destroy(set); + + return 0; +} + +static int +command_list_requires(int argc, const char *argv[]) +{ + return list_properties(argv[0], RAZOR_PROPERTY_REQUIRES); +} + +static int +command_list_provides(int argc, const char *argv[]) +{ + return list_properties(argv[0], RAZOR_PROPERTY_PROVIDES); +} + +static int +command_list_obsoletes(int argc, const char *argv[]) +{ + return list_properties(argv[0], RAZOR_PROPERTY_OBSOLETES); +} + +static int +command_list_conflicts(int argc, const char *argv[]) +{ + return list_properties(argv[0], RAZOR_PROPERTY_CONFLICTS); +} + +static int +command_list_files(int argc, const char *argv[]) +{ + struct razor_set *set; + + set = razor_set_open(repo_filename); + if (set == NULL) + return 1; + razor_set_list_files(set, argv[0]); + razor_set_destroy(set); + + return 0; +} + +static int +command_list_file_packages(int argc, const char *argv[]) +{ + struct razor_set *set; + struct razor_package_iterator *pi; + struct razor_package *package; + const char *name, *version, *arch; + + set = razor_set_open(repo_filename); + if (set == NULL) + return 1; + + pi = razor_package_iterator_create_for_file(set, argv[0]); + while (razor_package_iterator_next(pi, &package, + &name, &version, &arch)) + printf("%s-%s\n", name, version); + razor_package_iterator_destroy(pi); + + razor_set_destroy(set); + + return 0; +} + +static int +command_list_package_files(int argc, const char *argv[]) +{ + struct razor_set *set; + + set = razor_set_open(repo_filename); + if (set == NULL) + return 1; + razor_set_list_package_files(set, argv[0]); + razor_set_destroy(set); + + return 0; +} + +static void +list_packages_for_property(struct razor_set *set, + struct razor_property *property) +{ + struct razor_package_iterator *pi; + struct razor_package *package; + const char *name, *version, *arch; + + pi = razor_package_iterator_create_for_property(set, property); + while (razor_package_iterator_next(pi, &package, + &name, &version, &arch)) + printf("%s-%s.%s\n", name, version, arch); + razor_package_iterator_destroy(pi); +} + +static int +list_property_packages(const char *ref_name, + const char *ref_version, + enum razor_property_type ref_type) +{ + struct razor_set *set; + struct razor_property *property; + struct razor_property_iterator *pi; + const char *name, *version; + enum razor_property_type type; + enum razor_version_relation relation; + + if (ref_name == NULL) + return 0; + + set = razor_set_open(repo_filename); + if (set == NULL) + return 1; + + pi = razor_property_iterator_create(set, NULL); + while (razor_property_iterator_next(pi, &property, + &name, &relation, &version, + &type)) { + if (strcmp(ref_name, name) != 0) + continue; + if (ref_version && relation == RAZOR_VERSION_EQUAL && + strcmp(ref_version, version) != 0) + continue; + if (ref_type != type) + continue; + + list_packages_for_property(set, property); + } + razor_property_iterator_destroy(pi); + + return 0; +} + +static int +command_what_requires(int argc, const char *argv[]) +{ + return list_property_packages(argv[0], argv[1], + RAZOR_PROPERTY_REQUIRES); +} + +static int +command_what_provides(int argc, const char *argv[]) +{ + return list_property_packages(argv[0], argv[1], + RAZOR_PROPERTY_PROVIDES); +} + +static int +show_progress(void *clientp, + double dltotal, double dlnow, double ultotal, double ulnow) +{ + const char *file = clientp; + + if (!dlnow < dltotal) + fprintf(stderr, "\rdownloading %s, %dkB/%dkB", + file, (int) dlnow / 1024, (int) dltotal / 1024); + + return 0; +} + +static int +download_if_missing(const char *url, const char *file) +{ + CURL *curl; + struct stat buf; + char error[256]; + FILE *fp; + CURLcode res; + long response; + + curl = curl_easy_init(); + if (curl == NULL) + return 1; + + curl_easy_setopt(curl, CURLOPT_ERRORBUFFER, error); + curl_easy_setopt(curl, CURLOPT_NOPROGRESS, 0); + curl_easy_setopt(curl, CURLOPT_PROGRESSFUNCTION, show_progress); + curl_easy_setopt(curl, CURLOPT_PROGRESSDATA, file); + + if (stat(file, &buf) < 0) { + fp = fopen(file, "w"); + if (fp == NULL) { + fprintf(stderr, + "failed to open %s for writing\n", file); + return -1; + } + curl_easy_setopt(curl, CURLOPT_WRITEDATA, fp); + curl_easy_setopt(curl, CURLOPT_URL, url); + res = curl_easy_perform(curl); + fclose(fp); + if (res != CURLE_OK) { + fprintf(stderr, "curl error: %s\n", error); + unlink(file); + return -1; + } + res = curl_easy_getinfo(curl, + CURLINFO_RESPONSE_CODE, &response); + if (res != CURLE_OK) { + fprintf(stderr, "curl error: %s\n", error); + unlink(file); + return -1; + } + if (response != 200) { + fprintf(stderr, " - failed %ld\n", response); + unlink(file); + return -1; + } + fprintf(stderr, "\n"); + } + + curl_easy_cleanup(curl); + + return 0; +} + +#define YUM_URL "http://download.fedora.redhat.com" \ + "/pub/fedora/linux/development/i386/os" + +static int +command_import_yum(int argc, const char *argv[]) +{ + struct razor_set *set; + char buffer[512]; + + printf("downloading from %s.\n", yum_url); + snprintf(buffer, sizeof buffer, + "%s/repodata/primary.xml.gz", yum_url); + if (download_if_missing(buffer, "primary.xml.gz") < 0) + return -1; + snprintf(buffer, sizeof buffer, + "%s/repodata/filelists.xml.gz", yum_url); + if (download_if_missing(buffer, "filelists.xml.gz") < 0) + return -1; + + set = razor_set_create_from_yum(); + if (set == NULL) + return 1; + razor_set_write(set, rawhide_repo_filename); + razor_set_destroy(set); + printf("wrote %s\n", rawhide_repo_filename); + + return 0; +} + +static int +command_import_rpmdb(int argc, const char *argv[]) +{ + struct razor_set *set; + + set = razor_set_create_from_rpmdb(); + if (set == NULL) + return 1; + razor_set_write(set, repo_filename); + razor_set_destroy(set); + printf("wrote %s\n", repo_filename); + + return 0; +} + +static int +mark_packages_for_update(struct razor_transaction *trans, + struct razor_set *set, const char *pattern) +{ + struct razor_package_iterator *pi; + struct razor_package *package; + const char *name, *version, *arch; + int matches = 0; + + pi = razor_package_iterator_create(set); + while (razor_package_iterator_next(pi, &package, + &name, &version, &arch)) { + if (pattern && fnmatch(pattern, name, 0) == 0) { + razor_transaction_update_package(trans, package); + matches++; + } + } + razor_package_iterator_destroy(pi); + + return matches; +} + +static int +mark_packages_for_removal(struct razor_transaction *trans, + struct razor_set *set, const char *pattern) +{ + struct razor_package_iterator *pi; + struct razor_package *package; + const char *name, *version, *arch; + int matches = 0; + + pi = razor_package_iterator_create(set); + while (razor_package_iterator_next(pi, &package, + &name, &version, &arch)) { + if (pattern && fnmatch(pattern, name, 0) == 0) { + razor_transaction_remove_package(trans, package); + matches++; + } + } + razor_package_iterator_destroy(pi); + + return matches; +} + +static int +command_update(int argc, const char *argv[]) +{ + struct razor_set *set, *upstream; + struct razor_transaction *trans; + int i, errors; + + set = razor_set_open(repo_filename); + upstream = razor_set_open(rawhide_repo_filename); + if (set == NULL || upstream == NULL) + return 1; + + trans = razor_transaction_create(set, upstream); + if (argc == 0) + razor_transaction_update_all(trans); + for (i = 0; i < argc; i++) { + if (mark_packages_for_update(trans, set, argv[i]) == 0) { + fprintf(stderr, "no match for %s\n", argv[i]); + return 1; + } + } + + errors = razor_transaction_resolve(trans); + if (errors) + return 1; + + set = razor_transaction_finish(trans); + razor_set_write(set, updated_repo_filename); + razor_set_destroy(set); + razor_set_destroy(upstream); + printf("wrote system-updated.repo\n"); + + return 0; +} + +static int +command_remove(int argc, const char *argv[]) +{ + struct razor_set *set, *upstream; + struct razor_transaction *trans; + int i, errors; + + set = razor_set_open(repo_filename); + if (set == NULL) + return 1; + + upstream = razor_set_create(); + trans = razor_transaction_create(set, upstream); + for (i = 0; i < argc; i++) { + if (mark_packages_for_removal(trans, set, argv[i]) == 0) { + fprintf(stderr, "no match for %s\n", argv[i]); + return 1; + } + } + + errors = razor_transaction_resolve(trans); + if (errors) + return 1; + + set = razor_transaction_finish(trans); + razor_set_write(set, updated_repo_filename); + razor_set_destroy(set); + razor_set_destroy(upstream); + printf("wrote system-updated.repo\n"); + + return 0; +} + +static void +print_diff(const char *name, + const char *old_version, const char *new_version, const char *arch, + void *data) +{ + if (old_version) + printf("removing %s %s\n", name, old_version); + else + printf("install %s %s\n", name, new_version); +} + +static int +command_diff(int argc, const char *argv[]) +{ + struct razor_set *set, *updated; + + set = razor_set_open(repo_filename); + updated = razor_set_open(updated_repo_filename); + if (set == NULL || updated == NULL) + return 1; + + razor_set_diff(set, updated, print_diff, NULL); + + razor_set_destroy(set); + razor_set_destroy(updated); + + return 0; +} + +static int +command_import_rpms(int argc, const char *argv[]) +{ + DIR *dir; + struct dirent *de; + struct razor_importer *importer; + struct razor_set *set; + struct razor_rpm *rpm; + int len; + char filename[256]; + const char *dirname = argv[0]; + + if (dirname == NULL) { + fprintf(stderr, "usage: razor import-rpms DIR\n"); + return -1; + } + + dir = opendir(dirname); + if (dir == NULL) { + fprintf(stderr, "couldn't read dir %s\n", dirname); + return -1; + } + + importer = razor_importer_new(); + + while (de = readdir(dir), de != NULL) { + len = strlen(de->d_name); + if (len < 5 || strcmp(de->d_name + len - 4, ".rpm") != 0) + continue; + snprintf(filename, sizeof filename, + "%s/%s", dirname, de->d_name); + rpm = razor_rpm_open(filename); + if (rpm == NULL) { + fprintf(stderr, + "failed to open rpm \"%s\"\n", filename); + continue; + } + if (razor_importer_add_rpm(importer, rpm)) { + fprintf(stderr, "couldn't import %s\n", filename); + break; + } + razor_rpm_close(rpm); + } + + if (de != NULL) { + razor_importer_destroy(importer); + return -1; + } + + set = razor_importer_finish(importer); + + razor_set_write(set, repo_filename); + razor_set_destroy(set); + printf("wrote %s\n", repo_filename); + + return 0; +} + +static void +download_package(const char *name, + const char *old_version, + const char *new_version, + const char *arch, + void *data) +{ + char file[PATH_MAX], url[256]; + const char *v; + int *errors = data; + + if (old_version) + return; + + /* Skip epoch */ + v = strchr(new_version, ':'); + if (v != NULL) + v = v + 1; + else + v = new_version; + + snprintf(url, sizeof url, + "%s/Packages/%s-%s.%s.rpm", yum_url, name, v, arch); + snprintf(file, sizeof file, + "rpms/%s-%s.%s.rpm", name, v, arch); + if (download_if_missing(url, file) < 0) + (*errors)++; +} + +static void +install_package(const char *name, + const char *old_version, + const char *new_version, + const char *arch, + void *data) +{ + const char *v, *root = data; + char file[PATH_MAX]; + struct razor_rpm *rpm; + + if (old_version) { + printf("removing %s %s not handled\n", name, old_version); + return; + } + + /* Skip epoch */ + v = strchr(new_version, ':'); + if (v != NULL) + v = v + 1; + else + v = new_version; + + printf("install %s %s\n", name, v); + snprintf(file, sizeof file, "rpms/%s-%s.%s.rpm", name, v, arch); + + rpm = razor_rpm_open(file); + if (rpm == NULL) { + fprintf(stderr, "failed to open rpm %s\n", file); + return; + } + if (razor_rpm_install(rpm, root) < 0) { + fprintf(stderr, + "failed to install rpm %s\n", file); + return; + } + razor_rpm_close(rpm); +} + +static int +command_install(int argc, const char *argv[]) +{ + struct razor_root *root; + struct razor_set *upstream, *next; + struct razor_transaction *trans; + int i = 0, errors, dependencies = 1; + + if (i < argc && strcmp(argv[i], "--no-dependencies") == 0) { + dependencies = 0; + i++; + } + + root = razor_root_open(install_root, RAZOR_ROOT_OPEN_WRITE); + upstream = razor_set_open(rawhide_repo_filename); + trans = razor_root_create_transaction(root, upstream); + + for (; i < argc; i++) { + if (mark_packages_for_update(trans, upstream, argv[i]) == 0) { + fprintf(stderr, "no package matched %s\n", argv[i]); + razor_root_close(root); + return 1; + } + } + + if (dependencies) { + errors = razor_transaction_resolve(trans); + if (errors) { + razor_root_close(root); + return 1; + } + } + + next = razor_transaction_finish(trans); + + razor_root_update(root, next); + + if (mkdir("rpms", 0777) && errno != EEXIST) { + fprintf(stderr, "failed to create rpms directory.\n"); + razor_root_close(root); + return 1; + } + + razor_root_diff(root, download_package, &errors); + if (errors > 0) { + fprintf(stderr, "failed to download %d packages\n", errors); + razor_root_close(root); + return 1; + } + + /* FIXME: We need to figure out the right install order here, + * so the post and pre scripts can run. */ + razor_root_diff(root, install_package, (void *) root); + + razor_set_destroy(next); + razor_set_destroy(upstream); + + return razor_root_commit(root); +} + +static int +command_init(int argc, const char *argv[]) +{ + return razor_root_create(install_root); +} + +static int +command_download(int argc, const char *argv[]) +{ + struct razor_set *set; + struct razor_package_iterator *pi; + struct razor_package *package; + const char *pattern = argv[0], *name, *version, *arch; + char url[256], file[256]; + int matches = 0; + + if (mkdir("rpms", 0777) && errno != EEXIST) { + fprintf(stderr, "failed to create rpms directory.\n"); + return 1; + } + + set = razor_set_open(rawhide_repo_filename); + pi = razor_package_iterator_create(set); + while (razor_package_iterator_next(pi, &package, + &name, &version, &arch)) { + if (pattern && fnmatch(pattern, name, 0) != 0) + continue; + + matches++; + snprintf(url, sizeof url, + "%s/Packages/%s-%s.%s.rpm", + yum_url, name, version, arch); + snprintf(file, sizeof file, + "rpms/%s-%s.%s.rpm", name, version, arch); + download_if_missing(url, file); + } + razor_package_iterator_destroy(pi); + razor_set_destroy(set); + + if (matches == 0) + fprintf(stderr, "no packages matched \"%s\"\n", pattern); + else if (matches == 1) + fprintf(stderr, "downloaded 1 package\n"); + else + fprintf(stderr, "downloaded %d packages\n", matches); + + return 0; +} + +static struct { + const char *name; + const char *description; + int (*func)(int argc, const char *argv[]); +} razor_commands[] = { + { "list", "list all packages", command_list }, + { "list-requires", "list all requires for the given package", command_list_requires }, + { "list-provides", "list all provides for the given package", command_list_provides }, + { "list-obsoletes", "list all obsoletes for the given package", command_list_obsoletes }, + { "list-conflicts", "list all conflicts for the given package", command_list_conflicts }, + { "list-files", "list files for package set", command_list_files }, + { "list-file-packages", "list packages owning file", command_list_file_packages }, + { "list-package-files", "list files in package", command_list_package_files }, + { "what-requires", "list the packages that have the given requires", command_what_requires }, + { "what-provides", "list the packages that have the given provides", command_what_provides }, + { "import-yum", "import yum metadata files", command_import_yum }, + { "import-rpmdb", "import the system rpm database", command_import_rpmdb }, + { "import-rpms", "import rpms from the given directory", command_import_rpms }, + { "update", "update all or specified packages", command_update }, + { "remove", "remove specified packages", command_remove }, + { "diff", "show diff between two package sets", command_diff }, + { "install", "install rpm", command_install }, + { "init", "init razor root", command_init }, + { "download", "download packages", command_download } +}; + +static int +usage(void) +{ + int i; + + printf("usage:\n"); + for (i = 0; i < ARRAY_SIZE(razor_commands); i++) + printf(" %-20s%s\n", + razor_commands[i].name, razor_commands[i].description); + + return 1; +} + +int +main(int argc, const char *argv[]) +{ + char *repo; + int i; + + repo = getenv("RAZOR_REPO"); + if (repo != NULL) + repo_filename = repo; + + yum_url = getenv("YUM_URL"); + if (yum_url == NULL) + yum_url = YUM_URL; + + if (argc < 2) + return usage(); + + for (i = 0; i < ARRAY_SIZE(razor_commands); i++) + if (strcmp(razor_commands[i].name, argv[1]) == 0) + return razor_commands[i].func(argc - 2, argv + 2); + + return usage(); +} diff --git a/src/rpm.c b/src/rpm.c new file mode 100644 index 0000000..6a3ea80 --- /dev/null +++ b/src/rpm.c @@ -0,0 +1,897 @@ +/* + * Copyright (C) 2008 Kristian Høgsberg + * Copyright (C) 2008 Red Hat, Inc + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License along + * with this program; if not, write to the Free Software Foundation, Inc., + * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. + */ + +#include +#include +#include +#include +#include "razor.h" + +enum option_type { + OPTION_LAST, + OPTION_GROUP, + OPTION_BOOL, + OPTION_STRING +}; + +struct option { + enum option_type type; + const char *name; + char short_name; + const char *arg_name; + const char *description; + void *data; +}; + +/* A note about all these options: rpm allows options to mean + * different things depending on what other options are present on the + * command line. For example, if -q or --query is present, -i no + * longer means install, but info. The way we handle this is by + * setting all the options that may match (ie if -i is given we set + * install and info), and then look at the relevent one depending on + * what else in on the command line. */ + +static int option_all, option_whatrequires, option_whatprovides; +static int option_package; + +static const struct option query_options[] = { + { OPTION_BOOL, "configfiles", 'c', NULL, "list all configuration files", NULL }, + { OPTION_BOOL, "docfiles", 'd', NULL, "list all documentation files", NULL }, + { OPTION_BOOL, "dump", 0, NULL, "dump basic file information", NULL }, + { OPTION_BOOL, "list", 0, NULL, "list files in package", NULL }, + { OPTION_STRING, "queryformat", 0, "QUERYFORMAT", "use the following query format", NULL }, + { OPTION_BOOL, "state", 's', NULL, "display the states of the listed files", NULL }, + { OPTION_BOOL, "all", 'a', NULL, "query/verify all packages", &option_all }, + { OPTION_BOOL, "file", 'f', NULL, "query/verify package(s) owning file", NULL }, + { OPTION_BOOL, "group", 'g', NULL, "query/verify package(s) in group", NULL }, + { OPTION_BOOL, "package", 'p', NULL, "query/verify a package file", &option_package }, + { OPTION_BOOL, "ftswalk", 'W', NULL, "query/verify package(s) from TOP file tree walk", NULL }, + { OPTION_BOOL, "pkgid", 0, NULL, "query/verify package(s) with package identifier", NULL }, + { OPTION_BOOL, "hdrid", 0, NULL, "query/verify package(s) with header identifier", NULL }, + { OPTION_BOOL, "fileid", 0, NULL, "query/verify package(s) with file identifier", NULL }, + { OPTION_BOOL, "specfile", 0, NULL, "query a spec file", NULL, }, + { OPTION_BOOL, "triggeredby", 0, NULL, "query the package(s) triggered by the package", NULL }, + { OPTION_BOOL, "whatrequires", 0, NULL, "query/verify the package(s) which require a dependency", &option_whatrequires }, + { OPTION_BOOL, "whatprovides", 0, NULL, "query/verify the package(s) which provide a dependency", &option_whatprovides }, + { OPTION_BOOL, "nomanifest", 0, NULL, "do not process non-package files as manifests", NULL }, + { } +}; + +static int option_nodeps; + +static const struct option verify_options[] = { + { OPTION_BOOL, "nomd5", 0, NULL, "don't verify MD5 digest of files", NULL }, + { OPTION_BOOL, "nofiles", 0, NULL, "don't verify files in package", NULL }, + { OPTION_BOOL, "nodeps", 0, NULL, "don't verify package dependencies", &option_nodeps }, + { OPTION_BOOL, "noscript", 0, NULL, "don't execute verify script(s)", NULL, }, + { OPTION_BOOL, "all", 'a', NULL, "query/verify all packages", &option_all }, + { OPTION_BOOL, "file", 'f', NULL, "query/verify package(s) owning file", NULL }, + { OPTION_BOOL, "group", 'g', NULL, "query/verify package(s) in group", NULL }, + { OPTION_BOOL, "package", 'p', NULL, "query/verify a package file", &option_package }, + { OPTION_BOOL, "ftswalk", 'W', NULL, "query/verify package(s) from TOP file tree walk", NULL }, + { OPTION_BOOL, "pkgid", 0, NULL, "query/verify package(s) with package identifier", NULL }, + { OPTION_BOOL, "hdrid", 0, NULL, "query/verify package(s) with header identifier", NULL }, + { OPTION_BOOL, "fileid", 0, NULL, "query/verify package(s) with file identifier", NULL }, + { OPTION_BOOL, "specfile", 0, NULL, "query a spec file", NULL }, + { OPTION_BOOL, "triggeredby", 0, NULL, "query the package(s) triggered by the package", NULL }, + { OPTION_BOOL, "whatrequires", 0, NULL, "query/verify the package(s) which require a dependency", &option_whatrequires }, + { OPTION_BOOL, "whatprovides", 0, NULL, "query/verify the package(s) which provide a dependency", &option_whatprovides }, + { OPTION_BOOL, "nomanifest", 0, NULL, "do not process non-package files as manifests", NULL }, + { } +}; + +static const struct option ftw_options[] = { + { OPTION_BOOL, "comfollow", 0, NULL, "FTS_COMFOLLOW: follow command line symlinks", NULL }, + { OPTION_BOOL, "logical", 0, NULL, "FTS_LOGICAL: logical walk", NULL }, + { OPTION_BOOL, "nochdir", 0, NULL, "FTS_NOCHDIR: don't change directories", NULL }, + { OPTION_BOOL, "nostat", 0, NULL, "FTS_NOSTAT: don't get stat info", NULL }, + { OPTION_BOOL, "physical", 0, NULL, "FTS_PHYSICAL: physical walk", NULL }, + { OPTION_BOOL, "seedot", 0, NULL, "FTS_SEEDOT: return dot and dot-dot", NULL }, + { OPTION_BOOL, "xdev", 0, NULL, "FTS_XDEV: don't cross devices", NULL }, + { OPTION_BOOL, "whiteout", 0, NULL, "FTS_WHITEOUT: return whiteout information", NULL }, + { } +}; + +static const struct option signature_options[] = { + { OPTION_BOOL, "addsign", 0, NULL, "sign package(s) (identical to --resign)", NULL, }, + { OPTION_BOOL, "checksig", 'K', NULL, "verify package signature(s)", NULL, }, + { OPTION_BOOL, "delsign", 0, NULL, "delete package signatures", NULL, }, + { OPTION_BOOL, "import", 0, NULL, "import an armored public key", NULL, }, + { OPTION_BOOL, "resign", 0, NULL, "sign package(s) (identical to --addsign)", NULL, }, + { OPTION_BOOL, "nodigest", 0, NULL, "don't verify package digest(s)", NULL, }, + { OPTION_BOOL, "nosignature", 0, NULL, "don't verify package signature(s)", NULL }, + { } +}; + +static int option_initdb; + +static const struct option database_options[] = { + { OPTION_BOOL, "initdb", 0, NULL, "initialize database", &option_initdb }, + { OPTION_BOOL, "rebuilddb", 0, NULL, "rebuild database inverted lists from installed package headers", NULL }, + { } +}; + +static int option_erase, option_install, option_upgrade, option_justdb; +static int option_test; + +static const struct option install_options[] = { + { OPTION_BOOL, "aid", 0, NULL, "add suggested packages to transaction", NULL, }, + { OPTION_BOOL, "allfiles", 0, NULL, "install all files, even configurations which might otherwise be skipped", NULL, }, + { OPTION_BOOL, "allmatches", 0, NULL, "remove all packages which match (normally an error is generated if specified multiple packages)", NULL, }, + { OPTION_BOOL, "badreloc", 0, NULL, "relocate files in non-relocatable package", NULL }, + { OPTION_BOOL, "erase", 'e', "", "erase (uninstall) package", &option_erase }, + { OPTION_BOOL, "excludedocs", 0, NULL, "do not install documentation", NULL, }, + { OPTION_BOOL, "excludepath", 0, "", "skip files with leading component ", NULL, }, + { OPTION_BOOL, "fileconflicts", 0, NULL, "detect file conflicts between packages", NULL, }, + { OPTION_BOOL, "force", 0, NULL, "short hand for --replacepkgs --replacefiles", NULL }, + { OPTION_BOOL, "freshen", 'F', "+", "upgrade package(s) if already installed", NULL }, + { OPTION_BOOL, "hash", 'h', NULL, "print hash marks as package installs (good with -v)", NULL }, + { OPTION_BOOL, "ignorearch", 0, NULL, "don't verify package architecture", NULL, }, + { OPTION_BOOL, "ignoreos", 0, NULL, "don't verify package operating system", NULL, }, + { OPTION_BOOL, "ignoresize", 0, NULL, "don't check disk space before installing", NULL }, + { OPTION_BOOL, "install", 'i', NULL, "install package(s)", &option_install }, + { OPTION_BOOL, "justdb", 0, NULL, "update the database, but do not modify the filesystem", &option_justdb, }, + { OPTION_BOOL, "nodeps", 0, NULL, "do not verify package dependencies", &option_nodeps, }, + { OPTION_BOOL, "nomd5", 0, NULL, "don't verify MD5 digest of files", NULL, }, + { OPTION_BOOL, "nocontexts", 0, NULL, "don't install file security contexts", NULL, }, + { OPTION_BOOL, "noorder", 0, NULL, "do not reorder package installation to satisfy dependencies", NULL, }, + { OPTION_BOOL, "nosuggest", 0, NULL, "do not suggest missing dependency resolution(s)", NULL, }, + { OPTION_BOOL, "noscripts", 0, NULL, "do not execute package scriptlet(s)", NULL, }, + { OPTION_BOOL, "notriggers", 0, NULL, "do not execute any scriptlet(s) triggered by this package", NULL, }, + { OPTION_BOOL, "oldpackage", 0, NULL, "upgrade to an old version of the package (--force on upgrades does this automatically)", NULL }, + { OPTION_BOOL, "percent", 0, NULL, "print percentages as package installs", NULL, }, + { OPTION_STRING, "prefix", 0, "", "relocate the package to , if relocatable", NULL, }, + { OPTION_STRING, "relocate", 0, "=", "relocate files from path to ", NULL, }, + { OPTION_BOOL, "repackage", 0, NULL, "save erased package files by repackaging", NULL, }, + { OPTION_BOOL, "replacefiles", 0, NULL, "ignore file conflicts between packages", NULL, }, + { OPTION_BOOL, "replacepkgs", 0, NULL, "reinstall if the package is already present", NULL, }, + { OPTION_BOOL, "test", 0, NULL, "don't install, but tell if it would work or not", &option_test }, + { OPTION_BOOL, "upgrade", 'U', "+", "upgrade package(s)", &option_upgrade }, + { } +}; + +static int option_version; +static const char *option_root = "install"; + +static const struct option common_options[] = { + { OPTION_STRING, "define", 'D', "MACRO EXPR", "define MACRO with value EXPR", NULL, }, + { OPTION_STRING, "eval", 'E', "EXPR", "print macro expansion of EXPR", NULL }, + { OPTION_STRING, "macros", 0, "", "read instead of default file(s)", NULL }, + { OPTION_BOOL, "nodigest", 0, NULL, "don't verify package digest(s)", NULL, }, + { OPTION_BOOL, "nosignature", 0, NULL, "don't verify package signature(s)", NULL, }, + { OPTION_STRING, "rcfile", 0, "", "read instead of default file(s)", NULL }, + { OPTION_STRING, "root", 'r', "ROOT", "use ROOT as top level directory (default: \"/\")", &option_root }, + { OPTION_BOOL, "querytags", 0, NULL, "display known query tags", NULL, }, + { OPTION_BOOL, "showrc", 0, NULL, "display final rpmrc and macro configuration", NULL, }, + { OPTION_BOOL, "quiet", 0, NULL, "provide less detailed output", NULL }, + { OPTION_BOOL, "verbose", 'v', NULL, "provide more detailed output", NULL }, + { OPTION_BOOL, "version", 0, NULL, "print the version of rpm being used", &option_version }, + { } +}; + +static int option_conflicts, option_obsoletes, option_requires; +static int option_provides, option_info, option_changelog; + +static const struct option alias_options[] = { + { OPTION_BOOL, "scripts", 0, NULL, "list install/erase scriptlets from package(s)", NULL, }, + { OPTION_BOOL, "setperms", 0, NULL, "set permissions of files in a package", NULL, }, + { OPTION_BOOL, "setugids", 0, NULL, "set user/group ownership of files in a package", NULL, }, + { OPTION_BOOL, "conflicts", 0, NULL, "list capabilities this package conflicts with", &option_conflicts, }, + { OPTION_BOOL, "obsoletes", 0, NULL, "list other packages removed by installing this package", &option_obsoletes, }, + { OPTION_BOOL, "provides", 0, NULL, "list capabilities that this package provides", &option_provides, }, + { OPTION_BOOL, "requires", 0, NULL, "list capabilities required by package(s)", &option_requires, }, + { OPTION_BOOL, "info", 'i', NULL, "list descriptive information from package(s)", &option_info, }, + { OPTION_BOOL, "changelog", 0, NULL, "list change logs for this package", &option_changelog, }, + { OPTION_BOOL, "xml", 0, NULL, "list metadata in xml", NULL, }, + { OPTION_BOOL, "triggers", 0, NULL, "list trigger scriptlets from package(s)", NULL, }, + { OPTION_BOOL, "last", 0, NULL, "list package(s) by install time, most recent first", NULL, }, + { OPTION_BOOL, "dupes", 0, NULL, "list duplicated packages", NULL, }, + { OPTION_BOOL, "filesbypkg", 0, NULL, "list all files from each package", NULL, }, + { OPTION_BOOL, "fileclass", 0, NULL, "list file names with classes", NULL, }, + { OPTION_BOOL, "filecolor", 0, NULL, "list file names with colors", NULL, }, + { OPTION_BOOL, "filecontext", 0, NULL, "list file names with security context from header", NULL, }, + { OPTION_BOOL, "fscontext", 0, NULL, "list file names with security context from file system", NULL, }, + { OPTION_BOOL, "recontext", 0, NULL, "list file names with security context from policy RE", NULL, }, + { OPTION_BOOL, "fileprovide", 0, NULL, "list file names with provides", NULL, }, + { OPTION_BOOL, "filerequire", 0, NULL, "list file names with requires", NULL, }, + { OPTION_BOOL, "redhatprovides", 0, NULL, "find package name that contains a provided capability (needs rpmdb-redhat package installed)", NULL, }, + { OPTION_BOOL, "redhatrequires", 0, NULL, "find package name that contains a required capability (needs rpmdb-redhat package installed)", NULL, }, + { OPTION_STRING, "buildpolicy", 0, "", "set buildroot (e.g. compress man pages)", NULL, }, + { OPTION_BOOL, "with", 0, "