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