src/main.c
author J. Ali Harlow <ali@juiblex.co.uk>
Mon Jul 11 13:54:54 2016 +0100 (2016-07-11)
changeset 488 7c6d932f291f
parent 475 008c75a5e08d
child 489 9d0a04089d22
permissions -rw-r--r--
Release 0.6.3.104
     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 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 	char buffer[512];
   745 
   746 	switch (razor_getopt(argc, argv, 0, NULL, "", NULL)) {
   747 		case -2:
   748 			return 0;
   749 		case -1:
   750 			return 1;
   751 	}
   752 
   753 	if (argc - optind > 0) {
   754 		razor_usage(argv[0], 0, NULL, "");
   755 		return 1;
   756 	}
   757 
   758 	printf("importing from '%s'.\n", yum_url);
   759 
   760 	set = razor_set_create_from_yum(yum_url);
   761 	if (set == NULL)
   762 		return 1;
   763 	atomic = razor_atomic_open("Yum import repository");
   764 	razor_set_write(set, atomic, rawhide_repo_uri, RAZOR_SECTION_ALL);
   765 	retval = razor_atomic_commit(atomic);
   766 	razor_set_unref(set);
   767 	if (retval)
   768 		fprintf(stderr, "%s\n", razor_atomic_get_error_msg(atomic));
   769 	else
   770 		printf("wrote %s\n", rawhide_repo_uri);
   771 	razor_atomic_destroy(atomic);
   772 
   773 	return retval;
   774 }
   775 
   776 #if HAVE_RPMLIB
   777 static int
   778 command_import_rpmdb(int argc, char * const argv[])
   779 {
   780 	struct razor_set *set;
   781 	struct razor_root *root;
   782 	struct razor_error *error = NULL;
   783 	struct razor_atomic *atomic;
   784 	int retval;
   785 
   786 	switch (razor_getopt(argc, argv, 0, NULL, "", NULL)) {
   787 		case -2:
   788 			return 0;
   789 		case -1:
   790 			return 1;
   791 	}
   792 
   793 	if (argc - optind > 0) {
   794 		razor_usage(argv[0], 0, NULL, "");
   795 		return 1;
   796 	}
   797 
   798 	root = razor_root_open(install_root, &error);
   799 	if (root == NULL) {
   800 		fprintf(stderr, "%s\n", razor_error_get_msg(error));
   801 		razor_error_free(error);
   802 		return 1;
   803 	}
   804 
   805 	set = razor_set_create_from_rpmdb();
   806 	if (set == NULL)
   807 		return 1;
   808 
   809 	atomic = razor_atomic_open("Import RPM database");
   810 
   811 	retval = razor_root_update(root, set, atomic);
   812 
   813 	if (retval)
   814 		fprintf(stderr, "%s\n", razor_atomic_get_error_msg(atomic));
   815 
   816 	razor_atomic_destroy(atomic);
   817 
   818 	razor_root_close(root);
   819 
   820 	return retval;
   821 }
   822 #endif
   823 
   824 static int
   825 mark_packages_for_update(struct razor_transaction *trans,
   826 			 struct razor_set *set, const char *pattern)
   827 {
   828 	struct razor_package_iterator *pi;
   829 	struct razor_package *package;
   830 	const char *name;
   831 	int matches = 0;
   832 
   833 	pi = razor_package_iterator_create(set);
   834 	while (razor_package_iterator_next(pi, &package,
   835 					   RAZOR_DETAIL_NAME, &name,
   836 					   RAZOR_DETAIL_LAST)) {
   837 		if (pattern && fnmatch(pattern, name, 0) == 0) {
   838 			razor_transaction_update_package(trans, package);
   839 			matches++;
   840 		}
   841 	}
   842 	razor_package_iterator_destroy(pi);
   843 
   844 	return matches;
   845 }
   846 
   847 static int
   848 mark_packages_for_removal(struct razor_transaction *trans,
   849 			  struct razor_set *set, const char *pattern)
   850 {
   851 	struct razor_package_iterator *pi;
   852 	struct razor_package *package;
   853 	const char *name;
   854 	int matches = 0;
   855 
   856 	pi = razor_package_iterator_create(set);
   857 	while (razor_package_iterator_next(pi, &package,
   858 					   RAZOR_DETAIL_NAME, &name,
   859 					   RAZOR_DETAIL_LAST)) {
   860 		if (pattern && fnmatch(pattern, name, 0) == 0) {
   861 			razor_transaction_remove_package(trans, package);
   862 			matches++;
   863 		}
   864 	}
   865 	razor_package_iterator_destroy(pi);
   866 
   867 	return matches;
   868 }
   869 
   870 static int
   871 command_remove(int argc, char * const argv[])
   872 {
   873 	struct razor_set *system, *upstream, *next;
   874 	struct razor_transaction *trans;
   875 	struct razor_error *error = NULL;
   876 	struct razor_root *root;
   877 	int i, retval;
   878 
   879 	switch (razor_getopt(argc, argv, 0, NULL, "pattern ...", NULL)) {
   880 		case -2:
   881 			return 0;
   882 		case -1:
   883 			return 1;
   884 	}
   885 
   886 	root = razor_root_open(install_root, &error);
   887 	if (root == NULL) {
   888 		fprintf(stderr, "%s\n", razor_error_get_msg(error));
   889 		razor_error_free(error);
   890 		return 1;
   891 	}
   892 
   893 	system = razor_root_get_system_set(root);
   894 	upstream = razor_set_create_without_root();
   895 	trans = razor_transaction_create(system, upstream);
   896 	razor_set_unref(upstream);
   897 	for (i = optind; i < argc; i++) {
   898 		if (mark_packages_for_removal(trans, system, argv[i]) == 0) {
   899 			fprintf(stderr, "no match for %s\n", argv[i]);
   900 			razor_transaction_destroy(trans);
   901 			razor_root_close(root);
   902 			return 1;
   903 		}
   904 	}
   905 
   906 	razor_transaction_resolve(trans);
   907 	retval = razor_transaction_describe(trans);
   908 	if (retval) {
   909 		razor_transaction_destroy(trans);
   910 		razor_root_close(root);
   911 		return 1;
   912 	}
   913 
   914 	next = razor_transaction_commit(trans);
   915 
   916 	retval = update_system(root, NULL, trans, next, "Remove");
   917 
   918 	razor_transaction_destroy(trans);
   919 	razor_root_close(root);
   920 	razor_set_unref(next);
   921 
   922 	return retval;
   923 }
   924 
   925 static void
   926 print_diff(enum razor_diff_action action,
   927 	   struct razor_package *package,
   928 	   const char *name,
   929 	   const char *version,
   930 	   const char *arch,
   931 	   void *data)
   932 {
   933 	if (action == RAZOR_DIFF_ACTION_ADD)
   934 		printf("install %s-%s.%s\n", name, version, arch);
   935 	if (action == RAZOR_DIFF_ACTION_REMOVE)
   936 		printf("remove %s-%s.%s\n", name, version, arch);
   937 }
   938 
   939 static int
   940 command_diff(int argc, char * const argv[])
   941 {
   942 	struct razor_error *error = NULL;
   943 	struct razor_set *set, *updated;
   944 
   945 	switch (razor_getopt(argc, argv, 0, NULL, "", NULL)) {
   946 		case -2:
   947 			return 0;
   948 		case -1:
   949 			return 1;
   950 	}
   951 
   952 	if (argc - optind > 0) {
   953 		razor_usage(argv[0], 0, NULL, "");
   954 		return 1;
   955 	}
   956 
   957 	set = razor_root_open_read_only(install_root, &error);
   958 	if (set)
   959 		updated = razor_set_open(rawhide_repo_uri, 0, &error);
   960 	else
   961 		updated = NULL;
   962 	if (updated == NULL) {
   963 		fprintf(stderr, "%s\n", razor_error_get_msg(error));
   964 		razor_error_free(error);
   965 		if (set)
   966 			razor_set_unref(set);
   967 		return 1;
   968 	}
   969 
   970 	razor_set_diff(set, updated, print_diff, NULL);
   971 
   972 	razor_set_unref(set);
   973 	razor_set_unref(updated);
   974 
   975 	return 0;
   976 }
   977 
   978 static int
   979 command_import_rpms(int argc, char * const argv[])
   980 {
   981 	DIR *dir;
   982 	struct dirent *de;
   983 	struct razor_importer *importer;
   984 	struct razor_set *set;
   985 	struct razor_rpm *rpm;
   986 	struct razor_error *error=NULL;
   987 	struct razor_atomic *atomic;
   988 	int len, imported_count = 0;
   989 	char filename[256];
   990 	const char *dirname;
   991 	int retval;
   992 
   993 	switch (razor_getopt(argc, argv, 0, NULL, "dir", NULL)) {
   994 		case -2:
   995 			return 0;
   996 		case -1:
   997 			return 1;
   998 	}
   999 
  1000 	if (argc - optind != 1) {
  1001 		razor_usage(argv[0], 0, NULL, "dir");
  1002 		return 1;
  1003 	}
  1004 
  1005 	dirname = argv[optind];
  1006 
  1007 	dir = opendir(dirname);
  1008 	if (dir == NULL) {
  1009 		fprintf(stderr, "couldn't read dir %s\n", dirname);
  1010 		return -1;
  1011 	}
  1012 
  1013 	importer = razor_importer_create();
  1014 
  1015 	while (de = readdir(dir), de != NULL) {
  1016 		len = strlen(de->d_name);
  1017 		if (len < 5 || strcmp(de->d_name + len - 4, ".rpm") != 0)
  1018 			continue;
  1019 		snprintf(filename, sizeof filename,
  1020 			 "%s/%s", dirname, de->d_name);
  1021 		rpm = razor_rpm_open(filename, &error);
  1022 		if (rpm == NULL) {
  1023 			fprintf(stderr, "%s\n", razor_error_get_msg(error));
  1024 			razor_error_free(error);
  1025 			error=NULL;
  1026 			continue;
  1027 		}
  1028 		if (razor_importer_add_rpm(importer, rpm)) {
  1029 			fprintf(stderr, "couldn't import %s\n", filename);
  1030 			break;
  1031 		}
  1032 		razor_rpm_close(rpm);
  1033 
  1034 		printf("\rimporting %d", ++imported_count);
  1035 		fflush(stdout);
  1036 	}
  1037 
  1038 	if (de != NULL) {
  1039 		razor_importer_destroy(importer);
  1040 		return -1;
  1041 	}
  1042 
  1043 	printf("\nsaving\n");
  1044 	set = razor_importer_finish(importer);
  1045 
  1046 	atomic = razor_atomic_open("Update system database");
  1047 	razor_set_write(set, atomic, repo_filename, RAZOR_SECTION_ALL);
  1048 	razor_set_unref(set);
  1049 	retval = razor_atomic_commit(atomic);
  1050 	if (retval)
  1051 		fprintf(stderr, "%s\n", razor_atomic_get_error_msg(atomic));
  1052 	else
  1053 		printf("wrote %s\n", repo_filename);
  1054 	razor_atomic_destroy(atomic);
  1055 
  1056 	return retval;
  1057 }
  1058 
  1059 static char *
  1060 rpm_filename(const char *name, const char *version, const char *arch)
  1061 {
  1062  	const char *v;
  1063  
  1064  	/* Skip epoch */
  1065 	v = strchr(version, ':');
  1066  	if (v != NULL)
  1067  		v = v + 1;
  1068  	else
  1069 		v = version;
  1070 
  1071 	return razor_concat(name, "-", v, ".", arch, ".rpm", NULL);
  1072 }
  1073 
  1074 static struct razor_set *
  1075 relocate_packages(struct razor_set *set, struct razor_atomic *atomic,
  1076 		  struct razor_relocations *relocations)
  1077 {
  1078 	int i;
  1079 	struct razor_importer *importer;
  1080 	struct razor_property_iterator *prop_iter;
  1081 	struct razor_package_iterator *pkg_iter;
  1082  	struct razor_file_iterator *file_iter;
  1083  	struct razor_package *package;
  1084 	struct razor_property *property;
  1085 	struct razor_rpm *rpm;
  1086 	struct razor_error *error=NULL;
  1087 	const char *name, *version, *arch, *summary, *desc, *url, *license;
  1088 	const char *preunprog, *preun, *postunprog, *postun;
  1089 	const char *install_prefix;
  1090 	const char *const *prefixes;
  1091 	char *file, *s, *uri, *filename;
  1092 	uint32_t flags;
  1093 
  1094 	importer = razor_importer_create();
  1095 	pkg_iter = razor_package_iterator_create(set);
  1096 
  1097 	while (razor_package_iterator_next(pkg_iter, &package,
  1098 					   RAZOR_DETAIL_NAME, &name,
  1099 					   RAZOR_DETAIL_VERSION, &version,
  1100 					   RAZOR_DETAIL_ARCH, &arch,
  1101 					   RAZOR_DETAIL_SUMMARY, &summary,
  1102 					   RAZOR_DETAIL_DESCRIPTION, &desc,
  1103 					   RAZOR_DETAIL_URL, &url,
  1104 					   RAZOR_DETAIL_LICENSE, &license,
  1105 					   RAZOR_DETAIL_PREUNPROG, &preunprog,
  1106 					   RAZOR_DETAIL_PREUN, &preun,
  1107 					   RAZOR_DETAIL_POSTUNPROG, &postunprog,
  1108 					   RAZOR_DETAIL_POSTUN, &postun,
  1109 					   RAZOR_DETAIL_LAST)) {
  1110 		filename = rpm_filename(name, version, arch);
  1111 		s = razor_concat("Packages/", filename, NULL);
  1112 		uri = razor_path_relative_to_uri(yum_url, s, NULL);
  1113 		free(s);
  1114 		free(filename);
  1115 		rpm = razor_rpm_open(uri, &error);
  1116 		free(uri);
  1117 		if (rpm == NULL) {
  1118 			razor_atomic_propagate_error(atomic, error, NULL);
  1119 			razor_package_iterator_destroy(pkg_iter);
  1120 			razor_importer_destroy(importer);
  1121 			return NULL;
  1122 		}
  1123 
  1124 		razor_relocations_set_rpm(relocations, rpm);
  1125 
  1126 		razor_importer_begin_package(importer, name, version, arch);
  1127 		razor_importer_add_details(importer,
  1128 					   summary, desc, url, license);
  1129 
  1130 		razor_rpm_get_details(rpm, RAZOR_DETAIL_PREFIXES, &prefixes,
  1131 				      RAZOR_DETAIL_LAST);
  1132 		for (i = 0; prefixes && prefixes[i]; i++) {
  1133 			install_prefix = razor_relocations_apply(relocations,
  1134 								 prefixes[i]);
  1135 			razor_importer_add_install_prefix(importer,
  1136 							  install_prefix);
  1137 		}
  1138 
  1139 		razor_rpm_close(rpm);
  1140 
  1141 		prop_iter = razor_property_iterator_create(set, package);
  1142 		while (razor_property_iterator_next(prop_iter, &property,
  1143 						    &name, &flags, &version))
  1144 			razor_importer_add_property(importer,
  1145 						    name, flags, version);
  1146 		razor_property_iterator_destroy(prop_iter);
  1147 
  1148 		file_iter = razor_file_iterator_create(set, package, 0);
  1149 		while (razor_file_iterator_next(file_iter, &name)) {
  1150 			name = razor_relocations_apply(relocations, name);
  1151 			razor_importer_add_file(importer, name);
  1152 		}
  1153 		razor_file_iterator_destroy(file_iter);
  1154 
  1155 		razor_importer_add_script(importer, RAZOR_PROPERTY_PREUN,
  1156 					  preunprog, preun);
  1157 		razor_importer_add_script(importer, RAZOR_PROPERTY_POSTUN,
  1158 					  postunprog, postun);
  1159 
  1160 		razor_importer_finish_package(importer);
  1161 	}
  1162 
  1163 	razor_package_iterator_destroy(pkg_iter);
  1164 	return razor_importer_finish(importer);
  1165 }
  1166 
  1167 static int
  1168 install_package(struct razor_transaction *trans, struct razor_set *set,
  1169 		struct razor_atomic *atomic, struct razor_package *package,
  1170 		struct razor_relocations *relocations, int install_count,
  1171 		enum razor_stage_type stage)
  1172 {
  1173 	int retval;
  1174 	const char *name, *version, *arch;
  1175 	char *file, *s, *uri;
  1176 	struct razor_rpm *rpm;
  1177 	struct razor_error *error=NULL;
  1178 
  1179 	razor_package_get_details(set, package,
  1180 				  RAZOR_DETAIL_NAME, &name,
  1181 				  RAZOR_DETAIL_VERSION, &version,
  1182 				  RAZOR_DETAIL_ARCH, &arch,
  1183 				  RAZOR_DETAIL_LAST);
  1184 
  1185 	s = rpm_filename(name, version, arch);
  1186 	file = razor_concat("Packages/", s, NULL);
  1187 	free(s);
  1188 	uri = razor_path_relative_to_uri(yum_url, file, NULL);
  1189 	free(file);
  1190 
  1191 	if (stage & RAZOR_STAGE_SCRIPTS_PRE)
  1192 		printf("install %s\n", uri);
  1193 
  1194 	rpm = razor_rpm_open(uri, &error);
  1195 	free(uri);
  1196 	if (rpm == NULL) {
  1197 		razor_atomic_propagate_error(atomic, error, NULL);
  1198 		fprintf(stderr, "%s\n", razor_error_get_msg(error));
  1199 		return -1;
  1200 	}
  1201 	if (relocations)
  1202 		razor_rpm_set_relocations(rpm, relocations);
  1203 	razor_transaction_fixup_package(trans, package, rpm);
  1204 	retval = razor_rpm_install(rpm, atomic, install_root, install_count,
  1205 				   stage);
  1206 	if (retval < 0) {
  1207 		s = rpm_filename(name, version, arch);
  1208 		fprintf(stderr, "%s: %s\n", s,
  1209 			razor_atomic_get_error_msg(atomic));
  1210 		free(s);
  1211 	}
  1212 	razor_rpm_close(rpm);
  1213 	return retval;
  1214 }
  1215 
  1216 /*
  1217  * Returns 0 on success, -1 on failure and 1 if a RAZOR_INSTALL_ACTION_COMMIT
  1218  * is met (in which case the action is consumed).
  1219  */
  1220 static int
  1221 update_packages(struct razor_transaction *trans,
  1222 		struct razor_install_iterator *ii, struct razor_set *system,
  1223 		struct razor_set *next, struct razor_atomic *atomic,
  1224 		struct razor_relocations *relocations,
  1225 		enum razor_stage_type stage)
  1226 {
  1227 	struct razor_package *package;
  1228 	enum razor_install_action action;
  1229 	int retval = 0, count;
  1230 
  1231 	while (!retval && razor_install_iterator_next(ii, &package, &action,
  1232 						      &count)) {
  1233 		if (action == RAZOR_INSTALL_ACTION_ADD) {
  1234 			if (install_package(trans, next, atomic, package,
  1235 					    relocations, count, stage))
  1236 				retval = -1;
  1237 		} else if (action == RAZOR_INSTALL_ACTION_REMOVE) {
  1238 			if (razor_package_remove(system, next, atomic, package,
  1239 						 install_root, count, stage))
  1240 				retval = -1;
  1241 		} else if (action == RAZOR_INSTALL_ACTION_COMMIT)
  1242 				retval = 1;
  1243 	}
  1244 
  1245 	return retval;
  1246 }
  1247 
  1248 static int
  1249 update_system(struct razor_root *root, struct razor_relocations *relocations,
  1250 	      struct razor_transaction *trans, struct razor_set *next,
  1251 	      const char *verb)
  1252 {
  1253 	struct razor_set *system, *set;
  1254 	struct razor_atomic *atomic;
  1255 	struct razor_install_iterator *ii;
  1256 	int r, retval = 0;
  1257 	char *description;
  1258 	size_t pos;
  1259 
  1260 	description = razor_concat(verb, " packages", NULL);
  1261 
  1262 	system = razor_set_ref(razor_root_get_system_set(root));
  1263 
  1264 	ii = razor_set_create_install_iterator(system, next);
  1265 
  1266 	do {
  1267 		pos = razor_install_iterator_tell(ii);
  1268 
  1269 		atomic = razor_atomic_open(description);
  1270 
  1271 		r = update_packages(trans, ii, system, next, atomic,
  1272 				    relocations, RAZOR_STAGE_SCRIPTS_PRE);
  1273 		if (r < 0) {
  1274 			fprintf(stderr, "%s aborted\n", verb);
  1275 			retval = r;
  1276 		} else {
  1277 			razor_install_iterator_seek(ii, pos);
  1278 			r = update_packages(trans, ii, system, next, atomic,
  1279 					    relocations, RAZOR_STAGE_FILES);
  1280 
  1281 			if (r == 1) {
  1282 				set = razor_install_iterator_commit_set(ii);
  1283 				razor_root_update(root, set, atomic);
  1284 				razor_set_unref(set);
  1285 			} else if (r == 0)
  1286 				razor_root_update(root, next, atomic);
  1287 
  1288 			retval = razor_atomic_commit(atomic);
  1289 			if (retval)
  1290 				fprintf(stderr, "%s\n",
  1291 					razor_atomic_get_error_msg(atomic));
  1292 			else {
  1293 				razor_install_iterator_seek(ii, pos);
  1294 				update_packages(trans, ii, system, next,
  1295 						atomic, relocations,
  1296 						RAZOR_STAGE_SCRIPTS_POST);
  1297 			}
  1298 		}
  1299 
  1300 		razor_atomic_destroy(atomic);
  1301 	} while(!retval && r == 1);
  1302 
  1303 	razor_install_iterator_destroy(ii);
  1304 
  1305 	razor_set_unref(system);
  1306 
  1307 	free(description);
  1308 
  1309 	return retval;
  1310 }
  1311 
  1312 static int
  1313 command_install_or_update(int argc, char * const argv[], int do_update)
  1314 {
  1315 	struct razor_relocations *relocations = NULL;
  1316 	struct razor_set *system, *upstream, *next, *set;
  1317 	struct razor_transaction *trans;
  1318 	struct razor_error *error = NULL;
  1319 	struct razor_atomic *atomic;
  1320 	struct razor_root *root;
  1321 	int opt, i, retval = 0, len, dependencies = 1;
  1322 	char *oldpath;
  1323 	const char *arg;
  1324 	enum {
  1325 		opt_no_dependencies = 1,
  1326 		opt_relocate = 2,
  1327 	};
  1328 	static struct razor_option options[] = {
  1329 		{ .name = "no-dependencies", .has_arg = no_argument,
  1330 		  .val = opt_no_dependencies,
  1331 		  .description = "Do not verify package dependencies" },
  1332 		{ .name = "relocate", .has_arg = required_argument,
  1333 		  .val = opt_relocate,
  1334 		  .description = "Relocate files from path OLD to NEW",
  1335 		  .arg_description = "OLD=NEW" },
  1336 	};
  1337 
  1338 	do {
  1339 		opt = razor_getopt(argc, argv, ARRAY_SIZE(options), options,
  1340 				   "rpm ...", &arg);
  1341 		switch (opt) {
  1342 			case -2:
  1343 				return 0;
  1344 			case -1:
  1345 				return 1;
  1346 			case opt_no_dependencies:
  1347 				dependencies = 0;
  1348 				break;
  1349 			case opt_relocate:
  1350 				if (strchr(arg, '=') == NULL) {
  1351 					razor_usage(argv[0],
  1352 						    ARRAY_SIZE(options),
  1353 						    options, "rpm ...");
  1354 					return 1;
  1355 				}
  1356 				len = strchr(arg, '=') - arg;
  1357 				oldpath = malloc(len + 1);
  1358 				strncpy(oldpath, arg, len);
  1359 				oldpath[len] = '\0';
  1360 				if (!relocations)
  1361 				       relocations = razor_relocations_create();
  1362 				razor_relocations_add(relocations, oldpath,
  1363 						      arg + len + 1);
  1364 				free(oldpath);
  1365 				break;
  1366 		}
  1367 	} while (opt);
  1368 
  1369 	upstream = razor_set_open(rawhide_repo_uri, 0, &error);
  1370 	if (upstream == NULL) {
  1371 		fprintf(stderr, "%s\n", razor_error_get_msg(error));
  1372 		razor_error_free(error);
  1373 		if (relocations)
  1374 			razor_relocations_destroy(relocations);
  1375 		return 1;
  1376 	}
  1377 
  1378 	if (do_update)
  1379 		atomic = razor_atomic_open("Update packages");
  1380 	else
  1381 		atomic = razor_atomic_open("Install packages");
  1382 
  1383 	if (relocations) {
  1384 		set = relocate_packages(upstream, atomic, relocations);
  1385 		if (set == NULL) {
  1386 			fprintf(stderr, "%s\n",
  1387 				razor_atomic_get_error_msg(atomic));
  1388 			razor_atomic_destroy(atomic);
  1389 			razor_set_unref(upstream);
  1390 			return 1;
  1391 		}
  1392 		razor_set_unref(upstream);
  1393 		upstream = set;
  1394 	}
  1395 
  1396 	root = razor_root_open(install_root, &error);
  1397 	if (root == NULL) {
  1398 		fprintf(stderr, "%s\n", razor_error_get_msg(error));
  1399 		razor_error_free(error);
  1400 		razor_atomic_destroy(atomic);
  1401 		razor_set_unref(upstream);
  1402 		if (relocations)
  1403 			razor_relocations_destroy(relocations);
  1404 		return 1;
  1405 	}
  1406 
  1407 	system = razor_root_get_system_set(root);
  1408 	trans = razor_transaction_create(system, upstream);
  1409 
  1410 	if (optind == argc && do_update)
  1411 		razor_transaction_update_all(trans);
  1412 	for (i = optind; i < argc; i++) {
  1413 		if (do_update &&
  1414 		    mark_packages_for_update(trans, system, argv[i]))
  1415 			continue;
  1416 		if (mark_packages_for_update(trans, upstream, argv[i]) == 0) {
  1417 			fprintf(stderr, "no package matched %s\n", argv[i]);
  1418 			razor_transaction_destroy(trans);
  1419 			razor_root_close(root);
  1420 			razor_set_unref(upstream);
  1421 			razor_atomic_destroy(atomic);
  1422 			if (relocations)
  1423 				razor_relocations_destroy(relocations);
  1424 			return 1;
  1425 		}
  1426 	}
  1427 
  1428 	if (dependencies) {
  1429 		razor_transaction_resolve(trans);
  1430 		if (razor_transaction_describe(trans) > 0) {
  1431 			razor_transaction_destroy(trans);
  1432 			razor_set_unref(upstream);
  1433 			razor_root_close(root);
  1434 			razor_atomic_destroy(atomic);
  1435 			if (relocations)
  1436 				razor_relocations_destroy(relocations);
  1437 			return 1;
  1438 		}
  1439 	}
  1440 
  1441 	razor_atomic_destroy(atomic);
  1442 
  1443 	next = razor_transaction_commit(trans);
  1444 
  1445 	retval = update_system(root, relocations, trans, next,
  1446 			       do_update ? "Update" : "Install");
  1447 
  1448 	razor_set_unref(upstream);
  1449 	razor_root_close(root);
  1450 
  1451 	razor_transaction_destroy(trans);
  1452 	if (relocations)
  1453 		razor_relocations_destroy(relocations);
  1454 
  1455 	razor_set_unref(next);
  1456 
  1457 	return retval;
  1458 }
  1459 
  1460 static int
  1461 command_update(int argc, char * const argv[])
  1462 {
  1463 	return command_install_or_update(argc, argv, 1);
  1464 }
  1465 
  1466 static int
  1467 command_install(int argc, char * const argv[])
  1468 {
  1469 	return command_install_or_update(argc, argv, 0);
  1470 }
  1471 
  1472 static int
  1473 command_init(int argc, char * const argv[])
  1474 {
  1475 	int retval;
  1476 	struct razor_error *error = NULL;
  1477 
  1478 	switch (razor_getopt(argc, argv, 0, NULL, "", NULL)) {
  1479 		case -2:
  1480 			return 0;
  1481 		case -1:
  1482 			return 1;
  1483 	}
  1484 
  1485 	if (argc - optind > 0) {
  1486 		razor_usage(argv[0], 0, NULL, "");
  1487 		return 1;
  1488 	}
  1489 
  1490 	retval = razor_root_create(install_root, &error);
  1491 	if (retval) {
  1492 		fprintf(stderr, "%s\n", razor_error_get_msg(error));
  1493 		razor_error_free(error);
  1494 	} else
  1495 		printf("Created install root\n");
  1496 
  1497 	return retval;
  1498 }
  1499 
  1500 static int
  1501 command_download(int argc, char * const argv[])
  1502 {
  1503 	struct razor_error *error = NULL;
  1504 	struct razor_atomic *atomic;
  1505 	struct razor_set *set;
  1506 	struct razor_package_iterator *pi;
  1507 	struct razor_package *package;
  1508 	const char *pattern, *name, *version, *arch;
  1509 	char *url, *file, *s, filename[256];
  1510 	int matches = 0;
  1511 
  1512 	switch (razor_getopt(argc, argv, 0, NULL, "[pattern]", NULL)) {
  1513 		case -2:
  1514 			return 0;
  1515 		case -1:
  1516 			return 1;
  1517 	}
  1518 
  1519 	if (argc - optind > 1) {
  1520 		razor_usage(argv[0], 0, NULL, "[pattern]");
  1521 		return 1;
  1522 	}
  1523 
  1524 	pattern = argv[optind];
  1525 
  1526 	set = razor_set_open(rawhide_repo_uri, 0, &error);
  1527 	if (set == NULL) {
  1528 		fprintf(stderr, "%s\n", razor_error_get_msg(error));
  1529 		razor_error_free(error);
  1530 		return 1;
  1531 	}
  1532 
  1533 	atomic = razor_atomic_open("Download packages");
  1534 
  1535 	if (razor_atomic_create_dir(atomic, "file:rpms", 
  1536 				    S_IRWXU | S_IRWXG | S_IRWXO)) {
  1537 		fprintf(stderr, "%s\n", razor_atomic_get_error_msg(atomic));
  1538 		razor_atomic_destroy(atomic);
  1539 		return 1;
  1540 	}
  1541 
  1542 	if (razor_atomic_commit(atomic)) {
  1543 		fprintf(stderr, "%s\n", razor_atomic_get_error_msg(atomic));
  1544 		razor_atomic_destroy(atomic);
  1545 		return 1;
  1546 	}
  1547 	razor_atomic_destroy(atomic);
  1548 
  1549 	pi = razor_package_iterator_create(set);
  1550 	while (razor_package_iterator_next(pi, &package,
  1551 					   RAZOR_DETAIL_NAME, &name,
  1552 					   RAZOR_DETAIL_VERSION, &version,
  1553 					   RAZOR_DETAIL_ARCH, &arch,
  1554 					   RAZOR_DETAIL_LAST)) {
  1555 		if (pattern && fnmatch(pattern, name, 0) != 0)
  1556 			continue;
  1557 
  1558 		matches++;
  1559 		snprintf(filename, sizeof filename,
  1560 			 "%s-%s.%s.rpm", name, version, arch);
  1561 		s = razor_concat("Packages/", filename, NULL);
  1562 		url = razor_path_relative_to_uri(yum_url, s, NULL);
  1563 		free(s);
  1564 		file = razor_concat("rpms/", filename, NULL);
  1565 		download_if_missing(url, file);
  1566 		free(url);
  1567 		free(file);
  1568 	}
  1569 	razor_package_iterator_destroy(pi);
  1570 	razor_set_unref(set);
  1571 
  1572 	if (matches == 0)
  1573 		fprintf(stderr, "no packages matched \"%s\"\n", pattern);
  1574 	else if (matches == 1)
  1575 		fprintf(stderr, "downloaded 1 package\n");
  1576 	else
  1577 		fprintf(stderr, "downloaded %d packages\n", matches);
  1578 
  1579 	return 0;
  1580 }
  1581 
  1582 static int
  1583 command_dump(int argc, char * const argv[])
  1584 {
  1585 	struct razor_error *error = NULL;
  1586 	const char *filename;
  1587 
  1588 	switch (razor_getopt(argc, argv, 0, NULL, "[filename]", NULL)) {
  1589 		case -2:
  1590 			return 0;
  1591 		case -1:
  1592 			return 1;
  1593 	}
  1594 
  1595 	if (argc - optind > 1) {
  1596 		razor_usage(argv[0], 0, NULL, "[filename]");
  1597 		return 1;
  1598 	}
  1599 
  1600 	filename = argv[optind];
  1601 
  1602 	if (razor_dump_database(stdout, install_root, filename, &error)) {
  1603 		fprintf(stderr, "%s\n", razor_error_get_msg(error));
  1604 		razor_error_free(error);
  1605 		return 1;
  1606 	}
  1607 
  1608 	return 0;
  1609 }
  1610 
  1611 static int
  1612 command_info(int argc, char * const argv[])
  1613 {
  1614 	struct razor_error *error = NULL;
  1615 	struct razor_set *set;
  1616 	struct razor_package_iterator *pi;
  1617 	struct razor_package *package;
  1618 	struct razor_string_iterator *si;
  1619 	const char *pattern, *name, *version, *arch;
  1620 	const char *summary, *description, *url, *license;
  1621 	const char *prefix;
  1622 
  1623 	switch (razor_getopt(argc, argv, 0, NULL, "[pattern]", NULL)) {
  1624 		case -2:
  1625 			return 0;
  1626 		case -1:
  1627 			return 1;
  1628 	}
  1629 
  1630 	if (argc - optind > 1) {
  1631 		razor_usage(argv[0], 0, NULL, "[pattern]");
  1632 		return 1;
  1633 	}
  1634 
  1635 	pattern = argv[optind];
  1636 
  1637 	set = razor_root_open_read_only(install_root, &error);
  1638 	if (set == NULL) {
  1639 		fprintf(stderr, "%s\n", razor_error_get_msg(error));
  1640 		razor_error_free(error);
  1641 		return 1;
  1642 	}
  1643 
  1644 	pi = razor_package_iterator_create(set);
  1645 	while (razor_package_iterator_next(pi, &package,
  1646 					   RAZOR_DETAIL_NAME, &name,
  1647 					   RAZOR_DETAIL_VERSION, &version,
  1648 					   RAZOR_DETAIL_ARCH, &arch,
  1649 					   RAZOR_DETAIL_LAST)) {
  1650 		if (pattern && fnmatch(pattern, name, 0) != 0)
  1651 			continue;
  1652 
  1653 		printf ("Name:        %s\n", name);
  1654 		printf ("Arch:        %s\n", arch);
  1655 		printf ("Version:     %s\n", version);
  1656 
  1657 		si = razor_install_prefix_iterator_create(set, package);
  1658 		if (razor_string_iterator_next(si, &prefix)) {
  1659 			printf ("Relocations: %s\n", prefix);
  1660 			while (razor_string_iterator_next(si, &prefix))
  1661 				printf ("           : %s\n", prefix);
  1662 		}
  1663 		razor_string_iterator_destroy(si);
  1664 
  1665 		razor_package_get_details (set, package,
  1666 					   RAZOR_DETAIL_SUMMARY, &summary,
  1667 					   RAZOR_DETAIL_DESCRIPTION, &description,
  1668 					   RAZOR_DETAIL_URL, &url,
  1669 					   RAZOR_DETAIL_LICENSE, &license,
  1670 					   RAZOR_DETAIL_LAST);
  1671 
  1672 		printf ("URL:         %s\n", url);
  1673 		printf ("License:     %s\n", license);
  1674 		printf ("Summary:     %s\n", summary);
  1675 		printf ("Description:\n");
  1676 		printf ("%s\n", description);
  1677 		printf ("\n");
  1678 	}
  1679 	razor_package_iterator_destroy(pi);
  1680 	razor_set_unref(set);
  1681 
  1682 	return 0;
  1683 }
  1684 
  1685 #define SEARCH_MAX 256
  1686 
  1687 static int
  1688 command_search(int argc, char * const argv[])
  1689 {
  1690 	struct razor_error *error = NULL;
  1691 	struct razor_set *set;
  1692 	struct razor_package_iterator *pi;
  1693 	struct razor_package *package;
  1694 	char pattern[SEARCH_MAX];
  1695 	const char *name, *version, *arch;
  1696 	const char *summary, *description, *url, *license;
  1697 
  1698 	switch (razor_getopt(argc, argv, 0, NULL, "pattern", NULL)) {
  1699 		case -2:
  1700 			return 0;
  1701 		case -1:
  1702 			return 1;
  1703 	}
  1704 
  1705 	if (argc != 2) {
  1706 		razor_usage(argv[0], 0, NULL, "pattern");
  1707 		return 1;
  1708 	}
  1709 
  1710 	snprintf(pattern, sizeof pattern, "*%s*", argv[1]);
  1711 
  1712 	set = razor_set_open(rawhide_repo_uri, 0, &error);
  1713 	if (set == NULL) {
  1714 		fprintf(stderr, "%s\n", razor_error_get_msg(error));
  1715 		razor_error_free(error);
  1716 		return 1;
  1717 	}
  1718 
  1719 	pi = razor_package_iterator_create(set);
  1720 	while (razor_package_iterator_next(pi, &package,
  1721 					   RAZOR_DETAIL_NAME, &name,
  1722 					   RAZOR_DETAIL_VERSION, &version,
  1723 					   RAZOR_DETAIL_ARCH, &arch,
  1724 					   RAZOR_DETAIL_SUMMARY, &summary,
  1725 					   RAZOR_DETAIL_DESCRIPTION, &description,
  1726 					   RAZOR_DETAIL_URL, &url,
  1727 					   RAZOR_DETAIL_LICENSE, &license,
  1728 					   RAZOR_DETAIL_LAST)) {
  1729 		if (!fnmatch(pattern, name, FNM_CASEFOLD) ||
  1730 		    !fnmatch(pattern, url, FNM_CASEFOLD) ||
  1731 		    !fnmatch(pattern, summary, FNM_CASEFOLD) ||
  1732 		    !fnmatch(pattern, description, FNM_CASEFOLD))
  1733 			printf("%s-%s.%s: %s\n", name, version, arch, summary);
  1734 	}
  1735 	razor_package_iterator_destroy(pi);
  1736 	razor_set_unref(set);
  1737 
  1738 	return 0;
  1739 }
  1740 
  1741 static struct {
  1742 	const char *name;
  1743 	const char *description;
  1744 	int (*func)(int argc, char * const argv[]);
  1745 } razor_commands[] = {
  1746 	{ "diff", "Show diff between two package sets", command_diff },
  1747 	{ "download", "Download packages", command_download },
  1748 	{ "dump", "Low-level database dump (for debugging)", command_dump },
  1749 	{ "help", "List available commands", command_help },
  1750 #if HAVE_RPMLIB
  1751 	{ "import-rpmdb", "Import the system rpm database",
  1752 	  command_import_rpmdb },
  1753 #endif
  1754 	{ "import-rpms", "Import rpms from the given directory",
  1755 	  command_import_rpms },
  1756 	{ "import-yum", "Import yum metadata files", command_import_yum },
  1757 	{ "info", "Display package details", command_info },
  1758 	{ "init", "Init razor root", command_init },
  1759 	{ "install", "Install rpm", command_install },
  1760 	{ "list", "List all packages", command_list },
  1761 	{ "list-conflicts", "List all conflicts for the given package",
  1762 	  command_list_conflicts },
  1763 	{ "list-file-packages", "List packages owning file",
  1764 	  command_list_file_packages },
  1765 	{ "list-files", "List files for package set", command_list_files },
  1766 	{ "list-obsoletes", "List all obsoletes for the given package",
  1767 	  command_list_obsoletes },
  1768 	{ "list-package-files", "List files in package",
  1769 	  command_list_package_files },
  1770 	{ "list-provides", "List all provides for the given package",
  1771 	  command_list_provides },
  1772 	{ "list-requires", "List all requires for the given package",
  1773 	  command_list_requires },
  1774 	{ "list-scripts", "List all scripts for the given package",
  1775 	  command_list_scripts },
  1776 	{ "remove", "Remove specified packages", command_remove },
  1777 	{ "search", "Search package details", command_search },
  1778 	{ "update", "Update all or specified packages", command_update },
  1779 	{ "what-provides", "List the packages that have the given provides",
  1780 	  command_what_provides },
  1781 	{ "what-requires", "List the packages that have the given requires",
  1782 	  command_what_requires },
  1783 };
  1784 
  1785 static int
  1786 command_help(int argc, char * const argv[])
  1787 {
  1788 	int i;
  1789 
  1790 	printf("Available commands:\n");
  1791 	for (i = 0; i < ARRAY_SIZE(razor_commands); i++)
  1792 		printf("  %-20s%s\n",
  1793 		       razor_commands[i].name, razor_commands[i].description);
  1794 	printf("\nType \"razor --help\" for help about global options\n"
  1795 	       "or \"razor <command> --help\" for help about a particular "
  1796 	       "command's options.\n");
  1797 
  1798 	return 0;
  1799 }
  1800 
  1801 int
  1802 main(int argc, char *argv[])
  1803 {
  1804 	char *repo, *root;
  1805 	int i, opt, main_optind;
  1806 	int do_help_commands = 0;
  1807 	enum {
  1808 		opt_database = 1,
  1809 		opt_help,
  1810 		opt_help_commands,
  1811 		opt_root,
  1812 		opt_url,
  1813 	};
  1814 	struct option options[] = {
  1815 		{ .name = "database", .has_arg = required_argument,
  1816 		  .val = opt_database },
  1817 		{ .name = "help", .has_arg = no_argument, .val = opt_help },
  1818 		{ .name = "help-commands", .has_arg = no_argument,
  1819 		  .flag = &do_help_commands, .val = TRUE },
  1820 		{ .name = "root", .has_arg = required_argument,
  1821 		  .val = opt_root },
  1822 		{ .name = "url", .has_arg = required_argument, .val = opt_url },
  1823 		{ 0, }
  1824 	};
  1825 
  1826 	repo = getenv("RAZOR_REPO");
  1827 	if (repo != NULL)
  1828 		repo_filename = repo;
  1829 
  1830 	root = getenv("RAZOR_ROOT");
  1831 	if (root != NULL)
  1832 		install_root = root;
  1833 
  1834 	yum_url = getenv("YUM_URL");
  1835 	if (yum_url == NULL)
  1836 		yum_url = YUM_URL;
  1837 
  1838 	if (getenv("RAZOR_NO_ROOT_NAME_CHECKS"))
  1839 		razor_disable_root_name_checks(1);
  1840 
  1841 	optind = 1;
  1842 	opterr = 0;
  1843 
  1844 	while ((opt = getopt_long(argc, argv, "+", options, NULL)) != -1) {
  1845 		switch (opt) {
  1846 			case opt_database:
  1847 				razor_set_database_uri(optarg);
  1848 				break;
  1849 			case opt_help:
  1850 			default:
  1851 				printf("Usage: razor [global-options] command "
  1852 				       "[command-options-and-arguments]\n\n");
  1853 				printf("Options:\n");
  1854 				printf("  --help              "
  1855 				       "Show this help message and exit\n");
  1856 				printf("  --help-commands     List commands\n");
  1857 				printf("  --database=URI      "
  1858 				       "Use alternative database\n");
  1859 				printf("  --root=URI          "
  1860 				       "Use URI as top level directory\n");
  1861 				printf("  --url=URI           "
  1862 				       "Use URI as upstream repository\n");
  1863 				return opt != opt_help;
  1864 			case opt_root:
  1865 				install_root = optarg;
  1866 				break;
  1867 			case opt_url:
  1868 				yum_url = optarg;
  1869 				break;
  1870 			case 0:
  1871 				break;
  1872 		}
  1873 	}
  1874 
  1875 	main_optind = optind;
  1876 	optind = 1;
  1877 
  1878 	if (do_help_commands || argc - main_optind < 1) {
  1879 		command_help(argc - main_optind, argv + main_optind);
  1880 		return 1;
  1881 	}
  1882 
  1883 	init_uri_handler();
  1884 
  1885 	for (i = 0; i < ARRAY_SIZE(razor_commands); i++)
  1886 		if (strcmp(razor_commands[i].name, argv[main_optind]) == 0)
  1887 			return razor_commands[i].func(argc - main_optind,
  1888 						      argv + main_optind);
  1889 
  1890 	command_help(argc - main_optind, argv + main_optind);
  1891 	return 1;
  1892 }