src/main.c
author J. Ali Harlow <ali@juiblex.co.uk>
Tue Mar 06 12:39:15 2018 +0000 (2018-03-06)
changeset 495 5196f8110473
parent 476 48e45439fd9a
permissions -rw-r--r--
Release 0.6.3.111
     1 /*
     2  * Copyright (C) 2008  Kristian Høgsberg <krh@redhat.com>
     3  * Copyright (C) 2008  Red Hat, Inc
     4  * Copyright (C) 2009, 2011-2012, 2014, 2016  J. Ali Harlow <ali@juiblex.co.uk>
     5  *
     6  * This program is free software; you can redistribute it and/or modify
     7  * it under the terms of the GNU General Public License as published by
     8  * the Free Software Foundation; either version 2 of the License, or
     9  * (at your option) any later version.
    10  *
    11  * This program is distributed in the hope that it will be useful,
    12  * but WITHOUT ANY WARRANTY; without even the implied warranty of
    13  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
    14  * GNU General Public License for more details.
    15  *
    16  * You should have received a copy of the GNU General Public License along
    17  * with this program; if not, write to the Free Software Foundation, Inc.,
    18  * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
    19  */
    20 
    21 #define _GNU_SOURCE
    22 
    23 #include "config.h"
    24 
    25 #include <stdlib.h>
    26 #include <stddef.h>
    27 #include <stdio.h>
    28 #include <stdint.h>
    29 #include <string.h>
    30 #include <sys/stat.h>
    31 #include <unistd.h>
    32 #include <fcntl.h>
    33 #include <dirent.h>
    34 #include <limits.h>
    35 #ifdef MSWIN_API
    36 #include <windows.h>
    37 #include <shlwapi.h>
    38 #endif
    39 #ifdef HAVE_CURL
    40 #include <curl/curl.h>
    41 #endif
    42 #if !defined(HAVE_CURL) && !defined(MSWIN_API)
    43 #include <ctype.h>
    44 #endif
    45 #include <fnmatch.h>
    46 #include <errno.h>
    47 #include <getopt.h>
    48 #include "razor.h"
    49 #include "import.h"
    50 
    51 static const char system_repo_filename[] = "system.rzdb";
    52 static const char next_repo_filename[] = "system-next.rzdb";
    53 static const char rawhide_repo_uri[] = "file:rawhide.rzdb";
    54 static const char *install_root = "";
    55 static const char *repo_filename = system_repo_filename;
    56 static const char *yum_url;
    57 
    58 #ifndef FALSE
    59 #define FALSE 0
    60 #endif
    61 
    62 #ifndef TRUE
    63 #define TRUE (!FALSE)
    64 #endif
    65 
    66 #define ARRAY_SIZE(a) (sizeof(a) / sizeof((a)[0]))
    67 
    68 static int
    69 update_packages(struct razor_transaction *trans,
    70 		struct razor_install_iterator *ii, struct razor_set *system,
    71 		struct razor_set *next, struct razor_atomic *atomic,
    72 		struct razor_relocations *relocations,
    73 		enum razor_stage_type stage);
    74 static int
    75 update_system(struct razor_root *root, struct razor_relocations *relocations,
    76 	      struct razor_transaction *trans, struct razor_set *next,
    77 	      const char *verb);
    78 
    79 static int command_help(int argc, char * const argv[]);
    80 
    81 struct razor_option {
    82 	char *name;
    83 	int has_arg;
    84 	int val;
    85 	char *description;
    86 	char *arg_description;
    87 };
    88 
    89 static void
    90 razor_usage(const char *command, int n_options, struct razor_option *options,
    91 	    const char *parameter_string)
    92 {
    93 	int i, help_printed = FALSE;
    94 	char buf[19];
    95 
    96 	printf("Usage: razor %s [options] %s\n", command, parameter_string);
    97 	printf("(Specify the --help global option for a list of other "
    98 	       "help options)\n");
    99 	printf("\nOptions:\n");
   100 
   101 	for(i = 0; i < n_options; i++) {
   102 		if (!help_printed && strcmp(options[i].name, "help") > 0) {
   103 			printf("  --help              "
   104 			       "Show this help message and exit\n");
   105 			help_printed = TRUE;
   106 		}
   107 
   108 		if (options[i].has_arg != no_argument)
   109 			snprintf(buf, sizeof(buf), "%s=%s", options[i].name,
   110 				 options[i].arg_description);
   111 		else
   112 			strncpy(buf, options[i].name, sizeof(buf));
   113 		buf[18] = '\0';
   114 
   115 		printf("  --%-18s%s\n", buf, options[i].description);
   116 	}
   117 
   118 	if (!help_printed)
   119 		printf("  --help              "
   120 		       "Show this help message and exit\n");
   121 }
   122 
   123 /**
   124  * razor_getopt:
   125  *
   126  *
   127  * Returns: The next option found or -2 on handled or -1 on error
   128  *          or 0 on end of option list.
   129  **/
   130 static int
   131 razor_getopt(int argc, char * const argv[], int n_options,
   132 	     struct razor_option *options, const char *parameter_string,
   133 	     const char **arg)
   134 {
   135 	int i, opt, do_help = 0, retval;
   136 	struct option *longopts;
   137 
   138 	longopts = calloc((n_options + 2), sizeof(*longopts));
   139 
   140 	for(i = 0; i < n_options; i++) {
   141 		longopts[i].name = options[i].name;
   142 		longopts[i].has_arg = options[i].has_arg;
   143 		longopts[i].flag = &retval;
   144 		longopts[i].val = options[i].val;
   145 	}
   146 
   147 	longopts[i].name = "help";
   148 	longopts[i].has_arg = no_argument;
   149 	longopts[i].flag = &do_help;
   150 	longopts[i].val = TRUE;
   151 
   152 	opterr = 0;
   153 
   154 	opt = getopt_long(argc, (char **)argv, "+", longopts, NULL);
   155 
   156 	switch (opt)
   157 	{
   158 		case 0:
   159 			if (do_help) {
   160 				razor_usage(argv[0], n_options, options,
   161 					    parameter_string);
   162 				retval = -2;
   163 			} else if (arg)
   164 				*arg = optarg;
   165 			break;
   166 
   167 		case -1:
   168 			retval = 0;
   169 			break;
   170 
   171 		default:
   172 			razor_usage(argv[0], n_options, options,
   173 				    parameter_string);
   174 			retval = -1;
   175 	}
   176 
   177 	free(longopts);
   178 	return retval;
   179 }
   180 
   181 static struct razor_package_iterator *
   182 create_iterator_from_argv(struct razor_set *set, int argc, char * const argv[])
   183 {
   184 	struct razor_package_query *query;
   185 	struct razor_package_iterator *iter;
   186 	struct razor_package *package;
   187 	const char *name, *pattern;
   188 	int i, count;
   189 
   190 	if (argc == 0)
   191 		return razor_package_iterator_create(set);
   192 
   193 	query = razor_package_query_create(set);
   194 
   195 	for (i = 0; i < argc; i++) {
   196 		iter = razor_package_iterator_create(set);
   197 		pattern = argv[i];
   198 		count = 0;
   199 		while (razor_package_iterator_next(iter, &package,
   200 						   RAZOR_DETAIL_NAME, &name,
   201 						   RAZOR_DETAIL_LAST)) {
   202 			if (fnmatch(pattern, name, 0) != 0)
   203 				continue;
   204 
   205 			razor_package_query_add_package(query, package);
   206 			count++;
   207 		}
   208 		razor_package_iterator_destroy(iter);
   209 
   210 		if (count == 0)
   211 			fprintf(stderr,
   212 				"no package matches \"%s\"\n", pattern);
   213 	}
   214 
   215 	return razor_package_query_finish(query);
   216 }
   217 
   218 #define LIST_PACKAGES_ONLY_NAMES 0x01
   219 
   220 static void
   221 list_packages(struct razor_package_iterator *iter, uint32_t flags)
   222 {
   223 	struct razor_package *package;
   224 	const char *name, *version, *arch;
   225 
   226 	while (razor_package_iterator_next(iter, &package,
   227 					   RAZOR_DETAIL_NAME, &name,
   228 					   RAZOR_DETAIL_VERSION, &version,
   229 					   RAZOR_DETAIL_ARCH, &arch,
   230 					   RAZOR_DETAIL_LAST)) {
   231 		if (flags & LIST_PACKAGES_ONLY_NAMES)
   232 			printf("%s\n", name);
   233 		else
   234 			printf("%s-%s.%s\n", name, version, arch);
   235 	}
   236 }
   237 
   238 static int
   239 command_list(int argc, char * const argv[])
   240 {
   241 	int opt;
   242 	struct razor_package_iterator *pi;
   243 	struct razor_error *error = NULL;
   244 	struct razor_set *set;
   245 	uint32_t flags = 0;
   246 	enum {
   247 		opt_only_names = 1,
   248 	};
   249 	static struct razor_option options[] = {
   250 		{ .name = "only-names", .has_arg = no_argument,
   251 		  .val = opt_only_names,
   252 		  .description = "Only list package names" },
   253 	};
   254 
   255 	do {
   256 		opt = razor_getopt(argc, argv, ARRAY_SIZE(options), options,
   257 				   "pattern ...", NULL);
   258 		switch (opt) {
   259 			case -2:
   260 				return 0;
   261 			case -1:
   262 				return 1;
   263 			case opt_only_names:
   264 				flags |= LIST_PACKAGES_ONLY_NAMES;
   265 				break;
   266 		}
   267 	} while (opt);
   268 
   269 	set = razor_root_open_read_only(install_root, &error);
   270 	if (set == NULL) {
   271 		fprintf(stderr, "%s\n", razor_error_get_msg(error));
   272 		razor_error_free(error);
   273 		return 1;
   274 	}
   275 
   276 	pi = create_iterator_from_argv(set, argc - optind, argv + optind);
   277 	list_packages(pi, flags);
   278 	razor_package_iterator_destroy(pi);
   279 	razor_set_unref(set);
   280 
   281 	return 0;
   282 }
   283 
   284 static void
   285 list_package_properties(struct razor_set *set,
   286 			struct razor_package *package, uint32_t type)
   287 {
   288 	struct razor_property_iterator *pi;
   289 	struct razor_property *property;
   290 	const char *name, *version;
   291 	uint32_t flags;
   292 
   293 	pi = razor_property_iterator_create(set, package);
   294 	while (razor_property_iterator_next(pi, &property,
   295 					    &name, &flags, &version)) {
   296 		if ((flags & RAZOR_PROPERTY_TYPE_MASK) != type)
   297 			continue;
   298 		printf("%s", name);
   299 		if (version[0] != '\0')
   300 			printf(" %s %s",
   301 			       razor_property_relation_to_string(property),
   302 			       version);
   303 
   304 		if (flags & ~(RAZOR_PROPERTY_RELATION_MASK | RAZOR_PROPERTY_TYPE_MASK)) {
   305 			printf(" [");
   306 			if (flags & RAZOR_PROPERTY_PRE)
   307 				printf(" pre");
   308 			if (flags & RAZOR_PROPERTY_POST)
   309 				printf(" post");
   310 			if (flags & RAZOR_PROPERTY_PREUN)
   311 				printf(" preun");
   312 			if (flags & RAZOR_PROPERTY_POSTUN)
   313 				printf(" postun");
   314 			printf(" ]");
   315 		}
   316 		printf("\n");
   317 	}
   318 	razor_property_iterator_destroy(pi);
   319 }
   320 
   321 static int
   322 list_properties(int argc, char * const argv[], uint32_t type)
   323 {
   324 	struct razor_set *set;
   325 	struct razor_error *error = NULL;
   326 	struct razor_package *package;
   327 	struct razor_package_iterator *pi;
   328 	const char *name, *version, *arch;
   329 
   330 	switch (razor_getopt(argc, argv, 0, NULL, "pattern ...", NULL)) {
   331 		case -2:
   332 			return 0;
   333 		case -1:
   334 			return 1;
   335 	}
   336 
   337 	set = razor_root_open_read_only(install_root, &error);
   338 	if (set == NULL) {
   339 		fprintf(stderr, "%s\n", razor_error_get_msg(error));
   340 		razor_error_free(error);
   341 		return 1;
   342 	}
   343 
   344 	pi = create_iterator_from_argv(set, argc - optind, argv + optind);
   345 	while (razor_package_iterator_next(pi, &package,
   346 					   RAZOR_DETAIL_NAME, &name,
   347 					   RAZOR_DETAIL_VERSION, &version,
   348 					   RAZOR_DETAIL_ARCH, &arch,
   349 					   RAZOR_DETAIL_LAST))
   350 		list_package_properties(set, package, type);
   351 	razor_package_iterator_destroy(pi);
   352 	razor_set_unref(set);
   353 
   354 	return 0;
   355 }
   356 
   357 static int
   358 command_list_requires(int argc, char * const argv[])
   359 {
   360 	return list_properties(argc, argv, RAZOR_PROPERTY_REQUIRES);
   361 }
   362 
   363 static int
   364 command_list_provides(int argc, char * const argv[])
   365 {
   366 	return list_properties(argc, argv, RAZOR_PROPERTY_PROVIDES);
   367 }
   368 
   369 static int
   370 command_list_obsoletes(int argc, char * const argv[])
   371 {
   372 	return list_properties(argc, argv, RAZOR_PROPERTY_OBSOLETES);
   373 }
   374 
   375 static int
   376 command_list_conflicts(int argc, char * const argv[])
   377 {
   378 	return list_properties(argc, argv, RAZOR_PROPERTY_CONFLICTS);
   379 }
   380 
   381 static int
   382 command_list_scripts(int argc, char * const argv[])
   383 {
   384 	struct razor_set *set;
   385 	struct razor_error *error = NULL;
   386 	struct razor_package *package;
   387 	struct razor_package_iterator *pi;
   388 	const char *preunprog, *preun, *postunprog, *postun;
   389 
   390 	switch (razor_getopt(argc, argv, 0, NULL, "pattern ...", NULL)) {
   391 		case -2:
   392 			return 0;
   393 		case -1:
   394 			return 1;
   395 	}
   396 
   397 	set = razor_root_open_read_only(install_root, &error);
   398 	if (set == NULL) {
   399 		fprintf(stderr, "%s\n", razor_error_get_msg(error));
   400 		razor_error_free(error);
   401 		return 1;
   402 	}
   403 
   404 	pi = create_iterator_from_argv(set, argc - optind, argv + optind);
   405 	while (razor_package_iterator_next(pi, &package,
   406 					   RAZOR_DETAIL_PREUNPROG, &preunprog,
   407 					   RAZOR_DETAIL_PREUN, &preun,
   408 					   RAZOR_DETAIL_POSTUNPROG, &postunprog,
   409 					   RAZOR_DETAIL_POSTUN, &postun,
   410 					   RAZOR_DETAIL_LAST)) {
   411 		if (preun && *preun) {
   412 			printf("preuninstall scriptlet");
   413 			if (preunprog && *preunprog)
   414 				printf(" (using %s)",preunprog);
   415 			printf(":\n%s\n",preun);
   416 		}
   417 		if (postun && *postun) {
   418 			printf("postuninstall scriptlet");
   419 			if (postunprog && *postunprog)
   420 				printf(" (using %s)",postunprog);
   421 			printf(":\n%s\n",postun);
   422 		}
   423 	}
   424 	razor_package_iterator_destroy(pi);
   425 	razor_set_unref(set);
   426 
   427 	return 0;
   428 }
   429 
   430 static int
   431 command_list_files(int argc, char * const argv[])
   432 {
   433 	struct razor_error *error = NULL;
   434 	struct razor_set *set;
   435 
   436 	switch (razor_getopt(argc, argv, 0, NULL, "[pattern]", NULL)) {
   437 		case -2:
   438 			return 0;
   439 		case -1:
   440 			return 1;
   441 	}
   442 
   443 	if (argc - optind > 1) {
   444 		razor_usage(argv[0], 0, NULL, "[pattern]");
   445 		return 1;
   446 	}
   447 
   448 	set = razor_root_open_read_only(install_root, &error);
   449 	if (set == NULL) {
   450 		fprintf(stderr, "%s\n", razor_error_get_msg(error));
   451 		razor_error_free(error);
   452 		return 1;
   453 	}
   454 
   455 	razor_set_list_files(set, argv[optind]);
   456 	razor_set_unref(set);
   457 
   458 	return 0;
   459 }
   460 
   461 static int
   462 command_list_file_packages(int argc, char * const argv[])
   463 {
   464 	struct razor_error *error = NULL;
   465 	struct razor_set *set;
   466 	struct razor_package_iterator *pi;
   467 
   468 	switch (razor_getopt(argc, argv, 0, NULL, "pattern", NULL)) {
   469 		case -2:
   470 			return 0;
   471 		case -1:
   472 			return 1;
   473 	}
   474 
   475 	if (argc - optind != 1) {
   476 		razor_usage(argv[0], 0, NULL, "pattern");
   477 		return 1;
   478 	}
   479 
   480 	set = razor_root_open_read_only(install_root, &error);
   481 	if (set == NULL) {
   482 		fprintf(stderr, "%s\n", razor_error_get_msg(error));
   483 		razor_error_free(error);
   484 		return 1;
   485 	}
   486 
   487 	pi = razor_package_iterator_create_for_file(set, argv[optind]);
   488 	list_packages(pi, 0);
   489 	razor_package_iterator_destroy(pi);
   490 
   491 	razor_set_unref(set);
   492 
   493 	return 0;
   494 }
   495 
   496 static int
   497 command_list_package_files(int argc, char * const argv[])
   498 {
   499 	struct razor_error *error = NULL;
   500 	struct razor_set *set;
   501 	struct razor_package_iterator *pi;
   502 	struct razor_package *package;
   503 	const char *name, *version, *arch;
   504 
   505 	switch (razor_getopt(argc, argv, 0, NULL, "pattern ...", NULL)) {
   506 		case -2:
   507 			return 0;
   508 		case -1:
   509 			return 1;
   510 	}
   511 
   512 	set = razor_root_open_read_only(install_root, &error);
   513 	if (set == NULL) {
   514 		fprintf(stderr, "%s\n", razor_error_get_msg(error));
   515 		razor_error_free(error);
   516 		return 1;
   517 	}
   518 
   519 	pi = create_iterator_from_argv(set, argc - optind, argv + optind);
   520 	while (razor_package_iterator_next(pi, &package,
   521 					   RAZOR_DETAIL_NAME, &name,
   522 					   RAZOR_DETAIL_VERSION, &version,
   523 					   RAZOR_DETAIL_ARCH, &arch,
   524 					   RAZOR_DETAIL_LAST))
   525 		razor_set_list_package_files(set, package);
   526 	razor_package_iterator_destroy(pi);
   527 
   528 	razor_set_unref(set);
   529 
   530 	return 0;
   531 }
   532 
   533 static int
   534 list_property_packages(const char *ref_name,
   535 		       const char *ref_version,
   536 		       uint32_t type)
   537 {
   538 	struct razor_error *error = NULL;
   539 	struct razor_set *set;
   540 	struct razor_property *property;
   541 	struct razor_property_iterator *prop_iter;
   542 	struct razor_package_iterator *pkg_iter;
   543 	const char *name, *version;
   544 	uint32_t flags;
   545 
   546 	set = razor_root_open_read_only(install_root, &error);
   547 	if (set == NULL) {
   548 		fprintf(stderr, "%s\n", razor_error_get_msg(error));
   549 		razor_error_free(error);
   550 		return 1;
   551 	}
   552 
   553 	prop_iter = razor_property_iterator_create(set, NULL);
   554 	while (razor_property_iterator_next(prop_iter, &property,
   555 					    &name, &flags, &version)) {
   556 		if (strcmp(ref_name, name) != 0)
   557 			continue;
   558 		if (ref_version &&
   559 		    (flags & RAZOR_PROPERTY_RELATION_MASK) == RAZOR_PROPERTY_EQUAL &&
   560 		    strcmp(ref_version, version) != 0)
   561 			continue;
   562 		if ((flags & RAZOR_PROPERTY_TYPE_MASK) != type)
   563 			continue;
   564 
   565 		pkg_iter =
   566 			razor_package_iterator_create_for_property(set,
   567 								   property);
   568 		list_packages(pkg_iter, 0);
   569 		razor_package_iterator_destroy(pkg_iter);
   570 	}
   571 	razor_property_iterator_destroy(prop_iter);
   572 
   573 	razor_set_unref(set);
   574 
   575 	return 0;
   576 }
   577 
   578 static int
   579 command_what_requires(int argc, char * const argv[])
   580 {
   581 	switch (razor_getopt(argc, argv, 0, NULL, "name [version-release]",
   582 			     NULL)) {
   583 		case -2:
   584 			return 0;
   585 		case -1:
   586 			return 1;
   587 	}
   588 
   589 	if (argc - optind < 1 || argc - optind > 2) {
   590 		razor_usage(argv[0], 0, NULL, "name [version-release]");
   591 		return 1;
   592 	}
   593 
   594 	return list_property_packages(argv[optind], argv[optind + 1],
   595 				      RAZOR_PROPERTY_REQUIRES);
   596 }
   597 
   598 static int
   599 command_what_provides(int argc, char * const argv[])
   600 {
   601 	switch (razor_getopt(argc, argv, 0, NULL, "name [version-release]",
   602 			     NULL)) {
   603 		case -2:
   604 			return 0;
   605 		case -1:
   606 			return 1;
   607 	}
   608 
   609 	if (argc - optind < 1 || argc - optind > 2) {
   610 		razor_usage(argv[0], 0, NULL, "name [version-release]");
   611 		return 1;
   612 	}
   613 
   614 	return list_property_packages(argv[optind], argv[optind + 1],
   615 				      RAZOR_PROPERTY_PROVIDES);
   616 }
   617 
   618 #ifdef HAVE_CURL
   619 struct get_contents_with_curl_baton {
   620 	void *buf;
   621 	size_t buflen;
   622 };
   623 
   624 static size_t
   625 get_contents_with_curl_callback(void *contents, size_t size, size_t nmemb,
   626 				void *data)
   627 {
   628 	size_t nb = size * nmemb;
   629 	struct get_contents_with_curl_baton *baton = data;
   630 
   631 	baton->buf = realloc(baton->buf, baton->buflen + nb);
   632 	if (!baton->buf) {
   633 		fprintf(stderr, "Not enough memory to read file\n");
   634 		return 0;
   635 	}
   636 			 
   637 	memcpy((char *)baton->buf + baton->buflen, contents, nb);
   638 	baton->buflen += nb;
   639 
   640 	return nb;
   641 }
   642 
   643 static void *get_contents_with_curl(const char *uri, size_t *length,
   644 				    int private, struct razor_error **error)
   645 {
   646 	CURL *curl;
   647 	char errbuf[256];
   648 	CURLcode res;
   649 	struct get_contents_with_curl_baton baton = {0,};
   650 
   651 	curl = curl_easy_init();
   652 	if (!curl) {
   653 		razor_set_error(error, RAZOR_GENERAL_ERROR,
   654 				RAZOR_GENERAL_ERROR_FAILED, uri,
   655 				"Failed to initialize libcurl");
   656 		return NULL;
   657 	}
   658 
   659 	curl_easy_setopt(curl, CURLOPT_ERRORBUFFER, errbuf);
   660 	curl_easy_setopt(curl, CURLOPT_WRITEFUNCTION,
   661 			 get_contents_with_curl_callback);
   662 	curl_easy_setopt(curl, CURLOPT_WRITEDATA, (void *)&baton);
   663 	curl_easy_setopt(curl, CURLOPT_URL, uri);
   664 	curl_easy_setopt(curl, CURLOPT_USERAGENT, "razor/" VERSION);
   665 	res = curl_easy_perform(curl);
   666 	curl_easy_cleanup(curl);
   667 
   668 	if (res != CURLE_OK) {
   669 		razor_set_error(error, RAZOR_GENERAL_ERROR,
   670 				RAZOR_GENERAL_ERROR_FAILED, uri, errbuf);
   671 		free(baton.buf);
   672 		return NULL;
   673 	}
   674 
   675 	*length = baton.buflen;
   676 	return baton.buf;
   677 }
   678 
   679 int free_contents_with_curl(void *addr, size_t length)
   680 {
   681 	free(addr);
   682 }
   683 #endif
   684 
   685 static void init_uri_handler(void)
   686 {
   687 #ifdef HAVE_CURL
   688 	struct razor_uri_vtable uri_vtable={0,};
   689 	uri_vtable.structure_size=sizeof(uri_vtable);
   690 	uri_vtable.get_contents=get_contents_with_curl;
   691 	uri_vtable.free_contents=free_contents_with_curl;
   692 	razor_uri_set_vtable(NULL, &uri_vtable, NULL);
   693 #endif
   694 }
   695 
   696 static int
   697 download_if_missing(const char *uri, const char *file)
   698 {
   699 	int retval = 0;
   700 	struct stat buf;
   701 	void *contents;
   702 	size_t length;
   703 	struct razor_error *error = NULL;
   704 	FILE *fp;
   705 
   706 	if (stat(file, &buf) >= 0)
   707 		return 0;
   708 
   709 	contents = razor_uri_get_contents(uri, &length, 0, &error);
   710 
   711 	if (!contents) {
   712 		fprintf(stderr, "%s: %s\n", uri, razor_error_get_msg(error));
   713 		razor_error_free(error);
   714 		return -1;
   715 	}
   716 
   717 	fp = fopen(file, "wb");
   718 	if (!fp) {
   719 		perror(file);
   720 		razor_uri_free_contents(contents, length);
   721 		return -1;
   722 	}
   723 
   724 	if (fwrite(contents, 1, length, fp) != length) {
   725 		perror(file);
   726 		retval = -1;
   727 	}
   728 
   729 	fclose(fp);
   730 	razor_uri_free_contents(contents, length);
   731 
   732 	return retval;
   733 }
   734 
   735 #define YUM_URL "http://download.fedora.redhat.com" \
   736 	"/pub/fedora/linux/development/i386/os"
   737 
   738 static int
   739 command_import_yum(int argc, char * const argv[])
   740 {
   741 	int retval;
   742 	struct razor_set *set;
   743 	struct razor_atomic *atomic;
   744 
   745 	switch (razor_getopt(argc, argv, 0, NULL, "", NULL)) {
   746 		case -2:
   747 			return 0;
   748 		case -1:
   749 			return 1;
   750 	}
   751 
   752 	if (argc - optind > 0) {
   753 		razor_usage(argv[0], 0, NULL, "");
   754 		return 1;
   755 	}
   756 
   757 	printf("importing from '%s'.\n", yum_url);
   758 
   759 	set = razor_set_create_from_yum(yum_url);
   760 	if (set == NULL)
   761 		return 1;
   762 	atomic = razor_atomic_open("Yum import repository");
   763 	razor_set_write(set, atomic, rawhide_repo_uri, RAZOR_SECTION_ALL);
   764 	retval = razor_atomic_commit(atomic);
   765 	razor_set_unref(set);
   766 	if (retval)
   767 		fprintf(stderr, "%s\n", razor_atomic_get_error_msg(atomic));
   768 	else
   769 		printf("wrote %s\n", rawhide_repo_uri);
   770 	razor_atomic_destroy(atomic);
   771 
   772 	return retval;
   773 }
   774 
   775 #if HAVE_RPMLIB
   776 static int
   777 command_import_rpmdb(int argc, char * const argv[])
   778 {
   779 	struct razor_set *set;
   780 	struct razor_root *root;
   781 	struct razor_error *error = NULL;
   782 	struct razor_atomic *atomic;
   783 	int retval;
   784 
   785 	switch (razor_getopt(argc, argv, 0, NULL, "", NULL)) {
   786 		case -2:
   787 			return 0;
   788 		case -1:
   789 			return 1;
   790 	}
   791 
   792 	if (argc - optind > 0) {
   793 		razor_usage(argv[0], 0, NULL, "");
   794 		return 1;
   795 	}
   796 
   797 	root = razor_root_open(install_root, &error);
   798 	if (root == NULL) {
   799 		fprintf(stderr, "%s\n", razor_error_get_msg(error));
   800 		razor_error_free(error);
   801 		return 1;
   802 	}
   803 
   804 	set = razor_set_create_from_rpmdb();
   805 	if (set == NULL)
   806 		return 1;
   807 
   808 	atomic = razor_atomic_open("Import RPM database");
   809 
   810 	retval = razor_root_update(root, set, atomic);
   811 
   812 	if (retval)
   813 		fprintf(stderr, "%s\n", razor_atomic_get_error_msg(atomic));
   814 
   815 	razor_atomic_destroy(atomic);
   816 
   817 	razor_root_close(root);
   818 
   819 	return retval;
   820 }
   821 #endif
   822 
   823 static int
   824 mark_packages_for_update(struct razor_transaction *trans,
   825 			 struct razor_set *set, const char *pattern)
   826 {
   827 	struct razor_package_iterator *pi;
   828 	struct razor_package *package;
   829 	const char *name;
   830 	int matches = 0;
   831 
   832 	pi = razor_package_iterator_create(set);
   833 	while (razor_package_iterator_next(pi, &package,
   834 					   RAZOR_DETAIL_NAME, &name,
   835 					   RAZOR_DETAIL_LAST)) {
   836 		if (pattern && fnmatch(pattern, name, 0) == 0) {
   837 			razor_transaction_update_package(trans, package);
   838 			matches++;
   839 		}
   840 	}
   841 	razor_package_iterator_destroy(pi);
   842 
   843 	return matches;
   844 }
   845 
   846 static int
   847 mark_packages_for_removal(struct razor_transaction *trans,
   848 			  struct razor_set *set, const char *pattern)
   849 {
   850 	struct razor_package_iterator *pi;
   851 	struct razor_package *package;
   852 	const char *name;
   853 	int matches = 0;
   854 
   855 	pi = razor_package_iterator_create(set);
   856 	while (razor_package_iterator_next(pi, &package,
   857 					   RAZOR_DETAIL_NAME, &name,
   858 					   RAZOR_DETAIL_LAST)) {
   859 		if (pattern && fnmatch(pattern, name, 0) == 0) {
   860 			razor_transaction_remove_package(trans, package);
   861 			matches++;
   862 		}
   863 	}
   864 	razor_package_iterator_destroy(pi);
   865 
   866 	return matches;
   867 }
   868 
   869 static int
   870 command_remove(int argc, char * const argv[])
   871 {
   872 	struct razor_set *system, *upstream, *next;
   873 	struct razor_transaction *trans;
   874 	struct razor_error *error = NULL;
   875 	struct razor_root *root;
   876 	int i, retval;
   877 
   878 	switch (razor_getopt(argc, argv, 0, NULL, "pattern ...", NULL)) {
   879 		case -2:
   880 			return 0;
   881 		case -1:
   882 			return 1;
   883 	}
   884 
   885 	root = razor_root_open(install_root, &error);
   886 	if (root == NULL) {
   887 		fprintf(stderr, "%s\n", razor_error_get_msg(error));
   888 		razor_error_free(error);
   889 		return 1;
   890 	}
   891 
   892 	system = razor_root_get_system_set(root);
   893 	upstream = razor_set_create_without_root();
   894 	trans = razor_transaction_create(system, upstream);
   895 	razor_set_unref(upstream);
   896 	for (i = optind; i < argc; i++) {
   897 		if (mark_packages_for_removal(trans, system, argv[i]) == 0) {
   898 			fprintf(stderr, "no match for %s\n", argv[i]);
   899 			razor_transaction_destroy(trans);
   900 			razor_root_close(root);
   901 			return 1;
   902 		}
   903 	}
   904 
   905 	razor_transaction_resolve(trans);
   906 	retval = razor_transaction_describe(trans);
   907 	if (retval) {
   908 		razor_transaction_destroy(trans);
   909 		razor_root_close(root);
   910 		return 1;
   911 	}
   912 
   913 	next = razor_transaction_commit(trans);
   914 
   915 	retval = update_system(root, NULL, trans, next, "Remove");
   916 
   917 	razor_transaction_destroy(trans);
   918 	razor_root_close(root);
   919 	razor_set_unref(next);
   920 
   921 	return retval;
   922 }
   923 
   924 static void
   925 print_diff(enum razor_diff_action action,
   926 	   struct razor_package *package,
   927 	   const char *name,
   928 	   const char *version,
   929 	   const char *arch,
   930 	   void *data)
   931 {
   932 	if (action == RAZOR_DIFF_ACTION_ADD)
   933 		printf("install %s-%s.%s\n", name, version, arch);
   934 	if (action == RAZOR_DIFF_ACTION_REMOVE)
   935 		printf("remove %s-%s.%s\n", name, version, arch);
   936 }
   937 
   938 static int
   939 command_diff(int argc, char * const argv[])
   940 {
   941 	struct razor_error *error = NULL;
   942 	struct razor_set *set, *updated;
   943 
   944 	switch (razor_getopt(argc, argv, 0, NULL, "", NULL)) {
   945 		case -2:
   946 			return 0;
   947 		case -1:
   948 			return 1;
   949 	}
   950 
   951 	if (argc - optind > 0) {
   952 		razor_usage(argv[0], 0, NULL, "");
   953 		return 1;
   954 	}
   955 
   956 	set = razor_root_open_read_only(install_root, &error);
   957 	if (set)
   958 		updated = razor_set_open(rawhide_repo_uri, 0, &error);
   959 	else
   960 		updated = NULL;
   961 	if (updated == NULL) {
   962 		fprintf(stderr, "%s\n", razor_error_get_msg(error));
   963 		razor_error_free(error);
   964 		if (set)
   965 			razor_set_unref(set);
   966 		return 1;
   967 	}
   968 
   969 	razor_set_diff(set, updated, print_diff, NULL);
   970 
   971 	razor_set_unref(set);
   972 	razor_set_unref(updated);
   973 
   974 	return 0;
   975 }
   976 
   977 static int
   978 command_import_rpms(int argc, char * const argv[])
   979 {
   980 	DIR *dir;
   981 	struct dirent *de;
   982 	struct razor_importer *importer;
   983 	struct razor_set *set;
   984 	struct razor_rpm *rpm;
   985 	struct razor_error *error=NULL;
   986 	struct razor_atomic *atomic;
   987 	int len, imported_count = 0;
   988 	char filename[256];
   989 	const char *dirname;
   990 	int retval;
   991 
   992 	switch (razor_getopt(argc, argv, 0, NULL, "dir", NULL)) {
   993 		case -2:
   994 			return 0;
   995 		case -1:
   996 			return 1;
   997 	}
   998 
   999 	if (argc - optind != 1) {
  1000 		razor_usage(argv[0], 0, NULL, "dir");
  1001 		return 1;
  1002 	}
  1003 
  1004 	dirname = argv[optind];
  1005 
  1006 	dir = opendir(dirname);
  1007 	if (dir == NULL) {
  1008 		fprintf(stderr, "couldn't read dir %s\n", dirname);
  1009 		return -1;
  1010 	}
  1011 
  1012 	importer = razor_importer_create();
  1013 
  1014 	while (de = readdir(dir), de != NULL) {
  1015 		len = strlen(de->d_name);
  1016 		if (len < 5 || strcmp(de->d_name + len - 4, ".rpm") != 0)
  1017 			continue;
  1018 		snprintf(filename, sizeof filename,
  1019 			 "%s/%s", dirname, de->d_name);
  1020 		rpm = razor_rpm_open(filename, &error);
  1021 		if (rpm == NULL) {
  1022 			fprintf(stderr, "%s\n", razor_error_get_msg(error));
  1023 			razor_error_free(error);
  1024 			error=NULL;
  1025 			continue;
  1026 		}
  1027 		if (razor_importer_add_rpm(importer, rpm)) {
  1028 			fprintf(stderr, "couldn't import %s\n", filename);
  1029 			break;
  1030 		}
  1031 		razor_rpm_close(rpm);
  1032 
  1033 		printf("\rimporting %d", ++imported_count);
  1034 		fflush(stdout);
  1035 	}
  1036 
  1037 	if (de != NULL) {
  1038 		razor_importer_destroy(importer);
  1039 		return -1;
  1040 	}
  1041 
  1042 	printf("\nsaving\n");
  1043 	set = razor_importer_finish(importer);
  1044 
  1045 	atomic = razor_atomic_open("Update system database");
  1046 	razor_set_write(set, atomic, repo_filename, RAZOR_SECTION_ALL);
  1047 	razor_set_unref(set);
  1048 	retval = razor_atomic_commit(atomic);
  1049 	if (retval)
  1050 		fprintf(stderr, "%s\n", razor_atomic_get_error_msg(atomic));
  1051 	else
  1052 		printf("wrote %s\n", repo_filename);
  1053 	razor_atomic_destroy(atomic);
  1054 
  1055 	return retval;
  1056 }
  1057 
  1058 static char *
  1059 rpm_filename(const char *name, const char *version, const char *arch)
  1060 {
  1061  	const char *v;
  1062  
  1063  	/* Skip epoch */
  1064 	v = strchr(version, ':');
  1065  	if (v != NULL)
  1066  		v = v + 1;
  1067  	else
  1068 		v = version;
  1069 
  1070 	return razor_concat(name, "-", v, ".", arch, ".rpm", NULL);
  1071 }
  1072 
  1073 static struct razor_set *
  1074 relocate_packages(struct razor_set *set, struct razor_atomic *atomic,
  1075 		  struct razor_relocations *relocations)
  1076 {
  1077 	int i;
  1078 	struct razor_importer *importer;
  1079 	struct razor_property_iterator *prop_iter;
  1080 	struct razor_package_iterator *pkg_iter;
  1081  	struct razor_file_iterator *file_iter;
  1082  	struct razor_package *package;
  1083 	struct razor_property *property;
  1084 	struct razor_rpm *rpm;
  1085 	struct razor_error *error=NULL;
  1086 	const char *name, *version, *arch, *summary, *desc, *url, *license;
  1087 	const char *preunprog, *preun, *postunprog, *postun;
  1088 	const char *install_prefix;
  1089 	const char *const *prefixes;
  1090 	char *s, *uri, *filename;
  1091 	uint32_t flags;
  1092 
  1093 	importer = razor_importer_create();
  1094 	pkg_iter = razor_package_iterator_create(set);
  1095 
  1096 	while (razor_package_iterator_next(pkg_iter, &package,
  1097 					   RAZOR_DETAIL_NAME, &name,
  1098 					   RAZOR_DETAIL_VERSION, &version,
  1099 					   RAZOR_DETAIL_ARCH, &arch,
  1100 					   RAZOR_DETAIL_SUMMARY, &summary,
  1101 					   RAZOR_DETAIL_DESCRIPTION, &desc,
  1102 					   RAZOR_DETAIL_URL, &url,
  1103 					   RAZOR_DETAIL_LICENSE, &license,
  1104 					   RAZOR_DETAIL_PREUNPROG, &preunprog,
  1105 					   RAZOR_DETAIL_PREUN, &preun,
  1106 					   RAZOR_DETAIL_POSTUNPROG, &postunprog,
  1107 					   RAZOR_DETAIL_POSTUN, &postun,
  1108 					   RAZOR_DETAIL_LAST)) {
  1109 		filename = rpm_filename(name, version, arch);
  1110 		s = razor_concat("Packages/", filename, NULL);
  1111 		uri = razor_path_relative_to_uri(yum_url, s, NULL);
  1112 		free(s);
  1113 		free(filename);
  1114 		rpm = razor_rpm_open(uri, &error);
  1115 		free(uri);
  1116 		if (rpm == NULL) {
  1117 			razor_atomic_propagate_error(atomic, error, NULL);
  1118 			razor_package_iterator_destroy(pkg_iter);
  1119 			razor_importer_destroy(importer);
  1120 			return NULL;
  1121 		}
  1122 
  1123 		razor_relocations_set_rpm(relocations, rpm);
  1124 
  1125 		razor_importer_begin_package(importer, name, version, arch);
  1126 		razor_importer_add_details(importer,
  1127 					   summary, desc, url, license);
  1128 
  1129 		razor_rpm_get_details(rpm, RAZOR_DETAIL_PREFIXES, &prefixes,
  1130 				      RAZOR_DETAIL_LAST);
  1131 		for (i = 0; prefixes && prefixes[i]; i++) {
  1132 			install_prefix = razor_relocations_apply(relocations,
  1133 								 prefixes[i]);
  1134 			razor_importer_add_install_prefix(importer,
  1135 							  install_prefix);
  1136 		}
  1137 
  1138 		razor_rpm_close(rpm);
  1139 
  1140 		prop_iter = razor_property_iterator_create(set, package);
  1141 		while (razor_property_iterator_next(prop_iter, &property,
  1142 						    &name, &flags, &version))
  1143 			razor_importer_add_property(importer,
  1144 						    name, flags, version);
  1145 		razor_property_iterator_destroy(prop_iter);
  1146 
  1147 		file_iter = razor_file_iterator_create(set, package, 0);
  1148 		while (razor_file_iterator_next(file_iter, &name)) {
  1149 			name = razor_relocations_apply(relocations, name);
  1150 			razor_importer_add_file(importer, name);
  1151 		}
  1152 		razor_file_iterator_destroy(file_iter);
  1153 
  1154 		razor_importer_add_script(importer, RAZOR_PROPERTY_PREUN,
  1155 					  preunprog, preun);
  1156 		razor_importer_add_script(importer, RAZOR_PROPERTY_POSTUN,
  1157 					  postunprog, postun);
  1158 
  1159 		razor_importer_finish_package(importer);
  1160 	}
  1161 
  1162 	razor_package_iterator_destroy(pkg_iter);
  1163 	return razor_importer_finish(importer);
  1164 }
  1165 
  1166 static int
  1167 install_package(struct razor_transaction *trans, struct razor_set *set,
  1168 		struct razor_atomic *atomic, struct razor_package *package,
  1169 		struct razor_relocations *relocations, int install_count,
  1170 		enum razor_stage_type stage)
  1171 {
  1172 	int retval;
  1173 	const char *name, *version, *arch;
  1174 	char *file, *s, *uri;
  1175 	struct razor_rpm *rpm;
  1176 	struct razor_error *error=NULL;
  1177 
  1178 	razor_package_get_details(set, package,
  1179 				  RAZOR_DETAIL_NAME, &name,
  1180 				  RAZOR_DETAIL_VERSION, &version,
  1181 				  RAZOR_DETAIL_ARCH, &arch,
  1182 				  RAZOR_DETAIL_LAST);
  1183 
  1184 	s = rpm_filename(name, version, arch);
  1185 	file = razor_concat("Packages/", s, NULL);
  1186 	free(s);
  1187 	uri = razor_path_relative_to_uri(yum_url, file, NULL);
  1188 	free(file);
  1189 
  1190 	if (stage & RAZOR_STAGE_SCRIPTS_PRE)
  1191 		printf("install %s\n", uri);
  1192 
  1193 	rpm = razor_rpm_open(uri, &error);
  1194 	free(uri);
  1195 	if (rpm == NULL) {
  1196 		razor_atomic_propagate_error(atomic, error, NULL);
  1197 		fprintf(stderr, "%s\n", razor_error_get_msg(error));
  1198 		return -1;
  1199 	}
  1200 	if (relocations)
  1201 		razor_rpm_set_relocations(rpm, relocations);
  1202 	razor_transaction_fixup_package(trans, package, rpm);
  1203 	retval = razor_rpm_install(rpm, atomic, install_root, install_count,
  1204 				   stage);
  1205 	if (retval < 0) {
  1206 		s = rpm_filename(name, version, arch);
  1207 		fprintf(stderr, "%s: %s\n", s,
  1208 			razor_atomic_get_error_msg(atomic));
  1209 		free(s);
  1210 	}
  1211 	razor_rpm_close(rpm);
  1212 	return retval;
  1213 }
  1214 
  1215 /*
  1216  * Returns 0 on success, -1 on failure and 1 if a RAZOR_INSTALL_ACTION_COMMIT
  1217  * is met (in which case the action is consumed).
  1218  */
  1219 static int
  1220 update_packages(struct razor_transaction *trans,
  1221 		struct razor_install_iterator *ii, struct razor_set *system,
  1222 		struct razor_set *next, struct razor_atomic *atomic,
  1223 		struct razor_relocations *relocations,
  1224 		enum razor_stage_type stage)
  1225 {
  1226 	struct razor_package *package;
  1227 	enum razor_install_action action;
  1228 	int retval = 0, count;
  1229 
  1230 	while (!retval && razor_install_iterator_next(ii, &package, &action,
  1231 						      &count)) {
  1232 		if (action == RAZOR_INSTALL_ACTION_ADD) {
  1233 			if (install_package(trans, next, atomic, package,
  1234 					    relocations, count, stage))
  1235 				retval = -1;
  1236 		} else if (action == RAZOR_INSTALL_ACTION_REMOVE) {
  1237 			if (razor_package_remove(system, next, atomic, package,
  1238 						 install_root, count, stage))
  1239 				retval = -1;
  1240 		} else if (action == RAZOR_INSTALL_ACTION_COMMIT)
  1241 				retval = 1;
  1242 	}
  1243 
  1244 	return retval;
  1245 }
  1246 
  1247 static int
  1248 update_system(struct razor_root *root, struct razor_relocations *relocations,
  1249 	      struct razor_transaction *trans, struct razor_set *next,
  1250 	      const char *verb)
  1251 {
  1252 	struct razor_set *system, *set;
  1253 	struct razor_atomic *atomic;
  1254 	struct razor_install_iterator *ii;
  1255 	int r, retval = 0;
  1256 	char *description;
  1257 	size_t pos;
  1258 
  1259 	description = razor_concat(verb, " packages", NULL);
  1260 
  1261 	system = razor_set_ref(razor_root_get_system_set(root));
  1262 
  1263 	ii = razor_set_create_install_iterator(system, next);
  1264 
  1265 	do {
  1266 		pos = razor_install_iterator_tell(ii);
  1267 
  1268 		atomic = razor_atomic_open(description);
  1269 
  1270 		r = update_packages(trans, ii, system, next, atomic,
  1271 				    relocations, RAZOR_STAGE_SCRIPTS_PRE);
  1272 		if (r < 0) {
  1273 			fprintf(stderr, "%s aborted\n", verb);
  1274 			retval = r;
  1275 		} else {
  1276 			razor_install_iterator_seek(ii, pos);
  1277 			r = update_packages(trans, ii, system, next, atomic,
  1278 					    relocations, RAZOR_STAGE_FILES);
  1279 
  1280 			if (r == 1) {
  1281 				set = razor_install_iterator_commit_set(ii);
  1282 				razor_root_update(root, set, atomic);
  1283 				razor_set_unref(set);
  1284 			} else if (r == 0)
  1285 				razor_root_update(root, next, atomic);
  1286 
  1287 			retval = razor_atomic_commit(atomic);
  1288 			if (retval)
  1289 				fprintf(stderr, "%s\n",
  1290 					razor_atomic_get_error_msg(atomic));
  1291 			else {
  1292 				razor_install_iterator_seek(ii, pos);
  1293 				update_packages(trans, ii, system, next,
  1294 						atomic, relocations,
  1295 						RAZOR_STAGE_SCRIPTS_POST);
  1296 			}
  1297 		}
  1298 
  1299 		razor_atomic_destroy(atomic);
  1300 	} while(!retval && r == 1);
  1301 
  1302 	razor_install_iterator_destroy(ii);
  1303 
  1304 	razor_set_unref(system);
  1305 
  1306 	free(description);
  1307 
  1308 	return retval;
  1309 }
  1310 
  1311 static int
  1312 command_install_or_update(int argc, char * const argv[], int do_update)
  1313 {
  1314 	struct razor_relocations *relocations = NULL;
  1315 	struct razor_set *system, *upstream, *next, *set;
  1316 	struct razor_transaction *trans;
  1317 	struct razor_error *error = NULL;
  1318 	struct razor_atomic *atomic;
  1319 	struct razor_root *root;
  1320 	int opt, i, retval = 0, len, dependencies = 1;
  1321 	char *oldpath;
  1322 	const char *arg;
  1323 	enum {
  1324 		opt_no_dependencies = 1,
  1325 		opt_relocate = 2,
  1326 	};
  1327 	static struct razor_option options[] = {
  1328 		{ .name = "no-dependencies", .has_arg = no_argument,
  1329 		  .val = opt_no_dependencies,
  1330 		  .description = "Do not verify package dependencies" },
  1331 		{ .name = "relocate", .has_arg = required_argument,
  1332 		  .val = opt_relocate,
  1333 		  .description = "Relocate files from path OLD to NEW",
  1334 		  .arg_description = "OLD=NEW" },
  1335 	};
  1336 
  1337 	do {
  1338 		opt = razor_getopt(argc, argv, ARRAY_SIZE(options), options,
  1339 				   "rpm ...", &arg);
  1340 		switch (opt) {
  1341 			case -2:
  1342 				return 0;
  1343 			case -1:
  1344 				return 1;
  1345 			case opt_no_dependencies:
  1346 				dependencies = 0;
  1347 				break;
  1348 			case opt_relocate:
  1349 				if (strchr(arg, '=') == NULL) {
  1350 					razor_usage(argv[0],
  1351 						    ARRAY_SIZE(options),
  1352 						    options, "rpm ...");
  1353 					return 1;
  1354 				}
  1355 				len = strchr(arg, '=') - arg;
  1356 				oldpath = malloc(len + 1);
  1357 				strncpy(oldpath, arg, len);
  1358 				oldpath[len] = '\0';
  1359 				if (!relocations)
  1360 				       relocations = razor_relocations_create();
  1361 				razor_relocations_add(relocations, oldpath,
  1362 						      arg + len + 1);
  1363 				free(oldpath);
  1364 				break;
  1365 		}
  1366 	} while (opt);
  1367 
  1368 	upstream = razor_set_open(rawhide_repo_uri, 0, &error);
  1369 	if (upstream == NULL) {
  1370 		fprintf(stderr, "%s\n", razor_error_get_msg(error));
  1371 		razor_error_free(error);
  1372 		if (relocations)
  1373 			razor_relocations_destroy(relocations);
  1374 		return 1;
  1375 	}
  1376 
  1377 	if (do_update)
  1378 		atomic = razor_atomic_open("Update packages");
  1379 	else
  1380 		atomic = razor_atomic_open("Install packages");
  1381 
  1382 	if (relocations) {
  1383 		set = relocate_packages(upstream, atomic, relocations);
  1384 		if (set == NULL) {
  1385 			fprintf(stderr, "%s\n",
  1386 				razor_atomic_get_error_msg(atomic));
  1387 			razor_atomic_destroy(atomic);
  1388 			razor_set_unref(upstream);
  1389 			return 1;
  1390 		}
  1391 		razor_set_unref(upstream);
  1392 		upstream = set;
  1393 	}
  1394 
  1395 	root = razor_root_open(install_root, &error);
  1396 	if (root == NULL) {
  1397 		fprintf(stderr, "%s\n", razor_error_get_msg(error));
  1398 		razor_error_free(error);
  1399 		razor_atomic_destroy(atomic);
  1400 		razor_set_unref(upstream);
  1401 		if (relocations)
  1402 			razor_relocations_destroy(relocations);
  1403 		return 1;
  1404 	}
  1405 
  1406 	system = razor_root_get_system_set(root);
  1407 	trans = razor_transaction_create(system, upstream);
  1408 
  1409 	if (optind == argc && do_update)
  1410 		razor_transaction_update_all(trans);
  1411 	for (i = optind; i < argc; i++) {
  1412 		if (do_update &&
  1413 		    mark_packages_for_update(trans, system, argv[i]))
  1414 			continue;
  1415 		if (mark_packages_for_update(trans, upstream, argv[i]) == 0) {
  1416 			fprintf(stderr, "no package matched %s\n", argv[i]);
  1417 			razor_transaction_destroy(trans);
  1418 			razor_root_close(root);
  1419 			razor_set_unref(upstream);
  1420 			razor_atomic_destroy(atomic);
  1421 			if (relocations)
  1422 				razor_relocations_destroy(relocations);
  1423 			return 1;
  1424 		}
  1425 	}
  1426 
  1427 	if (dependencies) {
  1428 		razor_transaction_resolve(trans);
  1429 		if (razor_transaction_describe(trans) > 0) {
  1430 			razor_transaction_destroy(trans);
  1431 			razor_set_unref(upstream);
  1432 			razor_root_close(root);
  1433 			razor_atomic_destroy(atomic);
  1434 			if (relocations)
  1435 				razor_relocations_destroy(relocations);
  1436 			return 1;
  1437 		}
  1438 	}
  1439 
  1440 	razor_atomic_destroy(atomic);
  1441 
  1442 	next = razor_transaction_commit(trans);
  1443 
  1444 	retval = update_system(root, relocations, trans, next,
  1445 			       do_update ? "Update" : "Install");
  1446 
  1447 	razor_set_unref(upstream);
  1448 	razor_root_close(root);
  1449 
  1450 	razor_transaction_destroy(trans);
  1451 	if (relocations)
  1452 		razor_relocations_destroy(relocations);
  1453 
  1454 	razor_set_unref(next);
  1455 
  1456 	return retval;
  1457 }
  1458 
  1459 static int
  1460 command_update(int argc, char * const argv[])
  1461 {
  1462 	return command_install_or_update(argc, argv, 1);
  1463 }
  1464 
  1465 static int
  1466 command_install(int argc, char * const argv[])
  1467 {
  1468 	return command_install_or_update(argc, argv, 0);
  1469 }
  1470 
  1471 static int
  1472 command_init(int argc, char * const argv[])
  1473 {
  1474 	int retval;
  1475 	struct razor_error *error = NULL;
  1476 
  1477 	switch (razor_getopt(argc, argv, 0, NULL, "", NULL)) {
  1478 		case -2:
  1479 			return 0;
  1480 		case -1:
  1481 			return 1;
  1482 	}
  1483 
  1484 	if (argc - optind > 0) {
  1485 		razor_usage(argv[0], 0, NULL, "");
  1486 		return 1;
  1487 	}
  1488 
  1489 	retval = razor_root_create(install_root, &error);
  1490 	if (retval) {
  1491 		fprintf(stderr, "%s\n", razor_error_get_msg(error));
  1492 		razor_error_free(error);
  1493 	} else
  1494 		printf("Created install root\n");
  1495 
  1496 	return retval;
  1497 }
  1498 
  1499 static int
  1500 command_download(int argc, char * const argv[])
  1501 {
  1502 	struct razor_error *error = NULL;
  1503 	struct razor_atomic *atomic;
  1504 	struct razor_set *set;
  1505 	struct razor_package_iterator *pi;
  1506 	struct razor_package *package;
  1507 	const char *pattern, *name, *version, *arch;
  1508 	char *url, *file, *s, filename[256];
  1509 	int matches = 0;
  1510 
  1511 	switch (razor_getopt(argc, argv, 0, NULL, "[pattern]", NULL)) {
  1512 		case -2:
  1513 			return 0;
  1514 		case -1:
  1515 			return 1;
  1516 	}
  1517 
  1518 	if (argc - optind > 1) {
  1519 		razor_usage(argv[0], 0, NULL, "[pattern]");
  1520 		return 1;
  1521 	}
  1522 
  1523 	pattern = argv[optind];
  1524 
  1525 	set = razor_set_open(rawhide_repo_uri, 0, &error);
  1526 	if (set == NULL) {
  1527 		fprintf(stderr, "%s\n", razor_error_get_msg(error));
  1528 		razor_error_free(error);
  1529 		return 1;
  1530 	}
  1531 
  1532 	atomic = razor_atomic_open("Download packages");
  1533 
  1534 	if (razor_atomic_create_dir(atomic, "file:rpms", 
  1535 				    S_IRWXU | S_IRWXG | S_IRWXO)) {
  1536 		fprintf(stderr, "%s\n", razor_atomic_get_error_msg(atomic));
  1537 		razor_atomic_destroy(atomic);
  1538 		return 1;
  1539 	}
  1540 
  1541 	if (razor_atomic_commit(atomic)) {
  1542 		fprintf(stderr, "%s\n", razor_atomic_get_error_msg(atomic));
  1543 		razor_atomic_destroy(atomic);
  1544 		return 1;
  1545 	}
  1546 	razor_atomic_destroy(atomic);
  1547 
  1548 	pi = razor_package_iterator_create(set);
  1549 	while (razor_package_iterator_next(pi, &package,
  1550 					   RAZOR_DETAIL_NAME, &name,
  1551 					   RAZOR_DETAIL_VERSION, &version,
  1552 					   RAZOR_DETAIL_ARCH, &arch,
  1553 					   RAZOR_DETAIL_LAST)) {
  1554 		if (pattern && fnmatch(pattern, name, 0) != 0)
  1555 			continue;
  1556 
  1557 		matches++;
  1558 		snprintf(filename, sizeof filename,
  1559 			 "%s-%s.%s.rpm", name, version, arch);
  1560 		s = razor_concat("Packages/", filename, NULL);
  1561 		url = razor_path_relative_to_uri(yum_url, s, NULL);
  1562 		free(s);
  1563 		file = razor_concat("rpms/", filename, NULL);
  1564 		download_if_missing(url, file);
  1565 		free(url);
  1566 		free(file);
  1567 	}
  1568 	razor_package_iterator_destroy(pi);
  1569 	razor_set_unref(set);
  1570 
  1571 	if (matches == 0)
  1572 		fprintf(stderr, "no packages matched \"%s\"\n", pattern);
  1573 	else if (matches == 1)
  1574 		fprintf(stderr, "downloaded 1 package\n");
  1575 	else
  1576 		fprintf(stderr, "downloaded %d packages\n", matches);
  1577 
  1578 	return 0;
  1579 }
  1580 
  1581 static int
  1582 command_dump(int argc, char * const argv[])
  1583 {
  1584 	struct razor_error *error = NULL;
  1585 	const char *filename;
  1586 
  1587 	switch (razor_getopt(argc, argv, 0, NULL, "[filename]", NULL)) {
  1588 		case -2:
  1589 			return 0;
  1590 		case -1:
  1591 			return 1;
  1592 	}
  1593 
  1594 	if (argc - optind > 1) {
  1595 		razor_usage(argv[0], 0, NULL, "[filename]");
  1596 		return 1;
  1597 	}
  1598 
  1599 	filename = argv[optind];
  1600 
  1601 	if (razor_dump_database(stdout, install_root, filename, &error)) {
  1602 		fprintf(stderr, "%s\n", razor_error_get_msg(error));
  1603 		razor_error_free(error);
  1604 		return 1;
  1605 	}
  1606 
  1607 	return 0;
  1608 }
  1609 
  1610 static int
  1611 command_info(int argc, char * const argv[])
  1612 {
  1613 	struct razor_error *error = NULL;
  1614 	struct razor_set *set;
  1615 	struct razor_package_iterator *pi;
  1616 	struct razor_package *package;
  1617 	struct razor_string_iterator *si;
  1618 	const char *pattern, *name, *version, *arch;
  1619 	const char *summary, *description, *url, *license;
  1620 	const char *prefix;
  1621 
  1622 	switch (razor_getopt(argc, argv, 0, NULL, "[pattern]", NULL)) {
  1623 		case -2:
  1624 			return 0;
  1625 		case -1:
  1626 			return 1;
  1627 	}
  1628 
  1629 	if (argc - optind > 1) {
  1630 		razor_usage(argv[0], 0, NULL, "[pattern]");
  1631 		return 1;
  1632 	}
  1633 
  1634 	pattern = argv[optind];
  1635 
  1636 	set = razor_root_open_read_only(install_root, &error);
  1637 	if (set == NULL) {
  1638 		fprintf(stderr, "%s\n", razor_error_get_msg(error));
  1639 		razor_error_free(error);
  1640 		return 1;
  1641 	}
  1642 
  1643 	pi = razor_package_iterator_create(set);
  1644 	while (razor_package_iterator_next(pi, &package,
  1645 					   RAZOR_DETAIL_NAME, &name,
  1646 					   RAZOR_DETAIL_VERSION, &version,
  1647 					   RAZOR_DETAIL_ARCH, &arch,
  1648 					   RAZOR_DETAIL_LAST)) {
  1649 		if (pattern && fnmatch(pattern, name, 0) != 0)
  1650 			continue;
  1651 
  1652 		printf ("Name:        %s\n", name);
  1653 		printf ("Arch:        %s\n", arch);
  1654 		printf ("Version:     %s\n", version);
  1655 
  1656 		si = razor_install_prefix_iterator_create(set, package);
  1657 		if (razor_string_iterator_next(si, &prefix)) {
  1658 			printf ("Relocations: %s\n", prefix);
  1659 			while (razor_string_iterator_next(si, &prefix))
  1660 				printf ("           : %s\n", prefix);
  1661 		}
  1662 		razor_string_iterator_destroy(si);
  1663 
  1664 		razor_package_get_details (set, package,
  1665 					   RAZOR_DETAIL_SUMMARY, &summary,
  1666 					   RAZOR_DETAIL_DESCRIPTION, &description,
  1667 					   RAZOR_DETAIL_URL, &url,
  1668 					   RAZOR_DETAIL_LICENSE, &license,
  1669 					   RAZOR_DETAIL_LAST);
  1670 
  1671 		printf ("URL:         %s\n", url);
  1672 		printf ("License:     %s\n", license);
  1673 		printf ("Summary:     %s\n", summary);
  1674 		printf ("Description:\n");
  1675 		printf ("%s\n", description);
  1676 		printf ("\n");
  1677 	}
  1678 	razor_package_iterator_destroy(pi);
  1679 	razor_set_unref(set);
  1680 
  1681 	return 0;
  1682 }
  1683 
  1684 #define SEARCH_MAX 256
  1685 
  1686 static int
  1687 command_search(int argc, char * const argv[])
  1688 {
  1689 	struct razor_error *error = NULL;
  1690 	struct razor_set *set;
  1691 	struct razor_package_iterator *pi;
  1692 	struct razor_package *package;
  1693 	char pattern[SEARCH_MAX];
  1694 	const char *name, *version, *arch;
  1695 	const char *summary, *description, *url, *license;
  1696 
  1697 	switch (razor_getopt(argc, argv, 0, NULL, "pattern", NULL)) {
  1698 		case -2:
  1699 			return 0;
  1700 		case -1:
  1701 			return 1;
  1702 	}
  1703 
  1704 	if (argc != 2) {
  1705 		razor_usage(argv[0], 0, NULL, "pattern");
  1706 		return 1;
  1707 	}
  1708 
  1709 	snprintf(pattern, sizeof pattern, "*%s*", argv[1]);
  1710 
  1711 	set = razor_set_open(rawhide_repo_uri, 0, &error);
  1712 	if (set == NULL) {
  1713 		fprintf(stderr, "%s\n", razor_error_get_msg(error));
  1714 		razor_error_free(error);
  1715 		return 1;
  1716 	}
  1717 
  1718 	pi = razor_package_iterator_create(set);
  1719 	while (razor_package_iterator_next(pi, &package,
  1720 					   RAZOR_DETAIL_NAME, &name,
  1721 					   RAZOR_DETAIL_VERSION, &version,
  1722 					   RAZOR_DETAIL_ARCH, &arch,
  1723 					   RAZOR_DETAIL_SUMMARY, &summary,
  1724 					   RAZOR_DETAIL_DESCRIPTION, &description,
  1725 					   RAZOR_DETAIL_URL, &url,
  1726 					   RAZOR_DETAIL_LICENSE, &license,
  1727 					   RAZOR_DETAIL_LAST)) {
  1728 		if (!fnmatch(pattern, name, FNM_CASEFOLD) ||
  1729 		    !fnmatch(pattern, url, FNM_CASEFOLD) ||
  1730 		    !fnmatch(pattern, summary, FNM_CASEFOLD) ||
  1731 		    !fnmatch(pattern, description, FNM_CASEFOLD))
  1732 			printf("%s-%s.%s: %s\n", name, version, arch, summary);
  1733 	}
  1734 	razor_package_iterator_destroy(pi);
  1735 	razor_set_unref(set);
  1736 
  1737 	return 0;
  1738 }
  1739 
  1740 static struct {
  1741 	const char *name;
  1742 	const char *description;
  1743 	int (*func)(int argc, char * const argv[]);
  1744 } razor_commands[] = {
  1745 	{ "diff", "Show diff between two package sets", command_diff },
  1746 	{ "download", "Download packages", command_download },
  1747 	{ "dump", "Low-level database dump (for debugging)", command_dump },
  1748 	{ "help", "List available commands", command_help },
  1749 #if HAVE_RPMLIB
  1750 	{ "import-rpmdb", "Import the system rpm database",
  1751 	  command_import_rpmdb },
  1752 #endif
  1753 	{ "import-rpms", "Import rpms from the given directory",
  1754 	  command_import_rpms },
  1755 	{ "import-yum", "Import yum metadata files", command_import_yum },
  1756 	{ "info", "Display package details", command_info },
  1757 	{ "init", "Init razor root", command_init },
  1758 	{ "install", "Install rpm", command_install },
  1759 	{ "list", "List all packages", command_list },
  1760 	{ "list-conflicts", "List all conflicts for the given package",
  1761 	  command_list_conflicts },
  1762 	{ "list-file-packages", "List packages owning file",
  1763 	  command_list_file_packages },
  1764 	{ "list-files", "List files for package set", command_list_files },
  1765 	{ "list-obsoletes", "List all obsoletes for the given package",
  1766 	  command_list_obsoletes },
  1767 	{ "list-package-files", "List files in package",
  1768 	  command_list_package_files },
  1769 	{ "list-provides", "List all provides for the given package",
  1770 	  command_list_provides },
  1771 	{ "list-requires", "List all requires for the given package",
  1772 	  command_list_requires },
  1773 	{ "list-scripts", "List all scripts for the given package",
  1774 	  command_list_scripts },
  1775 	{ "remove", "Remove specified packages", command_remove },
  1776 	{ "search", "Search package details", command_search },
  1777 	{ "update", "Update all or specified packages", command_update },
  1778 	{ "what-provides", "List the packages that have the given provides",
  1779 	  command_what_provides },
  1780 	{ "what-requires", "List the packages that have the given requires",
  1781 	  command_what_requires },
  1782 };
  1783 
  1784 static int
  1785 command_help(int argc, char * const argv[])
  1786 {
  1787 	int i;
  1788 
  1789 	printf("Available commands:\n");
  1790 	for (i = 0; i < ARRAY_SIZE(razor_commands); i++)
  1791 		printf("  %-20s%s\n",
  1792 		       razor_commands[i].name, razor_commands[i].description);
  1793 	printf("\nType \"razor --help\" for help about global options\n"
  1794 	       "or \"razor <command> --help\" for help about a particular "
  1795 	       "command's options.\n");
  1796 
  1797 	return 0;
  1798 }
  1799 
  1800 int
  1801 main(int argc, char *argv[])
  1802 {
  1803 	char *repo, *root;
  1804 	int i, opt, main_optind;
  1805 	int do_help_commands = 0;
  1806 	enum {
  1807 		opt_database = 1,
  1808 		opt_help,
  1809 		opt_help_commands,
  1810 		opt_root,
  1811 		opt_url,
  1812 	};
  1813 	struct option options[] = {
  1814 		{ .name = "database", .has_arg = required_argument,
  1815 		  .val = opt_database },
  1816 		{ .name = "help", .has_arg = no_argument, .val = opt_help },
  1817 		{ .name = "help-commands", .has_arg = no_argument,
  1818 		  .flag = &do_help_commands, .val = TRUE },
  1819 		{ .name = "root", .has_arg = required_argument,
  1820 		  .val = opt_root },
  1821 		{ .name = "url", .has_arg = required_argument, .val = opt_url },
  1822 		{ 0, }
  1823 	};
  1824 
  1825 	repo = getenv("RAZOR_REPO");
  1826 	if (repo != NULL)
  1827 		repo_filename = repo;
  1828 
  1829 	root = getenv("RAZOR_ROOT");
  1830 	if (root != NULL)
  1831 		install_root = root;
  1832 
  1833 	yum_url = getenv("YUM_URL");
  1834 	if (yum_url == NULL)
  1835 		yum_url = YUM_URL;
  1836 
  1837 	if (getenv("RAZOR_NO_ROOT_NAME_CHECKS"))
  1838 		razor_disable_root_name_checks(1);
  1839 
  1840 	optind = 1;
  1841 	opterr = 0;
  1842 
  1843 	while ((opt = getopt_long(argc, argv, "+", options, NULL)) != -1) {
  1844 		switch (opt) {
  1845 			case opt_database:
  1846 				razor_set_database_uri(optarg);
  1847 				break;
  1848 			case opt_help:
  1849 			default:
  1850 				printf("Usage: razor [global-options] command "
  1851 				       "[command-options-and-arguments]\n\n");
  1852 				printf("Options:\n");
  1853 				printf("  --help              "
  1854 				       "Show this help message and exit\n");
  1855 				printf("  --help-commands     List commands\n");
  1856 				printf("  --database=URI      "
  1857 				       "Use alternative database\n");
  1858 				printf("  --root=URI          "
  1859 				       "Use URI as top level directory\n");
  1860 				printf("  --url=URI           "
  1861 				       "Use URI as upstream repository\n");
  1862 				return opt != opt_help;
  1863 			case opt_root:
  1864 				install_root = optarg;
  1865 				break;
  1866 			case opt_url:
  1867 				yum_url = optarg;
  1868 				break;
  1869 			case 0:
  1870 				break;
  1871 		}
  1872 	}
  1873 
  1874 	main_optind = optind;
  1875 	optind = 1;
  1876 
  1877 	if (do_help_commands || argc - main_optind < 1) {
  1878 		command_help(argc - main_optind, argv + main_optind);
  1879 		return 1;
  1880 	}
  1881 
  1882 	init_uri_handler();
  1883 
  1884 	for (i = 0; i < ARRAY_SIZE(razor_commands); i++)
  1885 		if (strcmp(razor_commands[i].name, argv[main_optind]) == 0)
  1886 			return razor_commands[i].func(argc - main_optind,
  1887 						      argv + main_optind);
  1888 
  1889 	command_help(argc - main_optind, argv + main_optind);
  1890 	return 1;
  1891 }