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