src/main.c
author J. Ali Harlow <ali@juiblex.co.uk>
Thu Oct 09 17:27:41 2014 +0100 (2014-10-09)
changeset 455 df914f383f5c
parent 447 0a5e583393e1
child 457 51a084acef49
permissions -rw-r--r--
Support downloading from local repository even without libcurl

Using the --url option of the razor executable, it is possible
to specify a yum repository on the local machine (eg., on installation
media) and import from there, eg.,:

C> razor --url file:///d:/ import-yum

This will be handled by libcurl if available but if not, an internal
copy routine will be used.

Note that if Microsoft's KTM implementation of atomic transactions is
used, then the current directory must support atomic transactions
(also improve error messages for this, and other, cases).
     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_set_unref(system);
  1379 
  1380 	free(description);
  1381 
  1382 	return retval;
  1383 }
  1384 
  1385 static int
  1386 command_install_or_update(int argc, char * const argv[], int do_update)
  1387 {
  1388 	struct razor_relocations *relocations = NULL;
  1389 	struct razor_set *system, *upstream, *next, *set;
  1390 	struct razor_transaction *trans;
  1391 	struct razor_error *error = NULL;
  1392 	struct razor_atomic *atomic;
  1393 	struct razor_root *root;
  1394 	int opt, i, retval = 0, len, dependencies = 1;
  1395 	char *oldpath;
  1396 	const char *arg;
  1397 	enum {
  1398 		opt_no_dependencies = 1,
  1399 		opt_relocate = 2,
  1400 	};
  1401 	static struct razor_option options[] = {
  1402 		{ .name = "no-dependencies", .has_arg = no_argument,
  1403 		  .val = opt_no_dependencies,
  1404 		  .description = "Do not verify package dependencies" },
  1405 		{ .name = "relocate", .has_arg = required_argument,
  1406 		  .val = opt_relocate,
  1407 		  .description = "Relocate files from path OLD to NEW",
  1408 		  .arg_description = "OLD=NEW" },
  1409 	};
  1410 
  1411 	do {
  1412 		opt = razor_getopt(argc, argv, ARRAY_SIZE(options), options,
  1413 				   "rpm ...", &arg);
  1414 		switch (opt) {
  1415 			case -2:
  1416 				return 0;
  1417 			case -1:
  1418 				return 1;
  1419 			case opt_no_dependencies:
  1420 				dependencies = 0;
  1421 				break;
  1422 			case opt_relocate:
  1423 				if (strchr(arg, '=') == NULL) {
  1424 					razor_usage(argv[0],
  1425 						    ARRAY_SIZE(options),
  1426 						    options, "rpm ...");
  1427 					return 1;
  1428 				}
  1429 				len = strchr(arg, '=') - arg;
  1430 				oldpath = malloc(len + 1);
  1431 				strncpy(oldpath, arg, len);
  1432 				oldpath[len] = '\0';
  1433 				if (!relocations)
  1434 				       relocations = razor_relocations_create();
  1435 				razor_relocations_add(relocations, oldpath,
  1436 						      arg + len + 1);
  1437 				free(oldpath);
  1438 				break;
  1439 		}
  1440 	} while (opt);
  1441 
  1442 	upstream = razor_set_open(rawhide_repo_filename, 0, &error);
  1443 	if (upstream == NULL) {
  1444 		fprintf(stderr, "%s\n", razor_error_get_msg(error));
  1445 		razor_error_free(error);
  1446 		return 1;
  1447 	}
  1448 
  1449 	if (do_update)
  1450 		atomic = razor_atomic_open("Update packages");
  1451 	else
  1452 		atomic = razor_atomic_open("Install packages");
  1453 
  1454 	if (relocations) {
  1455 		set = relocate_packages(upstream, atomic, relocations);
  1456 		if (set == NULL) {
  1457 			fprintf(stderr, "%s\n",
  1458 				razor_atomic_get_error_msg(atomic));
  1459 			razor_atomic_destroy(atomic);
  1460 			razor_set_unref(upstream);
  1461 			return 1;
  1462 		}
  1463 		razor_set_unref(upstream);
  1464 		upstream = set;
  1465 	}
  1466 
  1467 	root = razor_root_open(install_root, &error);
  1468 	if (root == NULL) {
  1469 		fprintf(stderr, "%s\n", razor_error_get_msg(error));
  1470 		razor_error_free(error);
  1471 		razor_atomic_destroy(atomic);
  1472 		razor_set_unref(upstream);
  1473 		if (relocations)
  1474 			razor_relocations_destroy(relocations);
  1475 		return 1;
  1476 	}
  1477 
  1478 	system = razor_root_get_system_set(root);
  1479 	trans = razor_transaction_create(system, upstream);
  1480 
  1481 	if (optind == argc && do_update)
  1482 		razor_transaction_update_all(trans);
  1483 	for (i = optind; i < argc; i++) {
  1484 		if (do_update &&
  1485 		    mark_packages_for_update(trans, system, argv[i]))
  1486 			continue;
  1487 		if (mark_packages_for_update(trans, upstream, argv[i]) == 0) {
  1488 			fprintf(stderr, "no package matched %s\n", argv[i]);
  1489 			razor_transaction_destroy(trans);
  1490 			razor_root_close(root);
  1491 			razor_set_unref(upstream);
  1492 			razor_atomic_destroy(atomic);
  1493 			if (relocations)
  1494 				razor_relocations_destroy(relocations);
  1495 			return 1;
  1496 		}
  1497 	}
  1498 
  1499 	if (dependencies) {
  1500 		razor_transaction_resolve(trans);
  1501 		if (razor_transaction_describe(trans) > 0) {
  1502 			razor_transaction_destroy(trans);
  1503 			razor_set_unref(upstream);
  1504 			razor_root_close(root);
  1505 			razor_atomic_destroy(atomic);
  1506 			if (relocations)
  1507 				razor_relocations_destroy(relocations);
  1508 			return 1;
  1509 		}
  1510 	}
  1511 
  1512 	if (razor_atomic_create_dir(atomic, "rpms",
  1513 				    S_IRWXU | S_IRWXG | S_IRWXO) ||
  1514 	    razor_atomic_commit(atomic)) {
  1515 		fprintf(stderr, "%s\n", razor_atomic_get_error_msg(atomic));
  1516 		razor_transaction_destroy(trans);
  1517 		razor_set_unref(upstream);
  1518 		razor_root_close(root);
  1519 		razor_atomic_destroy(atomic);
  1520 		if (relocations)
  1521 			razor_relocations_destroy(relocations);
  1522 		return 1;
  1523 	}
  1524 
  1525 	razor_atomic_destroy(atomic);
  1526 
  1527 	next = razor_transaction_commit(trans);
  1528 
  1529 	if (download_packages(system, next) < 0) {
  1530 		razor_set_unref(next);
  1531 		razor_transaction_destroy(trans);
  1532 		razor_set_unref(upstream);
  1533 		razor_root_close(root);
  1534 		if (relocations)
  1535 			razor_relocations_destroy(relocations);
  1536                 return 1;
  1537         }
  1538 
  1539 	retval = update_system(root, relocations, trans, next,
  1540 			       do_update ? "Update" : "Install");
  1541 
  1542 	razor_set_unref(upstream);
  1543 	razor_root_close(root);
  1544 
  1545 	razor_transaction_destroy(trans);
  1546 	if (relocations)
  1547 		razor_relocations_destroy(relocations);
  1548 
  1549 	razor_set_unref(next);
  1550 
  1551 	return retval;
  1552 }
  1553 
  1554 static int
  1555 command_update(int argc, char * const argv[])
  1556 {
  1557 	return command_install_or_update(argc, argv, 1);
  1558 }
  1559 
  1560 static int
  1561 command_install(int argc, char * const argv[])
  1562 {
  1563 	return command_install_or_update(argc, argv, 0);
  1564 }
  1565 
  1566 static int
  1567 command_init(int argc, char * const argv[])
  1568 {
  1569 	int retval;
  1570 	struct razor_error *error = NULL;
  1571 
  1572 	switch (razor_getopt(argc, argv, 0, NULL, "", NULL)) {
  1573 		case -2:
  1574 			return 0;
  1575 		case -1:
  1576 			return 1;
  1577 	}
  1578 
  1579 	if (argc - optind > 0) {
  1580 		razor_usage(argv[0], 0, NULL, "");
  1581 		return 1;
  1582 	}
  1583 
  1584 	retval = razor_root_create(install_root, &error);
  1585 	if (retval) {
  1586 		fprintf(stderr, "%s\n", razor_error_get_msg(error));
  1587 		razor_error_free(error);
  1588 	} else
  1589 		printf("Created install root\n");
  1590 
  1591 	return retval;
  1592 }
  1593 
  1594 static int
  1595 command_download(int argc, char * const argv[])
  1596 {
  1597 	struct razor_error *error = NULL;
  1598 	struct razor_atomic *atomic;
  1599 	struct razor_set *set;
  1600 	struct razor_package_iterator *pi;
  1601 	struct razor_package *package;
  1602 	const char *pattern, *name, *version, *arch;
  1603 	char url[256], file[256];
  1604 	int matches = 0;
  1605 
  1606 	switch (razor_getopt(argc, argv, 0, NULL, "[pattern]", NULL)) {
  1607 		case -2:
  1608 			return 0;
  1609 		case -1:
  1610 			return 1;
  1611 	}
  1612 
  1613 	if (argc - optind > 1) {
  1614 		razor_usage(argv[0], 0, NULL, "[pattern]");
  1615 		return 1;
  1616 	}
  1617 
  1618 	pattern = argv[optind];
  1619 
  1620 	set = razor_set_open(rawhide_repo_filename, 0, &error);
  1621 	if (set == NULL) {
  1622 		fprintf(stderr, "%s\n", razor_error_get_msg(error));
  1623 		razor_error_free(error);
  1624 		return 1;
  1625 	}
  1626 
  1627 	atomic = razor_atomic_open("Download packages");
  1628 
  1629 	if (razor_atomic_create_dir(atomic, "rpms", 
  1630 				    S_IRWXU | S_IRWXG | S_IRWXO)) {
  1631 		fprintf(stderr, "%s\n", razor_atomic_get_error_msg(atomic));
  1632 		razor_atomic_destroy(atomic);
  1633 		return 1;
  1634 	}
  1635 
  1636 	if (razor_atomic_commit(atomic)) {
  1637 		fprintf(stderr, "%s\n", razor_atomic_get_error_msg(atomic));
  1638 		razor_atomic_destroy(atomic);
  1639 		return 1;
  1640 	}
  1641 	razor_atomic_destroy(atomic);
  1642 
  1643 	pi = razor_package_iterator_create(set);
  1644 	while (razor_package_iterator_next(pi, &package,
  1645 					   RAZOR_DETAIL_NAME, &name,
  1646 					   RAZOR_DETAIL_VERSION, &version,
  1647 					   RAZOR_DETAIL_ARCH, &arch,
  1648 					   RAZOR_DETAIL_LAST)) {
  1649 		if (pattern && fnmatch(pattern, name, 0) != 0)
  1650 			continue;
  1651 
  1652 		matches++;
  1653 		snprintf(url, sizeof url,
  1654 			 "%s/Packages/%s-%s.%s.rpm",
  1655 			 yum_url, name, version, arch);
  1656 		snprintf(file, sizeof file,
  1657 			 "rpms/%s-%s.%s.rpm", name, version, arch);
  1658 		download_if_missing(url, file);
  1659 	}
  1660 	razor_package_iterator_destroy(pi);
  1661 	razor_set_unref(set);
  1662 
  1663 	if (matches == 0)
  1664 		fprintf(stderr, "no packages matched \"%s\"\n", pattern);
  1665 	else if (matches == 1)
  1666 		fprintf(stderr, "downloaded 1 package\n");
  1667 	else
  1668 		fprintf(stderr, "downloaded %d packages\n", matches);
  1669 
  1670 	return 0;
  1671 }
  1672 
  1673 static int
  1674 command_info(int argc, char * const argv[])
  1675 {
  1676 	struct razor_error *error = NULL;
  1677 	struct razor_set *set;
  1678 	struct razor_package_iterator *pi;
  1679 	struct razor_package *package;
  1680 	const char *pattern, *name, *version, *arch;
  1681 	const char *summary, *description, *url, *license;
  1682 
  1683 	switch (razor_getopt(argc, argv, 0, NULL, "[pattern]", 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, "[pattern]");
  1692 		return 1;
  1693 	}
  1694 
  1695 	pattern = argv[optind];
  1696 
  1697 	set = razor_root_open_read_only(install_root, &error);
  1698 	if (set == NULL) {
  1699 		fprintf(stderr, "%s\n", razor_error_get_msg(error));
  1700 		razor_error_free(error);
  1701 		return 1;
  1702 	}
  1703 
  1704 	pi = razor_package_iterator_create(set);
  1705 	while (razor_package_iterator_next(pi, &package,
  1706 					   RAZOR_DETAIL_NAME, &name,
  1707 					   RAZOR_DETAIL_VERSION, &version,
  1708 					   RAZOR_DETAIL_ARCH, &arch,
  1709 					   RAZOR_DETAIL_LAST)) {
  1710 		if (pattern && fnmatch(pattern, name, 0) != 0)
  1711 			continue;
  1712 
  1713 		razor_package_get_details (set, package,
  1714 					   RAZOR_DETAIL_SUMMARY, &summary,
  1715 					   RAZOR_DETAIL_DESCRIPTION, &description,
  1716 					   RAZOR_DETAIL_URL, &url,
  1717 					   RAZOR_DETAIL_LICENSE, &license,
  1718 					   RAZOR_DETAIL_LAST);
  1719 
  1720 		printf ("Name:        %s\n", name);
  1721 		printf ("Arch:        %s\n", arch);
  1722 		printf ("Version:     %s\n", version);
  1723 		printf ("URL:         %s\n", url);
  1724 		printf ("License:     %s\n", license);
  1725 		printf ("Summary:     %s\n", summary);
  1726 		printf ("Description:\n");
  1727 		printf ("%s\n", description);
  1728 		printf ("\n");
  1729 	}
  1730 	razor_package_iterator_destroy(pi);
  1731 	razor_set_unref(set);
  1732 
  1733 	return 0;
  1734 }
  1735 
  1736 #define SEARCH_MAX 256
  1737 
  1738 static int
  1739 command_search(int argc, char * const argv[])
  1740 {
  1741 	struct razor_error *error = NULL;
  1742 	struct razor_set *set;
  1743 	struct razor_package_iterator *pi;
  1744 	struct razor_package *package;
  1745 	char pattern[SEARCH_MAX];
  1746 	const char *name, *version, *arch;
  1747 	const char *summary, *description, *url, *license;
  1748 
  1749 	switch (razor_getopt(argc, argv, 0, NULL, "pattern", NULL)) {
  1750 		case -2:
  1751 			return 0;
  1752 		case -1:
  1753 			return 1;
  1754 	}
  1755 
  1756 	if (argc != 2) {
  1757 		razor_usage(argv[0], 0, NULL, "pattern");
  1758 		return 1;
  1759 	}
  1760 
  1761 	snprintf(pattern, sizeof pattern, "*%s*", argv[1]);
  1762 
  1763 	set = razor_set_open(rawhide_repo_filename, 0, &error);
  1764 	if (set == NULL) {
  1765 		fprintf(stderr, "%s\n", razor_error_get_msg(error));
  1766 		razor_error_free(error);
  1767 		return 1;
  1768 	}
  1769 
  1770 	pi = razor_package_iterator_create(set);
  1771 	while (razor_package_iterator_next(pi, &package,
  1772 					   RAZOR_DETAIL_NAME, &name,
  1773 					   RAZOR_DETAIL_VERSION, &version,
  1774 					   RAZOR_DETAIL_ARCH, &arch,
  1775 					   RAZOR_DETAIL_SUMMARY, &summary,
  1776 					   RAZOR_DETAIL_DESCRIPTION, &description,
  1777 					   RAZOR_DETAIL_URL, &url,
  1778 					   RAZOR_DETAIL_LICENSE, &license,
  1779 					   RAZOR_DETAIL_LAST)) {
  1780 		if (!fnmatch(pattern, name, FNM_CASEFOLD) ||
  1781 		    !fnmatch(pattern, url, FNM_CASEFOLD) ||
  1782 		    !fnmatch(pattern, summary, FNM_CASEFOLD) ||
  1783 		    !fnmatch(pattern, description, FNM_CASEFOLD))
  1784 			printf("%s-%s.%s: %s\n", name, version, arch, summary);
  1785 	}
  1786 	razor_package_iterator_destroy(pi);
  1787 	razor_set_unref(set);
  1788 
  1789 	return 0;
  1790 }
  1791 
  1792 static struct {
  1793 	const char *name;
  1794 	const char *description;
  1795 	int (*func)(int argc, char * const argv[]);
  1796 } razor_commands[] = {
  1797 	{ "diff", "Show diff between two package sets", command_diff },
  1798 	{ "download", "Download packages", command_download },
  1799 	{ "help", "List available commands", command_help },
  1800 #if HAVE_RPMLIB
  1801 	{ "import-rpmdb", "Import the system rpm database",
  1802 	  command_import_rpmdb },
  1803 #endif
  1804 	{ "import-rpms", "Import rpms from the given directory",
  1805 	  command_import_rpms },
  1806 	{ "import-yum", "Import yum metadata files", command_import_yum },
  1807 	{ "info", "Display package details", command_info },
  1808 	{ "init", "Init razor root", command_init },
  1809 	{ "install", "Install rpm", command_install },
  1810 	{ "list", "List all packages", command_list },
  1811 	{ "list-conflicts", "List all conflicts for the given package",
  1812 	  command_list_conflicts },
  1813 	{ "list-file-packages", "List packages owning file",
  1814 	  command_list_file_packages },
  1815 	{ "list-files", "List files for package set", command_list_files },
  1816 	{ "list-obsoletes", "List all obsoletes for the given package",
  1817 	  command_list_obsoletes },
  1818 	{ "list-package-files", "List files in package",
  1819 	  command_list_package_files },
  1820 	{ "list-provides", "List all provides for the given package",
  1821 	  command_list_provides },
  1822 	{ "list-requires", "List all requires for the given package",
  1823 	  command_list_requires },
  1824 	{ "list-scripts", "List all scripts for the given package",
  1825 	  command_list_scripts },
  1826 	{ "remove", "Remove specified packages", command_remove },
  1827 	{ "search", "Search package details", command_search },
  1828 	{ "update", "Update all or specified packages", command_update },
  1829 	{ "what-provides", "List the packages that have the given provides",
  1830 	  command_what_provides },
  1831 	{ "what-requires", "List the packages that have the given requires",
  1832 	  command_what_requires },
  1833 };
  1834 
  1835 static int
  1836 command_help(int argc, char * const argv[])
  1837 {
  1838 	int i;
  1839 
  1840 	printf("Available commands:\n");
  1841 	for (i = 0; i < ARRAY_SIZE(razor_commands); i++)
  1842 		printf("  %-20s%s\n",
  1843 		       razor_commands[i].name, razor_commands[i].description);
  1844 	printf("\nType \"razor --help\" for help about global options\n"
  1845 	       "or \"razor <command> --help\" for help about a particular "
  1846 	       "command's options.\n");
  1847 
  1848 	return 0;
  1849 }
  1850 
  1851 int
  1852 main(int argc, char *argv[])
  1853 {
  1854 	char *repo, *root;
  1855 	int i, opt, main_optind;
  1856 	int do_help_commands = 0;
  1857 	enum {
  1858 		opt_database = 1,
  1859 		opt_help,
  1860 		opt_help_commands,
  1861 		opt_root,
  1862 		opt_url,
  1863 	};
  1864 	struct option options[] = {
  1865 		{ .name = "database", .has_arg = required_argument,
  1866 		  .val = opt_database },
  1867 		{ .name = "help", .has_arg = no_argument, .val = opt_help },
  1868 		{ .name = "help-commands", .has_arg = no_argument,
  1869 		  .flag = &do_help_commands, .val = TRUE },
  1870 		{ .name = "root", .has_arg = required_argument,
  1871 		  .val = opt_root },
  1872 		{ .name = "url", .has_arg = required_argument, .val = opt_url },
  1873 		{ 0, }
  1874 	};
  1875 
  1876 	repo = getenv("RAZOR_REPO");
  1877 	if (repo != NULL)
  1878 		repo_filename = repo;
  1879 
  1880 	root = getenv("RAZOR_ROOT");
  1881 	if (root != NULL)
  1882 		install_root = root;
  1883 
  1884 	yum_url = getenv("YUM_URL");
  1885 	if (yum_url == NULL)
  1886 		yum_url = YUM_URL;
  1887 
  1888 	if (getenv("RAZOR_NO_ROOT_NAME_CHECKS"))
  1889 		razor_disable_root_name_checks(1);
  1890 
  1891 	optind = 1;
  1892 	opterr = 0;
  1893 
  1894 	while ((opt = getopt_long(argc, argv, "+", options, NULL)) != -1) {
  1895 		switch (opt) {
  1896 			case opt_database:
  1897 				razor_set_database_path(optarg);
  1898 				break;
  1899 			case opt_help:
  1900 			default:
  1901 				printf("Usage: razor [global-options] command "
  1902 				       "[command-options-and-arguments]\n\n");
  1903 				printf("Options:\n");
  1904 				printf("  --help              "
  1905 				       "Show this help message and exit\n");
  1906 				printf("  --help-commands     List commands\n");
  1907 				printf("  --database=PATH     "
  1908 				       "Use alternative database\n");
  1909 				printf("  --root=ROOT         "
  1910 				       "Use ROOT as top level directory\n");
  1911 				printf("  --url=URL           "
  1912 				       "Use URL as upstream repository\n");
  1913 				return opt != opt_help;
  1914 			case opt_root:
  1915 				install_root = optarg;
  1916 				break;
  1917 			case opt_url:
  1918 				yum_url = optarg;
  1919 				break;
  1920 			case 0:
  1921 				break;
  1922 		}
  1923 	}
  1924 
  1925 	main_optind = optind;
  1926 	optind = 1;
  1927 
  1928 	if (do_help_commands || argc - main_optind < 1) {
  1929 		command_help(argc - main_optind, argv + main_optind);
  1930 		return 1;
  1931 	}
  1932 
  1933 	for (i = 0; i < ARRAY_SIZE(razor_commands); i++)
  1934 		if (strcmp(razor_commands[i].name, argv[main_optind]) == 0)
  1935 			return razor_commands[i].func(argc - main_optind,
  1936 						      argv + main_optind);
  1937 
  1938 	command_help(argc - main_optind, argv + main_optind);
  1939 	return 1;
  1940 }