src/rpm.c
author James Bowes <jbowes@redhat.com>
Wed Jul 09 10:11:13 2008 -0400 (2008-07-09)
changeset 318 829d6711b316
parent 307 95b6bcadd6c4
child 369 f8c27fe9fe63
permissions -rw-r--r--
Use strings to identify section types in the on-disk repo format.

Previously, a given razor file type had a fixed number of sections in a
fixed order, identified by an integer type. Now, sections are identified
by a named string (stored in a string pool after the section lists).

This will allow for razor files to contain arbitrary sections.

For bonus points, also drop the 4k section alignment and change the
magic byte string to "RZDB".

committer: Kristian H?gsberg <krh@redhat.com>
rhughes@241
     1
/*
rhughes@241
     2
 * Copyright (C) 2008  Kristian Høgsberg <krh@redhat.com>
rhughes@241
     3
 * Copyright (C) 2008  Red Hat, Inc
rhughes@241
     4
 *
rhughes@241
     5
 * This program is free software; you can redistribute it and/or modify
rhughes@241
     6
 * it under the terms of the GNU General Public License as published by
rhughes@241
     7
 * the Free Software Foundation; either version 2 of the License, or
rhughes@241
     8
 * (at your option) any later version.
rhughes@241
     9
 *
rhughes@241
    10
 * This program is distributed in the hope that it will be useful,
rhughes@241
    11
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
rhughes@241
    12
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
rhughes@241
    13
 * GNU General Public License for more details.
rhughes@241
    14
 *
rhughes@241
    15
 * You should have received a copy of the GNU General Public License along
rhughes@241
    16
 * with this program; if not, write to the Free Software Foundation, Inc.,
rhughes@241
    17
 * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
rhughes@241
    18
 */
rhughes@241
    19
jbowes@276
    20
#include "config.h"
jbowes@276
    21
rhughes@241
    22
#include <stdlib.h>
rhughes@241
    23
#include <string.h>
rhughes@241
    24
#include <stdio.h>
krh@247
    25
#include <stdint.h>
rhughes@241
    26
#include <dirent.h>
rhughes@241
    27
#include "razor.h"
rhughes@241
    28
rhughes@241
    29
enum option_type {
rhughes@241
    30
	OPTION_LAST,
rhughes@241
    31
	OPTION_GROUP,
rhughes@241
    32
	OPTION_BOOL,
rhughes@241
    33
	OPTION_STRING
rhughes@241
    34
};
rhughes@241
    35
rhughes@241
    36
struct option {
rhughes@241
    37
	enum option_type type;
rhughes@241
    38
	const char *name;
rhughes@241
    39
	char short_name;
rhughes@241
    40
	const char *arg_name;
rhughes@241
    41
	const char *description;
rhughes@241
    42
	void *data;
rhughes@241
    43
};
rhughes@241
    44
rhughes@241
    45
/* A note about all these options: rpm allows options to mean
rhughes@241
    46
 * different things depending on what other options are present on the
rhughes@241
    47
 * command line.  For example, if -q or --query is present, -i no
rhughes@241
    48
 * longer means install, but info.  The way we handle this is by
rhughes@241
    49
 * setting all the options that may match (ie if -i is given we set
rhughes@241
    50
 * install and info), and then look at the relevent one depending on
rhughes@241
    51
 * what else in on the command line. */
rhughes@241
    52
jbowes@275
    53
static int option_all, option_list, option_whatrequires, option_whatprovides;
jbowes@277
    54
static int option_package, option_file;
rhughes@241
    55
rhughes@241
    56
static const struct option query_options[] = {
rhughes@241
    57
	{ OPTION_BOOL, "configfiles", 'c', NULL, "list all configuration files", NULL },
rhughes@241
    58
	{ OPTION_BOOL, "docfiles", 'd', NULL, "list all documentation files", NULL },
rhughes@241
    59
	{ OPTION_BOOL, "dump", 0, NULL, "dump basic file information", NULL },
jbowes@275
    60
	{ OPTION_BOOL, "list", 'l', NULL, "list files in package", &option_list },
rhughes@241
    61
	{ OPTION_STRING, "queryformat", 0, "QUERYFORMAT", "use the following query format", NULL },
rhughes@241
    62
	{ OPTION_BOOL, "state", 's', NULL, "display the states of the listed files", NULL },
rhughes@241
    63
	{ OPTION_BOOL, "all", 'a', NULL, "query/verify all packages", &option_all },
jbowes@277
    64
	{ OPTION_BOOL, "file", 'f', NULL, "query/verify package(s) owning file", &option_file },
rhughes@241
    65
	{ OPTION_BOOL, "group", 'g', NULL, "query/verify package(s) in group", NULL },
rhughes@241
    66
	{ OPTION_BOOL, "package", 'p', NULL, "query/verify a package file", &option_package },
rhughes@241
    67
	{ OPTION_BOOL, "ftswalk", 'W', NULL, "query/verify package(s) from TOP file tree walk", NULL },
rhughes@241
    68
	{ OPTION_BOOL, "pkgid", 0, NULL, "query/verify package(s) with package identifier", NULL },
rhughes@241
    69
	{ OPTION_BOOL, "hdrid", 0, NULL, "query/verify package(s) with header identifier", NULL },
rhughes@241
    70
	{ OPTION_BOOL, "fileid", 0, NULL, "query/verify package(s) with file identifier", NULL },
rhughes@241
    71
	{ OPTION_BOOL, "specfile", 0, NULL, "query a spec file", NULL, },
rhughes@241
    72
	{ OPTION_BOOL, "triggeredby", 0, NULL, "query the package(s) triggered by the package", NULL },
rhughes@241
    73
	{ OPTION_BOOL, "whatrequires", 0, NULL, "query/verify the package(s) which require a dependency", &option_whatrequires },
rhughes@241
    74
	{ OPTION_BOOL, "whatprovides", 0, NULL, "query/verify the package(s) which provide a dependency", &option_whatprovides },
rhughes@241
    75
	{ OPTION_BOOL, "nomanifest", 0, NULL, "do not process non-package files as manifests", NULL },
rhughes@241
    76
	{ }
rhughes@241
    77
};
rhughes@241
    78
rhughes@241
    79
static int option_nodeps;
rhughes@241
    80
rhughes@241
    81
static const struct option verify_options[] = {
rhughes@241
    82
	{ OPTION_BOOL, "nomd5", 0, NULL, "don't verify MD5 digest of files", NULL },
rhughes@241
    83
	{ OPTION_BOOL, "nofiles", 0, NULL, "don't verify files in package", NULL },
rhughes@241
    84
	{ OPTION_BOOL, "nodeps", 0, NULL, "don't verify package dependencies", &option_nodeps },
rhughes@241
    85
	{ OPTION_BOOL, "noscript", 0, NULL, "don't execute verify script(s)", NULL, },
rhughes@241
    86
	{ OPTION_BOOL, "all", 'a', NULL, "query/verify all packages", &option_all },
jbowes@277
    87
	{ OPTION_BOOL, "file", 'f', NULL, "query/verify package(s) owning file", &option_file },
rhughes@241
    88
	{ OPTION_BOOL, "group", 'g', NULL, "query/verify package(s) in group", NULL },
rhughes@241
    89
	{ OPTION_BOOL, "package", 'p', NULL, "query/verify a package file", &option_package },
rhughes@241
    90
	{ OPTION_BOOL, "ftswalk", 'W', NULL, "query/verify package(s) from TOP file tree walk", NULL },
rhughes@241
    91
	{ OPTION_BOOL, "pkgid", 0, NULL, "query/verify package(s) with package identifier", NULL },
rhughes@241
    92
	{ OPTION_BOOL, "hdrid", 0, NULL, "query/verify package(s) with header identifier", NULL },
rhughes@241
    93
	{ OPTION_BOOL, "fileid", 0, NULL, "query/verify package(s) with file identifier", NULL },
rhughes@241
    94
	{ OPTION_BOOL, "specfile", 0, NULL, "query a spec file", NULL },
rhughes@241
    95
	{ OPTION_BOOL, "triggeredby", 0, NULL, "query the package(s) triggered by the package", NULL },
rhughes@241
    96
	{ OPTION_BOOL, "whatrequires", 0, NULL, "query/verify the package(s) which require a dependency", &option_whatrequires },
rhughes@241
    97
	{ OPTION_BOOL, "whatprovides", 0, NULL, "query/verify the package(s) which provide a dependency", &option_whatprovides },
rhughes@241
    98
	{ OPTION_BOOL, "nomanifest", 0, NULL, "do not process non-package files as manifests", NULL },
rhughes@241
    99
	{ }
rhughes@241
   100
};
rhughes@241
   101
rhughes@241
   102
static const struct option ftw_options[] = {
rhughes@241
   103
	{ OPTION_BOOL, "comfollow", 0, NULL, "FTS_COMFOLLOW: follow command line symlinks", NULL },
rhughes@241
   104
	{ OPTION_BOOL, "logical", 0, NULL, "FTS_LOGICAL: logical walk", NULL },
rhughes@241
   105
	{ OPTION_BOOL, "nochdir", 0, NULL, "FTS_NOCHDIR: don't change directories", NULL },
rhughes@241
   106
	{ OPTION_BOOL, "nostat", 0, NULL, "FTS_NOSTAT: don't get stat info", NULL },
rhughes@241
   107
	{ OPTION_BOOL, "physical", 0, NULL, "FTS_PHYSICAL: physical walk", NULL },
rhughes@241
   108
	{ OPTION_BOOL, "seedot", 0, NULL, "FTS_SEEDOT: return dot and dot-dot", NULL },
rhughes@241
   109
	{ OPTION_BOOL, "xdev", 0, NULL, "FTS_XDEV: don't cross devices", NULL },
rhughes@241
   110
	{ OPTION_BOOL, "whiteout", 0, NULL, "FTS_WHITEOUT: return whiteout information", NULL },
rhughes@241
   111
	{ }
rhughes@241
   112
};
rhughes@241
   113
rhughes@241
   114
static const struct option signature_options[] = {
rhughes@241
   115
	{ OPTION_BOOL, "addsign", 0, NULL, "sign package(s) (identical to --resign)", NULL, },
rhughes@241
   116
	{ OPTION_BOOL, "checksig", 'K', NULL, "verify package signature(s)", NULL, },
rhughes@241
   117
	{ OPTION_BOOL, "delsign", 0, NULL, "delete package signatures", NULL, },
rhughes@241
   118
	{ OPTION_BOOL, "import", 0, NULL, "import an armored public key", NULL, },
rhughes@241
   119
	{ OPTION_BOOL, "resign", 0, NULL, "sign package(s) (identical to --addsign)", NULL, },
rhughes@241
   120
	{ OPTION_BOOL, "nodigest", 0, NULL, "don't verify package digest(s)", NULL, },
rhughes@241
   121
	{ OPTION_BOOL, "nosignature", 0, NULL, "don't verify package signature(s)", NULL },
rhughes@241
   122
	{ }
rhughes@241
   123
};
rhughes@241
   124
rhughes@241
   125
static int option_initdb;
rhughes@241
   126
rhughes@241
   127
static const struct option database_options[] = {
rhughes@241
   128
	{ OPTION_BOOL, "initdb", 0, NULL, "initialize database", &option_initdb },
rhughes@241
   129
	{ OPTION_BOOL, "rebuilddb", 0, NULL, "rebuild database inverted lists from installed package headers", NULL },
rhughes@241
   130
	{ }
rhughes@241
   131
};
rhughes@241
   132
rhughes@241
   133
static int option_erase, option_install, option_upgrade, option_justdb;
rhughes@241
   134
static int option_test;
rhughes@241
   135
rhughes@241
   136
static const struct option install_options[] = {
rhughes@241
   137
	{ OPTION_BOOL, "aid", 0, NULL, "add suggested packages to transaction", NULL, },
rhughes@241
   138
	{ OPTION_BOOL, "allfiles", 0, NULL, "install all files, even configurations which might otherwise be skipped", NULL, },
rhughes@241
   139
	{ OPTION_BOOL, "allmatches", 0, NULL, "remove all packages which match <package> (normally an error is generated if <package> specified multiple packages)", NULL, },
rhughes@241
   140
	{ OPTION_BOOL, "badreloc", 0, NULL, "relocate files in non-relocatable package", NULL },
rhughes@241
   141
	{ OPTION_BOOL, "erase", 'e', "<package>", "erase (uninstall) package", &option_erase },
rhughes@241
   142
	{ OPTION_BOOL, "excludedocs", 0, NULL, "do not install documentation", NULL, },
rhughes@241
   143
	{ OPTION_BOOL, "excludepath", 0, "<path>", "skip files with leading component <path> ", NULL, },
rhughes@241
   144
	{ OPTION_BOOL, "fileconflicts", 0, NULL, "detect file conflicts between packages", NULL, },
rhughes@241
   145
	{ OPTION_BOOL, "force", 0, NULL, "short hand for --replacepkgs --replacefiles", NULL },
rhughes@241
   146
	{ OPTION_BOOL, "freshen", 'F', "<packagefile>+", "upgrade package(s) if already installed", NULL },
rhughes@241
   147
	{ OPTION_BOOL, "hash", 'h', NULL, "print hash marks as package installs (good with -v)", NULL },
rhughes@241
   148
	{ OPTION_BOOL, "ignorearch", 0, NULL, "don't verify package architecture", NULL, },
rhughes@241
   149
	{ OPTION_BOOL, "ignoreos", 0, NULL, "don't verify package operating system", NULL, },
rhughes@241
   150
	{ OPTION_BOOL, "ignoresize", 0, NULL, "don't check disk space before installing", NULL },
rhughes@241
   151
	{ OPTION_BOOL, "install", 'i', NULL, "install package(s)", &option_install },
rhughes@241
   152
	{ OPTION_BOOL, "justdb", 0, NULL, "update the database, but do not modify the filesystem", &option_justdb, },
rhughes@241
   153
	{ OPTION_BOOL, "nodeps", 0, NULL, "do not verify package dependencies", &option_nodeps, },
rhughes@241
   154
	{ OPTION_BOOL, "nomd5", 0, NULL, "don't verify MD5 digest of files", NULL, },
rhughes@241
   155
	{ OPTION_BOOL, "nocontexts", 0, NULL, "don't install file security contexts", NULL, },
rhughes@241
   156
	{ OPTION_BOOL, "noorder", 0, NULL, "do not reorder package installation to satisfy dependencies", NULL, },
rhughes@241
   157
	{ OPTION_BOOL, "nosuggest", 0, NULL, "do not suggest missing dependency resolution(s)", NULL, },
rhughes@241
   158
	{ OPTION_BOOL, "noscripts", 0, NULL, "do not execute package scriptlet(s)", NULL, },
rhughes@241
   159
	{ OPTION_BOOL, "notriggers", 0, NULL, "do not execute any scriptlet(s) triggered by this package", NULL, },
rhughes@241
   160
	{ OPTION_BOOL, "oldpackage", 0, NULL, "upgrade to an old version of the package (--force on upgrades does this automatically)", NULL },
rhughes@241
   161
	{ OPTION_BOOL, "percent", 0, NULL, "print percentages as package installs", NULL, },
rhughes@241
   162
	{ OPTION_STRING, "prefix", 0, "<dir>", "relocate the package to <dir>, if relocatable", NULL, },
rhughes@241
   163
	{ OPTION_STRING, "relocate", 0, "<old>=<new>", "relocate files from path <old> to <new>", NULL, },
rhughes@241
   164
	{ OPTION_BOOL, "repackage", 0, NULL, "save erased package files by repackaging", NULL, },
rhughes@241
   165
	{ OPTION_BOOL, "replacefiles", 0, NULL, "ignore file conflicts between packages", NULL, },
rhughes@241
   166
	{ OPTION_BOOL, "replacepkgs", 0, NULL, "reinstall if the package is already present", NULL, },
rhughes@241
   167
	{ OPTION_BOOL, "test", 0, NULL, "don't install, but tell if it would work or not", &option_test },
rhughes@241
   168
	{ OPTION_BOOL, "upgrade", 'U', "<packagefile>+", "upgrade package(s)", &option_upgrade },
rhughes@241
   169
	{ }
rhughes@241
   170
};
rhughes@241
   171
rhughes@241
   172
static int option_version;
rhughes@241
   173
static const char *option_root = "install";
rhughes@241
   174
rhughes@241
   175
static const struct option common_options[] = {
rhughes@241
   176
	{ OPTION_STRING, "define", 'D', "MACRO EXPR", "define MACRO with value EXPR", NULL, },
rhughes@241
   177
	{ OPTION_STRING, "eval", 'E', "EXPR", "print macro expansion of EXPR", NULL },
rhughes@241
   178
	{ OPTION_STRING, "macros", 0, "<FILE:...>", "read <FILE:...> instead of default file(s)", NULL },
rhughes@241
   179
	{ OPTION_BOOL, "nodigest", 0, NULL, "don't verify package digest(s)", NULL, },
rhughes@241
   180
	{ OPTION_BOOL, "nosignature", 0, NULL, "don't verify package signature(s)", NULL, },
rhughes@241
   181
	{ OPTION_STRING, "rcfile", 0, "<FILE:...>", "read <FILE:...> instead of default file(s)", NULL },
rhughes@241
   182
	{ OPTION_STRING, "root", 'r', "ROOT", "use ROOT as top level directory (default: \"/\")", &option_root },
rhughes@241
   183
	{ OPTION_BOOL, "querytags", 0, NULL, "display known query tags", NULL, },
rhughes@241
   184
	{ OPTION_BOOL, "showrc", 0, NULL, "display final rpmrc and macro configuration", NULL, },
rhughes@241
   185
	{ OPTION_BOOL, "quiet", 0, NULL, "provide less detailed output", NULL },
rhughes@241
   186
	{ OPTION_BOOL, "verbose", 'v', NULL, "provide more detailed output", NULL },
rhughes@241
   187
	{ OPTION_BOOL, "version", 0, NULL, "print the version of rpm being used", &option_version },
rhughes@241
   188
	{ }
rhughes@241
   189
};
rhughes@241
   190
rhughes@241
   191
static int option_conflicts, option_obsoletes, option_requires;
rhughes@241
   192
static int option_provides, option_info, option_changelog;
rhughes@241
   193
rhughes@241
   194
static const struct option alias_options[] = {
rhughes@241
   195
	{ OPTION_BOOL, "scripts", 0, NULL, "list install/erase scriptlets from package(s)", NULL, },
rhughes@241
   196
	{ OPTION_BOOL, "setperms", 0, NULL, "set permissions of files in a package", NULL, },
rhughes@241
   197
	{ OPTION_BOOL, "setugids", 0, NULL, "set user/group ownership of files in a package", NULL, },
rhughes@241
   198
	{ OPTION_BOOL, "conflicts", 0, NULL, "list capabilities this package conflicts with", &option_conflicts, },
rhughes@241
   199
	{ OPTION_BOOL, "obsoletes", 0, NULL, "list other packages removed by installing this package", &option_obsoletes, },
rhughes@241
   200
	{ OPTION_BOOL, "provides", 0, NULL, "list capabilities that this package provides", &option_provides, },
jbowes@279
   201
	{ OPTION_BOOL, "requires", 'R', NULL, "list capabilities required by package(s)", &option_requires, },
rhughes@241
   202
	{ OPTION_BOOL, "info", 'i', NULL, "list descriptive information from package(s)", &option_info, },
rhughes@241
   203
	{ OPTION_BOOL, "changelog", 0, NULL, "list change logs for this package", &option_changelog, },
rhughes@241
   204
	{ OPTION_BOOL, "xml", 0, NULL, "list metadata in xml", NULL, },
rhughes@241
   205
	{ OPTION_BOOL, "triggers", 0, NULL, "list trigger scriptlets from package(s)", NULL, },
rhughes@241
   206
	{ OPTION_BOOL, "last", 0, NULL, "list package(s) by install time, most recent first", NULL, },
rhughes@241
   207
	{ OPTION_BOOL, "dupes", 0, NULL, "list duplicated packages", NULL, },
rhughes@241
   208
	{ OPTION_BOOL, "filesbypkg", 0, NULL, "list all files from each package", NULL, },
rhughes@241
   209
	{ OPTION_BOOL, "fileclass", 0, NULL, "list file names with classes", NULL, },
rhughes@241
   210
	{ OPTION_BOOL, "filecolor", 0, NULL, "list file names with colors", NULL, },
rhughes@241
   211
	{ OPTION_BOOL, "filecontext", 0, NULL, "list file names with security context from header", NULL, },
rhughes@241
   212
	{ OPTION_BOOL, "fscontext", 0, NULL, "list file names with security context from file system", NULL, },
rhughes@241
   213
	{ OPTION_BOOL, "recontext", 0, NULL, "list file names with security context from policy RE", NULL, },
rhughes@241
   214
	{ OPTION_BOOL, "fileprovide", 0, NULL, "list file names with provides", NULL, },
rhughes@241
   215
	{ OPTION_BOOL, "filerequire", 0, NULL, "list file names with requires", NULL, },
rhughes@241
   216
	{ OPTION_BOOL, "redhatprovides", 0, NULL, "find package name that contains a provided capability (needs rpmdb-redhat package installed)", NULL, },
rhughes@241
   217
	{ OPTION_BOOL, "redhatrequires", 0, NULL, "find package name that contains a required capability (needs rpmdb-redhat package installed)", NULL, },
rhughes@241
   218
	{ OPTION_STRING, "buildpolicy", 0, "<policy>", "set buildroot <policy> (e.g. compress man pages)", NULL, },
rhughes@241
   219
	{ OPTION_BOOL, "with", 0, "<option>", "enable configure <option> for build", NULL, },
rhughes@241
   220
	{ OPTION_BOOL, "without", 0, "<option>", "disable configure <option> for build", NULL },
rhughes@241
   221
	{ }
rhughes@241
   222
};
rhughes@241
   223
rhughes@241
   224
static int option_help, option_usage;
rhughes@241
   225
rhughes@241
   226
static const struct option help_options[] = {
rhughes@241
   227
	{ OPTION_BOOL, "help", '?', NULL, "Show this help message", &option_help },
rhughes@241
   228
	{ OPTION_BOOL, "usage", 0, NULL, "Display brief usage message", &option_usage},
rhughes@241
   229
	{ }
rhughes@241
   230
};
rhughes@241
   231
rhughes@241
   232
static int option_query, option_verify;
rhughes@241
   233
rhughes@241
   234
static const struct option rpm_options[] = {
rhughes@241
   235
	{ OPTION_BOOL, "query", 'q', NULL, "Query rpm database", &option_query },
rhughes@241
   236
	{ OPTION_BOOL, "verify", 'V', NULL, "Verify rpm database", &option_verify },
rhughes@241
   237
	{ OPTION_GROUP, NULL, 0, NULL, "Query options (with -q or --query):", &query_options },
rhughes@241
   238
	{ OPTION_GROUP, NULL, 0, NULL, "Verify options (with -V or --verify):", &verify_options },
rhughes@241
   239
	{ OPTION_GROUP, NULL, 0, NULL, "File tree walk options (with --ftswalk):", &ftw_options },
rhughes@241
   240
	{ OPTION_GROUP, NULL, 0, NULL, "Signature options:", &signature_options },
rhughes@241
   241
	{ OPTION_GROUP, NULL, 0, NULL, "Database options:", &database_options },
rhughes@241
   242
	{ OPTION_GROUP, NULL, 0, NULL, "Install/Upgrade/Erase options:", &install_options },
rhughes@241
   243
	{ OPTION_GROUP, NULL, 0, NULL, "Common options for all rpm modes and executables:", &common_options },
rhughes@241
   244
	{ OPTION_GROUP, NULL, 0, NULL, "Options implemented via popt alias/exec:", &alias_options },
rhughes@241
   245
	{ OPTION_GROUP, NULL, 0, NULL, "Help options", &help_options },
rhughes@241
   246
	{ }
rhughes@241
   247
};
rhughes@241
   248
richard@310
   249
static const char system_repo_filename[] = "system.rzdb";
rhughes@241
   250
static const char *repo_filename = system_repo_filename;
rhughes@241
   251
rhughes@241
   252
static void
rhughes@241
   253
command_initdb(int argc, const char *argv[])
rhughes@241
   254
{
rhughes@241
   255
	razor_root_create(option_root);
rhughes@241
   256
}
rhughes@241
   257
rhughes@241
   258
static struct razor_property *
rhughes@241
   259
add_property_packages(struct razor_set *set,
rhughes@241
   260
		      struct razor_package_query *query,
rhughes@241
   261
		      const char *ref_name,
rhughes@241
   262
		      const char *ref_version,
krh@247
   263
		      uint32_t ref_type)
rhughes@241
   264
{
rhughes@241
   265
	struct razor_property *property;
rhughes@241
   266
	struct razor_property_iterator *pi;
rhughes@241
   267
	struct razor_package_iterator *pkgi;
rhughes@241
   268
	const char *name, *version;
krh@247
   269
	uint32_t flags;
rhughes@241
   270
rhughes@241
   271
	pi = razor_property_iterator_create(set, NULL);
rhughes@241
   272
	while (razor_property_iterator_next(pi, &property, &name,
krh@247
   273
					    &flags, &version)) {
rhughes@241
   274
		if (strcmp(ref_name, name) != 0)
rhughes@241
   275
			continue;
krh@247
   276
		if (ref_version &&
krh@247
   277
		    (flags & RAZOR_PROPERTY_RELATION_MASK) == RAZOR_PROPERTY_EQUAL &&
rhughes@241
   278
		    strcmp(ref_version, version) != 0)
rhughes@241
   279
			continue;
krh@247
   280
		if ((flags & RAZOR_PROPERTY_TYPE_MASK) != ref_type)
rhughes@241
   281
			continue;
rhughes@241
   282
rhughes@241
   283
		pkgi = razor_package_iterator_create_for_property(set,
rhughes@241
   284
								  property);
rhughes@241
   285
		razor_package_query_add_iterator(query, pkgi);
rhughes@241
   286
		razor_package_iterator_destroy(pkgi);
rhughes@241
   287
	}
rhughes@241
   288
	razor_property_iterator_destroy(pi);
rhughes@241
   289
rhughes@241
   290
	return property;
rhughes@241
   291
}
rhughes@241
   292
rhughes@241
   293
static int
rhughes@241
   294
strcmpp(const void *p1, const void *p2)
rhughes@241
   295
{
rhughes@241
   296
	return strcmp(*(char * const *) p1, *(char * const *) p2);
rhughes@241
   297
}
rhughes@241
   298
rhughes@241
   299
static void
rhughes@241
   300
add_command_line_packages(struct razor_set *set,
rhughes@241
   301
			  struct razor_package_query *query,
rhughes@241
   302
			  int argc, const char **argv)
rhughes@241
   303
{
rhughes@241
   304
	struct razor_package *package;
rhughes@241
   305
	struct razor_package_iterator *pi;
richard@302
   306
	const char *name;
rhughes@241
   307
	int i, cmp, errors;
rhughes@241
   308
rhughes@241
   309
	qsort(argv, argc, sizeof(*argv), strcmpp);
rhughes@241
   310
	i = 0;
rhughes@241
   311
	errors = 0;
rhughes@241
   312
rhughes@241
   313
	pi = razor_package_iterator_create(set);
rhughes@241
   314
rhughes@241
   315
	while (razor_package_iterator_next(pi, &package,
richard@307
   316
					   RAZOR_DETAIL_NAME, &name,
richard@307
   317
					   RAZOR_DETAIL_LAST)) {
rhughes@241
   318
		while (cmp = strcmp(argv[i], name), cmp < 0 && i < argc) {
rhughes@241
   319
			fprintf(stderr, "error: package %s is not installed\n",
rhughes@241
   320
				argv[i]);
rhughes@241
   321
			errors++;
rhughes@241
   322
			i++;
rhughes@241
   323
		}
rhughes@241
   324
rhughes@241
   325
		if (cmp == 0) {
rhughes@241
   326
			razor_package_query_add_package(query, package);
rhughes@241
   327
			i++;
rhughes@241
   328
		}
rhughes@241
   329
	}
rhughes@241
   330
rhughes@241
   331
	razor_package_iterator_destroy(pi);
rhughes@241
   332
rhughes@241
   333
	if (errors)
rhughes@241
   334
		exit(1);
rhughes@241
   335
}
rhughes@241
   336
rhughes@241
   337
static struct razor_package_iterator *
rhughes@241
   338
get_query_packages(struct razor_set *set, int argc, const char *argv[])
rhughes@241
   339
{
rhughes@241
   340
	struct razor_package_query *query;
rhughes@241
   341
	struct razor_package_iterator *pi;
jbowes@277
   342
	char *files;
rhughes@241
   343
	int i;
rhughes@241
   344
jbowes@277
   345
	if (option_all + option_whatprovides + option_whatrequires +
jbowes@277
   346
	    option_file > 1) {
rhughes@241
   347
		printf("only one type of query/verify "
rhughes@241
   348
		       "may be performed at a time\n");
rhughes@241
   349
		exit(1);
rhughes@241
   350
	}
rhughes@241
   351
richard@310
   352
	files = "install/var/lib/razor/system-files.rzdb";
jbowes@277
   353
	if (option_file)
jbowes@288
   354
		if (razor_set_open_files(set, files))
jbowes@288
   355
			exit(1);
jbowes@277
   356
rhughes@241
   357
	query = razor_package_query_create(set);
rhughes@241
   358
rhughes@241
   359
	if (option_all) {
rhughes@241
   360
		pi = razor_package_iterator_create(set);
rhughes@241
   361
		razor_package_query_add_iterator(query, pi);
rhughes@241
   362
		razor_package_iterator_destroy(pi);
rhughes@241
   363
	} else if (option_whatrequires) {
rhughes@241
   364
		for (i = 0; i < argc; i++)
rhughes@241
   365
			add_property_packages(set, query,
rhughes@241
   366
					      argv[i], NULL,
rhughes@241
   367
					      RAZOR_PROPERTY_REQUIRES);
rhughes@241
   368
	} else if (option_whatprovides) {
rhughes@241
   369
		for (i = 0; i < argc; i++)
rhughes@241
   370
			add_property_packages(set, query,
rhughes@241
   371
					      argv[i], NULL,
rhughes@241
   372
					      RAZOR_PROPERTY_PROVIDES);
jbowes@277
   373
	} else if (option_file) {
jbowes@277
   374
		for (i = 0; i < argc; i++) {
jbowes@277
   375
			pi = razor_package_iterator_create_for_file(set,
jbowes@277
   376
								    argv[i]);
jbowes@277
   377
			razor_package_query_add_iterator(query, pi);
jbowes@277
   378
			razor_package_iterator_destroy(pi);
jbowes@277
   379
		}
rhughes@241
   380
	} else if (argc > 0) {
rhughes@241
   381
		add_command_line_packages(set, query, argc, argv);
rhughes@241
   382
	} else {
rhughes@241
   383
		printf("no arguments given for query/verify\n");
rhughes@241
   384
		exit(1);
rhughes@241
   385
	}
rhughes@241
   386
rhughes@241
   387
	return razor_package_query_finish(query);
rhughes@241
   388
}
rhughes@241
   389
rhughes@241
   390
static void
rhughes@241
   391
print_package_properties(struct razor_set *set,
rhughes@241
   392
			 struct razor_package *package,
krh@247
   393
			 uint32_t ref_type)
rhughes@241
   394
{
rhughes@241
   395
	struct razor_property *property;
rhughes@241
   396
	struct razor_property_iterator *pi;
rhughes@241
   397
	const char *name, *version;
krh@247
   398
	uint32_t flags;
rhughes@241
   399
rhughes@241
   400
	pi = razor_property_iterator_create(set, package);
rhughes@241
   401
	while (razor_property_iterator_next(pi, &property,
krh@247
   402
					    &name, &flags, &version)) {
krh@247
   403
		if ((flags & RAZOR_PROPERTY_TYPE_MASK) != ref_type)
rhughes@241
   404
			continue;
rhughes@241
   405
		if (version[0] == '\0')
rhughes@241
   406
			printf("%s\n", name);
rhughes@241
   407
		else
rhughes@241
   408
			printf("%s %s %s\n", name,
krh@247
   409
			       razor_property_relation_to_string(property),
krh@247
   410
			       version);
rhughes@241
   411
	}
rhughes@241
   412
	razor_property_iterator_destroy(pi);
rhughes@241
   413
}
rhughes@241
   414
rhughes@241
   415
static void
krh@266
   416
print_package_info(struct razor_set *set, struct razor_package *package,
krh@266
   417
		   const char *name, const char *version, const char *arch)
rhughes@241
   418
{
krh@266
   419
	const char *summary, *description, *url, *license;
krh@266
   420
richard@302
   421
	razor_package_get_details (set, package,
richard@302
   422
				   RAZOR_DETAIL_SUMMARY, &summary,
richard@302
   423
				   RAZOR_DETAIL_DESCRIPTION, &description,
richard@302
   424
				   RAZOR_DETAIL_URL, &url,
richard@302
   425
				   RAZOR_DETAIL_LICENSE, &license,
richard@307
   426
				   RAZOR_DETAIL_LAST);
krh@266
   427
krh@266
   428
	printf("Name:        %s\n", name);
krh@266
   429
	printf("Arch:        %s\n", arch);
krh@266
   430
	printf("Version:     %s\n", version);
krh@266
   431
	printf("URL:         %s\n", url);
krh@266
   432
	printf("License:     %s\n", license);
krh@266
   433
	printf("Summary:     %s\n", summary);
krh@266
   434
	printf("Description:\n");
krh@266
   435
	printf("%s\n", description);
krh@266
   436
	printf("\n");
rhughes@241
   437
}
rhughes@241
   438
rhughes@241
   439
static void
rhughes@241
   440
print_package_changelog(struct razor_set *set, struct razor_package *package)
rhughes@241
   441
{
rhughes@241
   442
	printf("FIXME: Package changelog not tracked.\n");
rhughes@241
   443
}
rhughes@241
   444
rhughes@241
   445
static struct razor_set *
rhughes@241
   446
create_set_from_command_line(int argc, const char *argv[])
rhughes@241
   447
{
rhughes@241
   448
	struct razor_importer *importer;
rhughes@241
   449
	struct razor_rpm *rpm;
rhughes@241
   450
	int i;
rhughes@241
   451
krh@249
   452
	importer = razor_importer_create();
rhughes@241
   453
rhughes@241
   454
	for (i = 0; i < argc; i++) {
rhughes@241
   455
		rpm = razor_rpm_open(argv[i]);
rhughes@241
   456
		if (rpm == NULL)
rhughes@241
   457
			continue;
rhughes@241
   458
		if (razor_importer_add_rpm(importer, rpm))
rhughes@241
   459
			printf("couldn't import %s\n", argv[i]);
rhughes@241
   460
rhughes@241
   461
		razor_rpm_close(rpm);
rhughes@241
   462
	}
rhughes@241
   463
rhughes@241
   464
	return razor_importer_finish(importer);
rhughes@241
   465
}
rhughes@241
   466
rhughes@241
   467
static void
rhughes@241
   468
command_query(int argc, const char *argv[])
rhughes@241
   469
{
rhughes@241
   470
	struct razor_set *set;
rhughes@241
   471
	struct razor_package_iterator *pi;
rhughes@241
   472
	struct razor_package *package;
jbowes@275
   473
	const char *name, *version, *arch, *details, *files;
rhughes@241
   474
rhughes@241
   475
	if (option_package) {
rhughes@241
   476
		set = create_set_from_command_line(argc, argv);
rhughes@241
   477
		argc = 0;
rhughes@241
   478
		option_all = 1;
rhughes@241
   479
	} else {
rhughes@241
   480
		set = razor_root_open_read_only(option_root);
jbowes@289
   481
jbowes@289
   482
		/* FIXME: We need to figure out how to do this right. */
richard@310
   483
		details = "install/var/lib/razor/system-details.rzdb";
jbowes@289
   484
		if (option_info)
jbowes@289
   485
			if (razor_set_open_details(set, details))
jbowes@289
   486
				return;
richard@310
   487
		files = "install/var/lib/razor/system-files.rzdb";
jbowes@289
   488
		if (option_list)
jbowes@289
   489
			if (razor_set_open_files(set, files))
jbowes@289
   490
				return;
rhughes@241
   491
	}
rhughes@241
   492
rhughes@241
   493
	pi = get_query_packages(set, argc, argv);
rhughes@241
   494
rhughes@241
   495
	while (razor_package_iterator_next(pi, &package,
richard@302
   496
					   RAZOR_DETAIL_NAME, &name,
richard@302
   497
					   RAZOR_DETAIL_VERSION, &version,
richard@307
   498
					   RAZOR_DETAIL_ARCH, &arch,
richard@307
   499
					   RAZOR_DETAIL_LAST)) {
rhughes@241
   500
		if (option_conflicts)
rhughes@241
   501
			print_package_properties(set, package,
rhughes@241
   502
						 RAZOR_PROPERTY_CONFLICTS);
rhughes@241
   503
		if (option_obsoletes)
rhughes@241
   504
			print_package_properties(set, package,
rhughes@241
   505
						 RAZOR_PROPERTY_OBSOLETES);
rhughes@241
   506
		if (option_requires)
rhughes@241
   507
			print_package_properties(set, package,
rhughes@241
   508
						 RAZOR_PROPERTY_REQUIRES);
rhughes@241
   509
		if (option_provides)
rhughes@241
   510
			print_package_properties(set, package,
rhughes@241
   511
						 RAZOR_PROPERTY_PROVIDES);
rhughes@241
   512
		if (option_info)
krh@266
   513
			print_package_info(set, package, name, version, arch);
rhughes@241
   514
		if (option_changelog)
rhughes@241
   515
			print_package_changelog(set, package);
jbowes@275
   516
		if (option_list)
krh@306
   517
			razor_set_list_package_files(set, package);
rhughes@241
   518
rhughes@241
   519
		if (option_conflicts + option_obsoletes +
rhughes@241
   520
		    option_requires + option_provides +
jbowes@275
   521
		    option_info + option_changelog + option_list == 0)
rhughes@241
   522
			printf("%s-%s.%s\n", name, version, arch);
rhughes@241
   523
	}
rhughes@241
   524
rhughes@241
   525
	razor_package_iterator_destroy(pi);
rhughes@241
   526
rhughes@241
   527
	razor_set_destroy(set);
rhughes@241
   528
rhughes@241
   529
	return;
rhughes@241
   530
}
rhughes@241
   531
rhughes@241
   532
static void
rhughes@241
   533
command_verify(int argc, const char *argv[])
rhughes@241
   534
{
rhughes@241
   535
	struct razor_set *set;
rhughes@241
   536
	struct razor_package_iterator *pi;
rhughes@241
   537
	struct razor_package *package;
rhughes@241
   538
	const char *name, *version, *arch;
rhughes@241
   539
rhughes@241
   540
	if (option_package) {
rhughes@241
   541
		set = create_set_from_command_line(argc, argv);
rhughes@241
   542
		argc = 0;
rhughes@241
   543
		option_all = 1;
rhughes@241
   544
	} else {
rhughes@241
   545
		set = razor_root_open_read_only(option_root);
rhughes@241
   546
	}
rhughes@241
   547
rhughes@241
   548
	pi = get_query_packages(set, argc, argv);
rhughes@241
   549
rhughes@241
   550
	while (razor_package_iterator_next(pi, &package,
richard@302
   551
					   RAZOR_DETAIL_NAME, &name,
richard@302
   552
					   RAZOR_DETAIL_VERSION, &version,
richard@307
   553
					   RAZOR_DETAIL_ARCH, &arch,
richard@307
   554
					   RAZOR_DETAIL_LAST)) {
rhughes@241
   555
		printf("verify %s-%s.%s - not implemented\n",
rhughes@241
   556
		       name, version, arch);
rhughes@241
   557
	}
rhughes@241
   558
rhughes@241
   559
	razor_package_iterator_destroy(pi);
rhughes@241
   560
}
rhughes@241
   561
rhughes@241
   562
static void
krh@253
   563
update_package(enum razor_diff_action action,
krh@253
   564
	       struct razor_package *package,
krh@253
   565
	       const char *name,
krh@253
   566
	       const char *version,
krh@253
   567
	       const char *arch,
krh@253
   568
	       void *data)
rhughes@241
   569
{
krh@253
   570
	if (action == RAZOR_DIFF_ACTION_ADD)
krh@253
   571
		printf("install %s-%s.%s\n", name, version, arch);
krh@253
   572
	if (action == RAZOR_DIFF_ACTION_REMOVE)
krh@253
   573
		printf("remove %s-%s.%s\n", name, version, arch);
rhughes@241
   574
}
rhughes@241
   575
rhughes@241
   576
static void
rhughes@241
   577
command_erase(int argc, const char *argv[])
rhughes@241
   578
{
rhughes@241
   579
	struct razor_set *set, *upstream, *next;
rhughes@241
   580
	struct razor_transaction *trans;
rhughes@241
   581
	struct razor_package_query *query;
rhughes@241
   582
	struct razor_package_iterator *pi;
rhughes@241
   583
	struct razor_package *package;
rhughes@241
   584
rhughes@241
   585
	if (argc == 0) {
rhughes@241
   586
		printf("no packages given for erase\n");
rhughes@241
   587
		exit(1);
rhughes@241
   588
	}
rhughes@241
   589
rhughes@241
   590
	set = razor_set_open(repo_filename);
rhughes@241
   591
	upstream = razor_set_create();
rhughes@241
   592
rhughes@241
   593
	trans = razor_transaction_create(set, upstream);
rhughes@241
   594
rhughes@241
   595
	query = razor_package_query_create(set);
rhughes@241
   596
	add_command_line_packages(set, query, argc, argv);
rhughes@241
   597
rhughes@241
   598
	pi = razor_package_query_finish(query);
richard@307
   599
	while (razor_package_iterator_next(pi, &package, RAZOR_DETAIL_LAST))
rhughes@241
   600
		razor_transaction_remove_package(trans, package);
rhughes@241
   601
	razor_package_iterator_destroy(pi);
rhughes@241
   602
rhughes@241
   603
	if (!option_nodeps && razor_transaction_describe(trans) > 0) {
rhughes@241
   604
		printf("unsatisfied dependencies.\n");
rhughes@241
   605
		exit(1);
rhughes@241
   606
	}
rhughes@241
   607
rhughes@241
   608
	if (option_test)
rhughes@241
   609
		exit(0);
rhughes@241
   610
rhughes@241
   611
	next = razor_transaction_finish(trans);
rhughes@241
   612
rhughes@241
   613
	if (!option_justdb)
krh@253
   614
		razor_set_diff(set, next, update_package, NULL);
rhughes@241
   615
rhughes@241
   616
	razor_set_destroy(set);
rhughes@241
   617
	razor_set_destroy(upstream);
rhughes@241
   618
rhughes@241
   619
	razor_set_destroy(next);
rhughes@241
   620
}
rhughes@241
   621
rhughes@241
   622
static void
rhughes@241
   623
command_install(int argc, const char *argv[])
rhughes@241
   624
{
rhughes@241
   625
	struct razor_set *set, *upstream, *next;
rhughes@241
   626
	struct razor_transaction *trans;
rhughes@241
   627
	struct razor_package_iterator *pi;
rhughes@241
   628
	struct razor_package *package;
rhughes@241
   629
rhughes@241
   630
	if (argc == 0) {
rhughes@241
   631
		printf("no packages given for install\n");
rhughes@241
   632
		exit(1);
rhughes@241
   633
	}
rhughes@241
   634
rhughes@241
   635
	set = razor_set_open(repo_filename);
rhughes@241
   636
	upstream = create_set_from_command_line(argc, argv);
rhughes@241
   637
rhughes@241
   638
	trans = razor_transaction_create(set, upstream);
rhughes@241
   639
rhughes@241
   640
	pi = razor_package_iterator_create(upstream);
richard@307
   641
	while (razor_package_iterator_next(pi, &package, RAZOR_DETAIL_LAST))
rhughes@241
   642
		razor_transaction_install_package(trans, package);
rhughes@241
   643
	razor_package_iterator_destroy(pi);
rhughes@241
   644
rhughes@241
   645
	if (!option_nodeps && razor_transaction_describe(trans) > 0) {
rhughes@241
   646
		printf("unsatisfied dependencies.\n");
rhughes@241
   647
		exit(1);
rhughes@241
   648
	}
rhughes@241
   649
rhughes@241
   650
	if (option_test)
rhughes@241
   651
		exit(0);
rhughes@241
   652
rhughes@241
   653
	next = razor_transaction_finish(trans);
rhughes@241
   654
rhughes@241
   655
	if (!option_justdb)
krh@253
   656
		razor_set_diff(set, next, update_package, NULL);
rhughes@241
   657
rhughes@241
   658
	razor_set_destroy(set);
rhughes@241
   659
	razor_set_destroy(upstream);
rhughes@241
   660
rhughes@241
   661
	razor_set_destroy(next);
rhughes@241
   662
}
rhughes@241
   663
rhughes@241
   664
static void
rhughes@241
   665
command_update(int argc, const char *argv[])
rhughes@241
   666
{
rhughes@241
   667
	struct razor_set *set, *upstream, *next;
rhughes@241
   668
	struct razor_transaction *trans;
rhughes@241
   669
	struct razor_package_iterator *pi;
rhughes@241
   670
	struct razor_package *package;
rhughes@241
   671
rhughes@241
   672
	if (argc == 0) {
rhughes@241
   673
		printf("no packages given for update\n");
rhughes@241
   674
		exit(1);
rhughes@241
   675
	}
rhughes@241
   676
rhughes@241
   677
	set = razor_set_open(repo_filename);
rhughes@241
   678
	upstream = create_set_from_command_line(argc, argv);
rhughes@241
   679
rhughes@241
   680
	trans = razor_transaction_create(set, upstream);
rhughes@241
   681
rhughes@241
   682
	pi = razor_package_iterator_create(upstream);
richard@307
   683
	while (razor_package_iterator_next(pi, &package, RAZOR_DETAIL_LAST))
rhughes@241
   684
		razor_transaction_update_package(trans, package);
rhughes@241
   685
	razor_package_iterator_destroy(pi);
rhughes@241
   686
rhughes@241
   687
	if (!option_nodeps && razor_transaction_describe(trans) > 0) {
rhughes@241
   688
		printf("unsatisfied dependencies.\n");
rhughes@241
   689
		exit(1);
rhughes@241
   690
	}
rhughes@241
   691
rhughes@241
   692
	if (option_test)
rhughes@241
   693
		exit(0);
rhughes@241
   694
rhughes@241
   695
	next = razor_transaction_finish(trans);
rhughes@241
   696
rhughes@241
   697
	if (!option_justdb)
rhughes@241
   698
		razor_set_diff(set, next, update_package, NULL);
rhughes@241
   699
rhughes@241
   700
	razor_set_destroy(set);
rhughes@241
   701
	razor_set_destroy(upstream);
rhughes@241
   702
rhughes@241
   703
	razor_set_destroy(next);
rhughes@241
   704
}
rhughes@241
   705
rhughes@241
   706
static int
rhughes@241
   707
for_each_option(const struct option *options,
rhughes@241
   708
		const char *name, char short_name,
rhughes@241
   709
		void (*fn)(const struct option *o,
rhughes@241
   710
			   const char *name, char short_name,
rhughes@241
   711
			   void *data), void *data)
rhughes@241
   712
{
rhughes@241
   713
	int i, count = 0;
rhughes@241
   714
rhughes@241
   715
	for (i = 0; options[i].type != OPTION_LAST; i++) {
rhughes@241
   716
		switch (options[i].type) {
rhughes@241
   717
		case OPTION_GROUP:
rhughes@241
   718
			count += for_each_option(options[i].data,
rhughes@241
   719
						 name, short_name, fn, data);
rhughes@241
   720
			break;
rhughes@241
   721
rhughes@241
   722
		case OPTION_BOOL:
rhughes@241
   723
		case OPTION_STRING:
rhughes@241
   724
			if (name && strcmp(options[i].name, name) == 0) {
rhughes@241
   725
				fn(&options[i], name, 0, data);
rhughes@241
   726
				count++;
rhughes@241
   727
				break;
rhughes@241
   728
			}
rhughes@241
   729
rhughes@241
   730
			if (short_name &&
rhughes@241
   731
			    short_name == options[i].short_name) {
rhughes@241
   732
				fn(&options[i], NULL, short_name, data);
rhughes@241
   733
				count++;
rhughes@241
   734
				break;
rhughes@241
   735
			}
rhughes@241
   736
			break;
rhughes@241
   737
rhughes@241
   738
		case OPTION_LAST:
rhughes@241
   739
			break;
rhughes@241
   740
		}
rhughes@241
   741
	}
rhughes@241
   742
rhughes@241
   743
	return count;
rhughes@241
   744
}
rhughes@241
   745
rhughes@241
   746
static void
rhughes@241
   747
handle_option(const struct option *o,
rhughes@241
   748
	      const char *name, char short_name, void *data)
rhughes@241
   749
{
rhughes@241
   750
	if (o->data == NULL) {
rhughes@241
   751
		if (name)
rhughes@241
   752
			printf("option --%s not supported\n", name);
rhughes@241
   753
		else
rhughes@241
   754
			printf("option -%c not supported\n", short_name);
rhughes@241
   755
		return;
rhughes@241
   756
	}
rhughes@241
   757
rhughes@241
   758
	switch (o->type) {
rhughes@241
   759
	case OPTION_BOOL:
rhughes@241
   760
		*(int *) o->data = 1;
rhughes@241
   761
		break;
rhughes@241
   762
rhughes@241
   763
	case OPTION_STRING:
rhughes@241
   764
		*(const char **) o->data = name + strlen(o->name) + 1;
rhughes@241
   765
		break;
rhughes@241
   766
rhughes@241
   767
	case OPTION_LAST:
rhughes@241
   768
	case OPTION_GROUP:
rhughes@241
   769
		/* Shouldn't happen. */
rhughes@241
   770
		break;
rhughes@241
   771
	}
rhughes@241
   772
}
rhughes@241
   773
rhughes@241
   774
static int
rhughes@241
   775
parse_options(const struct option *options, int argc, const char **argv)
rhughes@241
   776
{
rhughes@241
   777
	int i, j, k;
rhughes@241
   778
rhughes@241
   779
	for (i = 1, j = 0; i < argc; i++) {
rhughes@241
   780
		if (argv[i][0] != '-') {
rhughes@241
   781
			argv[j++] = argv[i];
rhughes@241
   782
			continue;
rhughes@241
   783
		}
rhughes@241
   784
rhughes@241
   785
		if (argv[i][1] == '-') {
rhughes@241
   786
			if (for_each_option(options, &argv[i][2], 0,
rhughes@241
   787
					    handle_option, NULL) == 0) {
rhughes@241
   788
				printf("unknown option: %s\n", argv[i]);
rhughes@241
   789
				exit(1);
rhughes@241
   790
			}
rhughes@241
   791
			continue;
rhughes@241
   792
		}
rhughes@241
   793
rhughes@241
   794
		for (k = 1; argv[i][k]; k++) {
rhughes@241
   795
			if (for_each_option(options, NULL, argv[i][k],
rhughes@241
   796
					    handle_option, NULL) == 0) {
rhughes@241
   797
				printf("unknown option: -%c\n", argv[i][k]);
rhughes@241
   798
				exit(1);
rhughes@241
   799
			}
rhughes@241
   800
		}
rhughes@241
   801
	}
rhughes@241
   802
rhughes@241
   803
	return j;
rhughes@241
   804
}
rhughes@241
   805
rhughes@241
   806
static void
rhughes@241
   807
print_options_help(const struct option *options)
rhughes@241
   808
{
rhughes@241
   809
	int i;
rhughes@241
   810
rhughes@241
   811
	for (i = 0; options[i].type != OPTION_LAST; i++) {
rhughes@241
   812
		switch (options[i].type) {
rhughes@241
   813
		case OPTION_GROUP:
rhughes@241
   814
			printf("%s\n", options[i].description);
rhughes@241
   815
			print_options_help(options[i].data);
rhughes@241
   816
			printf("\n");
rhughes@241
   817
			break;
rhughes@241
   818
rhughes@241
   819
		case OPTION_BOOL:
rhughes@241
   820
		case OPTION_STRING:
rhughes@241
   821
			printf("  ");
rhughes@241
   822
			if (options[i].short_name)
rhughes@241
   823
				printf("-%c", options[i].short_name);
rhughes@241
   824
			if (options[i].short_name && options[i].name)
rhughes@241
   825
				printf(", ");
rhughes@241
   826
			if (options[i].name)
rhughes@241
   827
				printf("--%s", options[i].name);
rhughes@241
   828
			if (options[i].arg_name)
rhughes@241
   829
				printf("=%s", options[i].arg_name);
rhughes@241
   830
			if (options[i].description)
rhughes@241
   831
				printf("\t\t%s", options[i].description);
rhughes@241
   832
			printf("\n");
rhughes@241
   833
			break;
rhughes@241
   834
rhughes@241
   835
		case OPTION_LAST:
rhughes@241
   836
			break;
rhughes@241
   837
		}
rhughes@241
   838
	}
rhughes@241
   839
}
rhughes@241
   840
rhughes@241
   841
static void
rhughes@241
   842
print_options_usage(const struct option *options)
rhughes@241
   843
{
rhughes@241
   844
	int i;
rhughes@241
   845
rhughes@241
   846
	for (i = 0; options[i].type != OPTION_LAST; i++) {
rhughes@241
   847
		switch (options[i].type) {
rhughes@241
   848
		case OPTION_GROUP:
rhughes@241
   849
			print_options_usage(options[i].data);
rhughes@241
   850
			break;
rhughes@241
   851
rhughes@241
   852
		case OPTION_BOOL:
rhughes@241
   853
			printf("[");
rhughes@241
   854
			if (options[i].short_name)
rhughes@241
   855
				printf("-%c", options[i].short_name);
rhughes@241
   856
			if (options[i].short_name && options[i].name)
rhughes@241
   857
				printf("|");
rhughes@241
   858
			if (options[i].name)
rhughes@241
   859
				printf("--%s", options[i].name);
rhughes@241
   860
			printf("] ");
rhughes@241
   861
			break;
rhughes@241
   862
rhughes@241
   863
		case OPTION_STRING:
rhughes@241
   864
			printf("[");
rhughes@241
   865
			if (options[i].short_name)
rhughes@241
   866
				printf("-%c", options[i].short_name);
rhughes@241
   867
			if (options[i].short_name && options[i].name)
rhughes@241
   868
				printf("|");
rhughes@241
   869
			if (options[i].name)
rhughes@241
   870
				printf("--%s", options[i].name);
rhughes@241
   871
			if (options[i].arg_name)
rhughes@241
   872
				printf("=%s", options[i].arg_name);
rhughes@241
   873
			printf("] ");
rhughes@241
   874
			break;
rhughes@241
   875
rhughes@241
   876
rhughes@241
   877
			break;
rhughes@241
   878
rhughes@241
   879
		case OPTION_LAST:
rhughes@241
   880
			break;
rhughes@241
   881
		}
rhughes@241
   882
	}
rhughes@241
   883
}
rhughes@241
   884
rhughes@241
   885
int
rhughes@241
   886
main(int argc, const char *argv[])
rhughes@241
   887
{
rhughes@241
   888
	argc = parse_options(rpm_options, argc, argv);
rhughes@241
   889
rhughes@241
   890
	if (option_version) {
jbowes@276
   891
		printf("razor rpm version " VERSION "\n");
rhughes@241
   892
		exit(0);
rhughes@241
   893
	}
rhughes@241
   894
rhughes@241
   895
	if (option_help) {
rhughes@241
   896
		printf("Usage: rpm [OPTION...]\n");
rhughes@241
   897
		print_options_help(rpm_options);
rhughes@241
   898
		exit(0);
rhughes@241
   899
	}
rhughes@241
   900
rhughes@241
   901
	if (option_usage) {
rhughes@241
   902
		printf("Usage: rpm [OPTION...]\n");
rhughes@241
   903
		print_options_usage(rpm_options);
rhughes@241
   904
		printf("\n");
rhughes@241
   905
		exit(0);
rhughes@241
   906
	}
rhughes@241
   907
rhughes@241
   908
	if (option_initdb) {
rhughes@241
   909
		command_initdb(argc, argv);
rhughes@241
   910
	} else if (option_verify) {
rhughes@241
   911
		command_verify(argc, argv);
rhughes@241
   912
	} else if (option_query) {
rhughes@241
   913
		command_query(argc, argv);
rhughes@241
   914
	} else if (option_install) {
rhughes@241
   915
		command_install(argc, argv);
rhughes@241
   916
	} else if (option_upgrade) {
rhughes@241
   917
		command_update(argc, argv);
rhughes@241
   918
	} else if (option_erase) {
rhughes@241
   919
		command_erase(argc, argv);
rhughes@241
   920
	} else {
rhughes@241
   921
		print_options_usage(rpm_options);
rhughes@241
   922
		printf("\n");
rhughes@241
   923
		exit(0);
rhughes@241
   924
	}
rhughes@241
   925
rhughes@241
   926
	return 0;
rhughes@241
   927
}