src/main.c
author J. Ali Harlow <ali@juiblex.co.uk>
Thu Feb 09 20:45:27 2012 +0000 (2012-02-09)
changeset 418 33b825d3128d
parent 412 810d9ba06afd
child 421 408c66ad463d
permissions -rw-r--r--
Add transaction barriers
These allow packages to be installed and removed which have scripts
that depend on each other when atomic transactions are involved.
Note that yum supports pre, but not other requires flags. post will
need similar support to the post scripts themselves pulling in the
requires flags from the rpms. Likewise preun and postun will need
similar handling to those scrips since the requires flags will need
to be stored in the razor database.
     1 /*
     2  * Copyright (C) 2008  Kristian Høgsberg <krh@redhat.com>
     3  * Copyright (C) 2008  Red Hat, Inc
     4  * Copyright (C) 2009, 2011-2012  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 HAVE_CURL
    36 #include <curl/curl.h>
    37 #endif
    38 #include <fnmatch.h>
    39 #include <errno.h>
    40 #include "razor.h"
    41 
    42 static const char system_repo_filename[] = "system.rzdb";
    43 static const char next_repo_filename[] = "system-next.rzdb";
    44 static const char rawhide_repo_filename[] = "rawhide.rzdb";
    45 static const char *install_root = "";
    46 static const char *repo_filename = system_repo_filename;
    47 static const char *yum_url;
    48 
    49 #define ARRAY_SIZE(a) (sizeof(a) / sizeof((a)[0]))
    50 
    51 static int
    52 update_packages(struct razor_transaction *trans,
    53 		struct razor_install_iterator *ii, struct razor_set *system,
    54 		struct razor_set *next, struct razor_atomic *atomic,
    55 		struct razor_relocations *relocations,
    56 		enum razor_stage_type stage);
    57 static int
    58 update_system(const char *install_root, struct razor_relocations *relocations,
    59 	      struct razor_transaction *trans, struct razor_set *system,
    60 	      struct razor_set *next, const char *verb);
    61 
    62 static struct razor_package_iterator *
    63 create_iterator_from_argv(struct razor_set *set, int argc, const char *argv[])
    64 {
    65 	struct razor_package_query *query;
    66 	struct razor_package_iterator *iter;
    67 	struct razor_package *package;
    68 	const char *name, *pattern;
    69 	int i, count;
    70 
    71 	if (argc == 0)
    72 		return razor_package_iterator_create(set);
    73 
    74 	query = razor_package_query_create(set);
    75 
    76 	for (i = 0; i < argc; i++) {
    77 		iter = razor_package_iterator_create(set);
    78 		pattern = argv[i];
    79 		count = 0;
    80 		while (razor_package_iterator_next(iter, &package,
    81 						   RAZOR_DETAIL_NAME, &name,
    82 						   RAZOR_DETAIL_LAST)) {
    83 			if (fnmatch(pattern, name, 0) != 0)
    84 				continue;
    85 
    86 			razor_package_query_add_package(query, package);
    87 			count++;
    88 		}
    89 		razor_package_iterator_destroy(iter);
    90 
    91 		if (count == 0)
    92 			fprintf(stderr,
    93 				"no package matches \"%s\"\n", pattern);
    94 	}
    95 
    96 	return razor_package_query_finish(query);
    97 }
    98 
    99 #define LIST_PACKAGES_ONLY_NAMES 0x01
   100 
   101 static void
   102 list_packages(struct razor_package_iterator *iter, uint32_t flags)
   103 {
   104 	struct razor_package *package;
   105 	const char *name, *version, *arch;
   106 
   107 	while (razor_package_iterator_next(iter, &package,
   108 					   RAZOR_DETAIL_NAME, &name,
   109 					   RAZOR_DETAIL_VERSION, &version,
   110 					   RAZOR_DETAIL_ARCH, &arch,
   111 					   RAZOR_DETAIL_LAST)) {
   112 		if (flags & LIST_PACKAGES_ONLY_NAMES)
   113 			printf("%s\n", name);
   114 		else
   115 			printf("%s-%s.%s\n", name, version, arch);
   116 	}
   117 }
   118 
   119 static int
   120 command_list(int argc, const char *argv[])
   121 {
   122 	struct razor_package_iterator *pi;
   123 	struct razor_atomic *atomic;
   124 	struct razor_set *set;
   125 	uint32_t flags = 0;
   126 	int i = 0;
   127 
   128 	if (i < argc && strcmp(argv[i], "--only-names") == 0) {
   129 		flags |= LIST_PACKAGES_ONLY_NAMES;
   130 		i++;
   131 	}
   132 
   133 	atomic = razor_atomic_open("List installed packages");
   134 	set = razor_root_open_read_only(install_root, atomic);
   135 	if (set == NULL) {
   136 		fprintf(stderr, "%s\n", razor_atomic_get_error_msg(atomic));
   137 		razor_atomic_destroy(atomic);
   138 		return 1;
   139 	}
   140 
   141 	pi = create_iterator_from_argv(set, argc - i, argv + i);
   142 	list_packages(pi, flags);
   143 	razor_package_iterator_destroy(pi);
   144 	razor_set_unref(set);
   145 	razor_atomic_destroy(atomic);
   146 
   147 	return 0;
   148 }
   149 
   150 static void
   151 list_package_properties(struct razor_set *set,
   152 			struct razor_package *package, uint32_t type)
   153 {
   154 	struct razor_property_iterator *pi;
   155 	struct razor_property *property;
   156 	const char *name, *version;
   157 	uint32_t flags;
   158 
   159 	pi = razor_property_iterator_create(set, package);
   160 	while (razor_property_iterator_next(pi, &property,
   161 					    &name, &flags, &version)) {
   162 		if ((flags & RAZOR_PROPERTY_TYPE_MASK) != type)
   163 			continue;
   164 		printf("%s", name);
   165 		if (version[0] != '\0')
   166 			printf(" %s %s",
   167 			       razor_property_relation_to_string(property),
   168 			       version);
   169 
   170 		if (flags & ~(RAZOR_PROPERTY_RELATION_MASK | RAZOR_PROPERTY_TYPE_MASK)) {
   171 			printf(" [");
   172 			if (flags & RAZOR_PROPERTY_PRE)
   173 				printf(" pre");
   174 			if (flags & RAZOR_PROPERTY_POST)
   175 				printf(" post");
   176 			if (flags & RAZOR_PROPERTY_PREUN)
   177 				printf(" preun");
   178 			if (flags & RAZOR_PROPERTY_POSTUN)
   179 				printf(" postun");
   180 			printf(" ]");
   181 		}
   182 		printf("\n");
   183 	}
   184 	razor_property_iterator_destroy(pi);
   185 }
   186 
   187 static int
   188 list_properties(int argc, const char *argv[], uint32_t type)
   189 {
   190 	struct razor_set *set;
   191 	struct razor_atomic *atomic;
   192 	struct razor_package *package;
   193 	struct razor_package_iterator *pi;
   194 	const char *name, *version, *arch;
   195 
   196 	atomic = razor_atomic_open("List package properties");
   197 	set = razor_root_open_read_only(install_root, atomic);
   198 	if (set == NULL) {
   199 		fprintf(stderr, "%s\n", razor_atomic_get_error_msg(atomic));
   200 		razor_atomic_destroy(atomic);
   201 		return 1;
   202 	}
   203 
   204 	pi = create_iterator_from_argv(set, argc, argv);
   205 	while (razor_package_iterator_next(pi, &package,
   206 					   RAZOR_DETAIL_NAME, &name,
   207 					   RAZOR_DETAIL_VERSION, &version,
   208 					   RAZOR_DETAIL_ARCH, &arch,
   209 					   RAZOR_DETAIL_LAST))
   210 		list_package_properties(set, package, type);
   211 	razor_package_iterator_destroy(pi);
   212 	razor_set_unref(set);
   213 	razor_atomic_destroy(atomic);
   214 
   215 	return 0;
   216 }
   217 
   218 static int
   219 command_list_requires(int argc, const char *argv[])
   220 {
   221 	return list_properties(argc, argv, RAZOR_PROPERTY_REQUIRES);
   222 }
   223 
   224 static int
   225 command_list_provides(int argc, const char *argv[])
   226 {
   227 	return list_properties(argc, argv, RAZOR_PROPERTY_PROVIDES);
   228 }
   229 
   230 static int
   231 command_list_obsoletes(int argc, const char *argv[])
   232 {
   233 	return list_properties(argc, argv, RAZOR_PROPERTY_OBSOLETES);
   234 }
   235 
   236 static int
   237 command_list_conflicts(int argc, const char *argv[])
   238 {
   239 	return list_properties(argc, argv, RAZOR_PROPERTY_CONFLICTS);
   240 }
   241 
   242 static int
   243 command_list_scripts(int argc, const char *argv[])
   244 {
   245 	struct razor_set *set;
   246 	struct razor_atomic *atomic;
   247 	struct razor_package *package;
   248 	struct razor_package_iterator *pi;
   249 	const char *preunprog, *preun, *postunprog, *postun;
   250 
   251 	atomic = razor_atomic_open("List package scripts");
   252 	set = razor_root_open_read_only(install_root, atomic);
   253 	if (set == NULL) {
   254 		fprintf(stderr, "%s\n", razor_atomic_get_error_msg(atomic));
   255 		razor_atomic_destroy(atomic);
   256 		return 1;
   257 	}
   258 
   259 	pi = create_iterator_from_argv(set, argc, argv);
   260 	while (razor_package_iterator_next(pi, &package,
   261 					   RAZOR_DETAIL_PREUNPROG, &preunprog,
   262 					   RAZOR_DETAIL_PREUN, &preun,
   263 					   RAZOR_DETAIL_POSTUNPROG, &postunprog,
   264 					   RAZOR_DETAIL_POSTUN, &postun,
   265 					   RAZOR_DETAIL_LAST)) {
   266 		if (preun && *preun) {
   267 			printf("preuninstall scriptlet");
   268 			if (preunprog && *preunprog)
   269 				printf(" (using %s)",preunprog);
   270 			printf(":\n%s\n",preun);
   271 		}
   272 		if (postun && *postun) {
   273 			printf("postuninstall scriptlet");
   274 			if (postunprog && *postunprog)
   275 				printf(" (using %s)",postunprog);
   276 			printf(":\n%s\n",postun);
   277 		}
   278 	}
   279 	razor_package_iterator_destroy(pi);
   280 	razor_set_unref(set);
   281 	razor_atomic_destroy(atomic);
   282 
   283 	return 0;
   284 }
   285 
   286 static int
   287 command_list_files(int argc, const char *argv[])
   288 {
   289 	struct razor_atomic *atomic;
   290 	struct razor_set *set;
   291 
   292 	atomic = razor_atomic_open("List package files");
   293 	set = razor_root_open_read_only(install_root, atomic);
   294 	if (set == NULL) {
   295 		fprintf(stderr, "%s\n", razor_atomic_get_error_msg(atomic));
   296 		razor_atomic_destroy(atomic);
   297 		return 1;
   298 	}
   299 
   300 	razor_set_list_files(set, argv[0]);
   301 	razor_set_unref(set);
   302 	razor_atomic_destroy(atomic);
   303 
   304 	return 0;
   305 }
   306 
   307 static int
   308 command_list_file_packages(int argc, const char *argv[])
   309 {
   310 	struct razor_atomic *atomic;
   311 	struct razor_set *set;
   312 	struct razor_package_iterator *pi;
   313 
   314 	atomic = razor_atomic_open("List file packages");
   315 	set = razor_root_open_read_only(install_root, atomic);
   316 	if (set == NULL) {
   317 		fprintf(stderr, "%s\n", razor_atomic_get_error_msg(atomic));
   318 		razor_atomic_destroy(atomic);
   319 		return 1;
   320 	}
   321 
   322 	pi = razor_package_iterator_create_for_file(set, argv[0]);
   323 	list_packages(pi, 0);
   324 	razor_package_iterator_destroy(pi);
   325 
   326 	razor_set_unref(set);
   327 	razor_atomic_destroy(atomic);
   328 
   329 	return 0;
   330 }
   331 
   332 static int
   333 command_list_package_files(int argc, const char *argv[])
   334 {
   335 	struct razor_atomic *atomic;
   336 	struct razor_set *set;
   337 	struct razor_package_iterator *pi;
   338 	struct razor_package *package;
   339 	const char *name, *version, *arch;
   340 
   341 	atomic = razor_atomic_open("List package files");
   342 	set = razor_root_open_read_only(install_root, atomic);
   343 	if (set == NULL) {
   344 		fprintf(stderr, "%s\n", razor_atomic_get_error_msg(atomic));
   345 		razor_atomic_destroy(atomic);
   346 		return 1;
   347 	}
   348 
   349 	pi = create_iterator_from_argv(set, argc, argv);
   350 	while (razor_package_iterator_next(pi, &package,
   351 					   RAZOR_DETAIL_NAME, &name,
   352 					   RAZOR_DETAIL_VERSION, &version,
   353 					   RAZOR_DETAIL_ARCH, &arch,
   354 					   RAZOR_DETAIL_LAST))
   355 		razor_set_list_package_files(set, package);
   356 	razor_package_iterator_destroy(pi);
   357 
   358 	razor_set_unref(set);
   359 	razor_atomic_destroy(atomic);
   360 
   361 	return 0;
   362 }
   363 
   364 static int
   365 list_property_packages(const char *ref_name,
   366 		       const char *ref_version,
   367 		       uint32_t type)
   368 {
   369 	struct razor_atomic *atomic;
   370 	struct razor_set *set;
   371 	struct razor_property *property;
   372 	struct razor_property_iterator *prop_iter;
   373 	struct razor_package_iterator *pkg_iter;
   374 	const char *name, *version;
   375 	uint32_t flags;
   376 
   377 	if (ref_name == NULL)
   378 		return 0;
   379 
   380 	atomic = razor_atomic_open("List package properties");
   381 	set = razor_root_open_read_only(install_root, atomic);
   382 	if (set == NULL) {
   383 		fprintf(stderr, "%s\n", razor_atomic_get_error_msg(atomic));
   384 		razor_atomic_destroy(atomic);
   385 		return 1;
   386 	}
   387 
   388 	prop_iter = razor_property_iterator_create(set, NULL);
   389 	while (razor_property_iterator_next(prop_iter, &property,
   390 					    &name, &flags, &version)) {
   391 		if (strcmp(ref_name, name) != 0)
   392 			continue;
   393 		if (ref_version &&
   394 		    (flags & RAZOR_PROPERTY_RELATION_MASK) == RAZOR_PROPERTY_EQUAL &&
   395 		    strcmp(ref_version, version) != 0)
   396 			continue;
   397 		if ((flags & RAZOR_PROPERTY_TYPE_MASK) != type)
   398 			continue;
   399 
   400 		pkg_iter =
   401 			razor_package_iterator_create_for_property(set,
   402 								   property);
   403 		list_packages(pkg_iter, 0);
   404 		razor_package_iterator_destroy(pkg_iter);
   405 	}
   406 	razor_property_iterator_destroy(prop_iter);
   407 
   408 	razor_set_unref(set);
   409 	razor_atomic_destroy(atomic);
   410 
   411 	return 0;
   412 }
   413 
   414 static int
   415 command_what_requires(int argc, const char *argv[])
   416 {
   417 	return list_property_packages(argv[0], argv[1],
   418 				      RAZOR_PROPERTY_REQUIRES);
   419 }
   420 
   421 static int
   422 command_what_provides(int argc, const char *argv[])
   423 {
   424 	return list_property_packages(argv[0], argv[1],
   425 				      RAZOR_PROPERTY_PROVIDES);
   426 }
   427 
   428 static int
   429 show_progress(void *clientp,
   430 	      double dltotal, double dlnow, double ultotal, double ulnow)
   431 {
   432 	const char *file = clientp;
   433 
   434 	if (!dlnow < dltotal)
   435 		fprintf(stderr, "\rdownloading %s, %dkB/%dkB",
   436 			file, (int) dlnow / 1024, (int) dltotal / 1024);
   437 
   438 	return 0;
   439 }
   440 
   441 static int
   442 download_if_missing(const char *url, const char *file)
   443 {
   444 #ifndef HAVE_CURL
   445 	return 1;
   446 #else
   447 	CURL *curl;
   448 	struct stat buf;
   449 	char error[256];
   450 	FILE *fp;
   451 	CURLcode res;
   452 	long response;
   453 
   454 	curl = curl_easy_init();
   455 	if (curl == NULL)
   456 		return 1;
   457 
   458 	curl_easy_setopt(curl, CURLOPT_ERRORBUFFER, error);
   459 	curl_easy_setopt(curl, CURLOPT_NOPROGRESS, 0);
   460 	curl_easy_setopt(curl, CURLOPT_PROGRESSFUNCTION, show_progress);
   461 	curl_easy_setopt(curl, CURLOPT_PROGRESSDATA, file);
   462 
   463 	if (stat(file, &buf) < 0) {
   464 		fp = fopen(file, "wb");
   465 		if (fp == NULL) {
   466 			fprintf(stderr,
   467 				"failed to open %s for writing\n", file);
   468 			return -1;
   469 		}
   470 		curl_easy_setopt(curl, CURLOPT_WRITEDATA, fp);
   471 		curl_easy_setopt(curl, CURLOPT_URL, url);
   472 		res = curl_easy_perform(curl);
   473 		fclose(fp);
   474 		if (res != CURLE_OK) {
   475 			fprintf(stderr, "curl error: %s\n", error);
   476 			unlink(file);
   477 			return -1;
   478 		}
   479 		res = curl_easy_getinfo(curl,
   480 					CURLINFO_RESPONSE_CODE, &response);
   481 		if (res != CURLE_OK) {
   482 			fprintf(stderr, "curl error: %s\n", error);
   483                         unlink(file);
   484                         return -1;
   485 		}
   486 		if (response != 200) {
   487 			fprintf(stderr, " - failed %ld\n", response);
   488                         unlink(file);
   489                         return -1;
   490 		}
   491 		fprintf(stderr, "\n");
   492 	}
   493 
   494 	curl_easy_cleanup(curl);
   495 
   496 	return 0;
   497 #endif	/* HAVE_CURL */
   498 }
   499 
   500 #define YUM_URL "http://download.fedora.redhat.com" \
   501 	"/pub/fedora/linux/development/i386/os"
   502 
   503 static int
   504 command_import_yum(int argc, const char *argv[])
   505 {
   506 	int retval;
   507 	struct razor_set *set;
   508 	struct razor_atomic *atomic;
   509 	char buffer[512];
   510 
   511 	printf("downloading from %s.\n", yum_url);
   512 	snprintf(buffer, sizeof buffer,
   513 		 "%s/repodata/primary.xml.gz", yum_url);
   514 	if (download_if_missing(buffer, "primary.xml.gz") < 0)
   515 		return -1;
   516 	snprintf(buffer, sizeof buffer,
   517 		 "%s/repodata/filelists.xml.gz", yum_url);
   518 	if (download_if_missing(buffer, "filelists.xml.gz") < 0)
   519 		return -1;
   520 
   521 	set = razor_set_create_from_yum();
   522 	if (set == NULL)
   523 		return 1;
   524 	atomic = razor_atomic_open("Yum import repository");
   525 	razor_set_write(set, atomic, rawhide_repo_filename, RAZOR_SECTION_ALL);
   526 	retval = razor_atomic_commit(atomic);
   527 	razor_set_unref(set);
   528 	if (retval)
   529 		fprintf(stderr, "%s\n", razor_atomic_get_error_msg(atomic));
   530 	else
   531 		printf("wrote %s\n", rawhide_repo_filename);
   532 	razor_atomic_destroy(atomic);
   533 
   534 	return retval;
   535 }
   536 
   537 #if HAVE_RPMLIB
   538 static int
   539 command_import_rpmdb(int argc, const char *argv[])
   540 {
   541 	struct razor_set *set;
   542 	struct razor_root *root;
   543 	struct razor_atomic *atomic;
   544 	int retval;
   545 
   546 	atomic = razor_atomic_open("Import RPM database");
   547 
   548 	root = razor_root_open(install_root, atomic);
   549 	if (root == NULL) {
   550 		fprintf(stderr, "%s\n", razor_atomic_get_error_msg(atomic));
   551 		razor_atomic_destroy(atomic);
   552 		return 1;
   553 	}
   554 
   555 	set = razor_set_create_from_rpmdb();
   556 	if (set == NULL)
   557 		return 1;
   558 
   559 	razor_root_update(root, set);
   560 
   561 	retval = razor_root_commit(root);
   562 	if (retval)
   563 		fprintf(stderr, "%s\n", razor_atomic_get_error_msg(atomic));
   564 
   565 	razor_atomic_destroy(atomic);
   566 
   567 	return retval;
   568 }
   569 #endif
   570 
   571 static int
   572 mark_packages_for_update(struct razor_transaction *trans,
   573 			 struct razor_set *set, const char *pattern)
   574 {
   575 	struct razor_package_iterator *pi;
   576 	struct razor_package *package;
   577 	const char *name;
   578 	int matches = 0;
   579 
   580 	pi = razor_package_iterator_create(set);
   581 	while (razor_package_iterator_next(pi, &package,
   582 					   RAZOR_DETAIL_NAME, &name,
   583 					   RAZOR_DETAIL_LAST)) {
   584 		if (pattern && fnmatch(pattern, name, 0) == 0) {
   585 			razor_transaction_update_package(trans, package);
   586 			matches++;
   587 		}
   588 	}
   589 	razor_package_iterator_destroy(pi);
   590 
   591 	return matches;
   592 }
   593 
   594 static int
   595 mark_packages_for_removal(struct razor_transaction *trans,
   596 			  struct razor_set *set, const char *pattern)
   597 {
   598 	struct razor_package_iterator *pi;
   599 	struct razor_package *package;
   600 	const char *name;
   601 	int matches = 0;
   602 
   603 	pi = razor_package_iterator_create(set);
   604 	while (razor_package_iterator_next(pi, &package,
   605 					   RAZOR_DETAIL_NAME, &name,
   606 					   RAZOR_DETAIL_LAST)) {
   607 		if (pattern && fnmatch(pattern, name, 0) == 0) {
   608 			razor_transaction_remove_package(trans, package);
   609 			matches++;
   610 		}
   611 	}
   612 	razor_package_iterator_destroy(pi);
   613 
   614 	return matches;
   615 }
   616 
   617 static int
   618 command_remove(int argc, const char *argv[])
   619 {
   620 	struct razor_set *system, *upstream, *next;
   621 	struct razor_transaction *trans;
   622 	struct razor_atomic *atomic;
   623 	int i, retval;
   624 
   625 	atomic = razor_atomic_open("Remove packages");
   626 
   627 	system = razor_root_open_read_only(install_root, atomic);
   628 	if (system == NULL) {
   629 		fprintf(stderr, "%s\n", razor_atomic_get_error_msg(atomic));
   630 		razor_atomic_destroy(atomic);
   631 		return 1;
   632 	}
   633 
   634 	razor_atomic_destroy(atomic);
   635 
   636 	upstream = razor_set_create_without_root();
   637 	trans = razor_transaction_create(system, upstream);
   638 	razor_set_unref(upstream);
   639 	for (i = 0; i < argc; i++) {
   640 		if (mark_packages_for_removal(trans, system, argv[i]) == 0) {
   641 			fprintf(stderr, "no match for %s\n", argv[i]);
   642 			razor_transaction_destroy(trans);
   643 			razor_set_unref(system);
   644 			return 1;
   645 		}
   646 	}
   647 
   648 	razor_transaction_resolve(trans);
   649 	retval = razor_transaction_describe(trans);
   650 	if (retval) {
   651 		razor_transaction_destroy(trans);
   652 		razor_set_unref(system);
   653 		return 1;
   654 	}
   655 
   656 	next = razor_transaction_commit(trans);
   657 
   658 	retval = update_system(install_root, NULL, trans, system, next,
   659 			       "Remove");
   660 
   661 	razor_transaction_destroy(trans);
   662 	razor_set_unref(system);
   663 	razor_set_unref(next);
   664 
   665 	return retval;
   666 }
   667 
   668 static void
   669 print_diff(enum razor_diff_action action,
   670 	   struct razor_package *package,
   671 	   const char *name,
   672 	   const char *version,
   673 	   const char *arch,
   674 	   void *data)
   675 {
   676 	if (action == RAZOR_DIFF_ACTION_ADD)
   677 		printf("install %s-%s.%s\n", name, version, arch);
   678 	if (action == RAZOR_DIFF_ACTION_REMOVE)
   679 		printf("remove %s-%s.%s\n", name, version, arch);
   680 }
   681 
   682 static int
   683 command_diff(int argc, const char *argv[])
   684 {
   685 	struct razor_atomic *atomic;
   686 	struct razor_set *set, *updated;
   687 
   688 	atomic = razor_atomic_open("Show package differences");
   689 	set = razor_root_open_read_only(install_root, atomic);
   690 	updated = razor_set_open(rawhide_repo_filename, atomic);
   691 	if (set == NULL || updated == NULL) {
   692 		fprintf(stderr, "%s\n", razor_atomic_get_error_msg(atomic));
   693 		razor_atomic_destroy(atomic);
   694 		return 1;
   695 	}
   696 
   697 	razor_set_diff(set, updated, print_diff, NULL);
   698 
   699 	razor_set_unref(set);
   700 	razor_set_unref(updated);
   701 	razor_atomic_destroy(atomic);
   702 
   703 	return 0;
   704 }
   705 
   706 static int
   707 command_import_rpms(int argc, const char *argv[])
   708 {
   709 	DIR *dir;
   710 	struct dirent *de;
   711 	struct razor_importer *importer;
   712 	struct razor_set *set;
   713 	struct razor_rpm *rpm;
   714 	struct razor_atomic *atomic;
   715 	int len, imported_count = 0;
   716 	char filename[256];
   717 	const char *dirname = argv[0];
   718 	int retval;
   719 
   720 	if (dirname == NULL) {
   721 		fprintf(stderr, "usage: razor import-rpms DIR\n");
   722 		return -1;
   723 	}
   724 
   725 	dir = opendir(dirname);
   726 	if (dir == NULL) {
   727 		fprintf(stderr, "couldn't read dir %s\n", dirname);
   728 		return -1;
   729 	}
   730 
   731 	importer = razor_importer_create();
   732 
   733 	while (de = readdir(dir), de != NULL) {
   734 		len = strlen(de->d_name);
   735 		if (len < 5 || strcmp(de->d_name + len - 4, ".rpm") != 0)
   736 			continue;
   737 		snprintf(filename, sizeof filename,
   738 			 "%s/%s", dirname, de->d_name);
   739 		atomic = razor_atomic_open("Read RPM");
   740 		rpm = razor_rpm_open(filename, atomic);
   741 		if (rpm == NULL)
   742 			fprintf(stderr, "%s\n",
   743 				razor_atomic_get_error_msg(atomic));
   744 		razor_atomic_destroy(atomic);
   745 		if (rpm == NULL)
   746 			continue;
   747 		if (razor_importer_add_rpm(importer, rpm)) {
   748 			fprintf(stderr, "couldn't import %s\n", filename);
   749 			break;
   750 		}
   751 		razor_rpm_close(rpm);
   752 
   753 		printf("\rimporting %d", ++imported_count);
   754 		fflush(stdout);
   755 	}
   756 
   757 	if (de != NULL) {
   758 		razor_importer_destroy(importer);
   759 		return -1;
   760 	}
   761 
   762 	printf("\nsaving\n");
   763 	set = razor_importer_finish(importer);
   764 
   765 	atomic = razor_atomic_open("Update system database");
   766 	razor_set_write(set, atomic, repo_filename, RAZOR_SECTION_ALL);
   767 	razor_set_unref(set);
   768 	retval = razor_atomic_commit(atomic);
   769 	if (retval)
   770 		fprintf(stderr, "%s\n", razor_atomic_get_error_msg(atomic));
   771 	else
   772 		printf("wrote %s\n", repo_filename);
   773 	razor_atomic_destroy(atomic);
   774 
   775 	return retval;
   776 }
   777 
   778 static char *
   779 rpm_filename(const char *name, const char *version, const char *arch)
   780 {
   781  	const char *v;
   782  
   783  	/* Skip epoch */
   784 	v = strchr(version, ':');
   785  	if (v != NULL)
   786  		v = v + 1;
   787  	else
   788 		v = version;
   789 
   790 	return razor_concat(name, "-", v, ".", arch, ".rpm", NULL);
   791 }
   792 
   793 static int
   794 download_packages(struct razor_set *system, struct razor_set *next)
   795 {
   796 	struct razor_install_iterator *ii;
   797 	struct razor_package *package;
   798 	enum razor_install_action action;
   799 	const char *name, *version, *arch;
   800 	char *file, *url, *s;
   801 	int errors = 0, count;
   802 
   803 	ii = razor_set_create_install_iterator(system, next);
   804 	while (razor_install_iterator_next(ii, &package, &action, &count)) {
   805 		if (action != RAZOR_INSTALL_ACTION_ADD)
   806 			continue;
   807 
   808 		razor_package_get_details(next, package,
   809 					  RAZOR_DETAIL_NAME, &name,
   810 					  RAZOR_DETAIL_VERSION, &version,
   811 					  RAZOR_DETAIL_ARCH, &arch,
   812 					  RAZOR_DETAIL_LAST);
   813 		
   814 		s = rpm_filename(name, version, arch);
   815 		url = razor_concat(yum_url, "/Packages/", s, NULL);
   816 		file = razor_concat("rpms/", s, NULL);
   817 		free(s);
   818 		if (download_if_missing(url, file) < 0)
   819 			errors++;
   820 		free(file);
   821 		free(url);
   822 	}
   823 	razor_install_iterator_destroy(ii);
   824 
   825 	if (errors > 0) {
   826 		fprintf(stderr, "failed to download %d packages\n", errors);
   827                 return -1;
   828         }
   829 
   830 	return 0;
   831 }
   832 
   833 static struct razor_set *
   834 relocate_packages(struct razor_set *set, struct razor_atomic *atomic,
   835 		  struct razor_relocations *relocations)
   836 {
   837 	int i;
   838 	struct razor_importer *importer;
   839 	struct razor_property_iterator *prop_iter;
   840 	struct razor_package_iterator *pkg_iter;
   841  	struct razor_file_iterator *file_iter;
   842  	struct razor_package *package;
   843 	struct razor_property *property;
   844 	struct razor_rpm *rpm;
   845 	const char *name, *version, *arch, *summary, *desc, *url, *license;
   846 	const char *preunprog, *preun, *postunprog, *postun;
   847 	const char *install_prefix;
   848 	const char *const *prefixes;
   849 	char *file, *s;
   850 	uint32_t flags;
   851 
   852 	importer = razor_importer_create();
   853 	pkg_iter = razor_package_iterator_create(set);
   854 
   855 	while (razor_package_iterator_next(pkg_iter, &package,
   856 					   RAZOR_DETAIL_NAME, &name,
   857 					   RAZOR_DETAIL_VERSION, &version,
   858 					   RAZOR_DETAIL_ARCH, &arch,
   859 					   RAZOR_DETAIL_SUMMARY, &summary,
   860 					   RAZOR_DETAIL_DESCRIPTION, &desc,
   861 					   RAZOR_DETAIL_URL, &url,
   862 					   RAZOR_DETAIL_LICENSE, &license,
   863 					   RAZOR_DETAIL_PREUNPROG, &preunprog,
   864 					   RAZOR_DETAIL_PREUN, &preun,
   865 					   RAZOR_DETAIL_POSTUNPROG, &postunprog,
   866 					   RAZOR_DETAIL_POSTUN, &postun,
   867 					   RAZOR_DETAIL_LAST)) {
   868 		s = rpm_filename(name, version, arch);
   869 		file = razor_concat("rpms/", s, NULL);
   870 		free(s);
   871 		rpm = razor_rpm_open(file, atomic);
   872 		free(file);
   873 		if (rpm == NULL) {
   874 			razor_package_iterator_destroy(pkg_iter);
   875 			razor_importer_destroy(importer);
   876 			return NULL;
   877 		}
   878 
   879 		razor_relocations_set_rpm(relocations, rpm);
   880 
   881 		razor_importer_begin_package(importer, name, version, arch);
   882 		razor_importer_add_details(importer,
   883 					   summary, desc, url, license);
   884 
   885 		razor_rpm_get_details(rpm, RAZOR_DETAIL_PREFIXES, &prefixes,
   886 				      RAZOR_DETAIL_LAST);
   887 		for (i = 0; prefixes && prefixes[i]; i++) {
   888 			install_prefix = razor_relocations_apply(relocations,
   889 								 prefixes[i]);
   890 			razor_importer_add_install_prefix(importer,
   891 							  install_prefix);
   892 		}
   893 
   894 		razor_rpm_close(rpm);
   895 
   896 		prop_iter = razor_property_iterator_create(set, package);
   897 		while (razor_property_iterator_next(prop_iter, &property,
   898 						    &name, &flags, &version))
   899 			razor_importer_add_property(importer,
   900 						    name, flags, version);
   901 		razor_property_iterator_destroy(prop_iter);
   902 
   903 		file_iter = razor_file_iterator_create(set, package, 0);
   904 		while (razor_file_iterator_next(file_iter, &name)) {
   905 			name = razor_relocations_apply(relocations, name);
   906 			razor_importer_add_file(importer, name);
   907 		}
   908 		razor_file_iterator_destroy(file_iter);
   909 
   910 		razor_importer_add_script(importer, RAZOR_PROPERTY_PREUN,
   911 					  preunprog, preun);
   912 		razor_importer_add_script(importer, RAZOR_PROPERTY_POSTUN,
   913 					  postunprog, postun);
   914 
   915 		razor_importer_finish_package(importer);
   916 	}
   917 
   918 	razor_package_iterator_destroy(pkg_iter);
   919 	return razor_importer_finish(importer);
   920 }
   921 
   922 static int
   923 install_package(struct razor_transaction *trans, struct razor_set *set,
   924 		struct razor_atomic *atomic, struct razor_package *package,
   925 		struct razor_relocations *relocations, int install_count,
   926 		enum razor_stage_type stage)
   927 {
   928 	int retval;
   929 	const char *name, *version, *arch;
   930 	char *file, *s;
   931 	struct razor_rpm *rpm;
   932 
   933 	razor_package_get_details(set, package,
   934 				  RAZOR_DETAIL_NAME, &name,
   935 				  RAZOR_DETAIL_VERSION, &version,
   936 				  RAZOR_DETAIL_ARCH, &arch,
   937 				  RAZOR_DETAIL_LAST);
   938 
   939 	if (stage & RAZOR_STAGE_SCRIPTS_PRE)
   940 		printf("install %s-%s\n", name, version);
   941 
   942 	s = rpm_filename(name, version, arch);
   943 	file = razor_concat("rpms/", s, NULL);
   944 	free(s);
   945 	rpm = razor_rpm_open(file, atomic);
   946 	free(file);
   947 	if (rpm == NULL) {
   948 		fprintf(stderr, "%s\n",
   949 			razor_atomic_get_error_msg(atomic));
   950 		return -1;
   951 	}
   952 	if (relocations)
   953 		razor_rpm_set_relocations(rpm, relocations);
   954 	razor_transaction_fixup_package(trans, package, rpm);
   955 	retval = razor_rpm_install(rpm, atomic, install_root, install_count,
   956 				   stage);
   957 	if (retval < 0) {
   958 		s = rpm_filename(name, version, arch);
   959 		fprintf(stderr, "%s: %s\n", s,
   960 			razor_atomic_get_error_msg(atomic));
   961 		free(s);
   962 	}
   963 	razor_rpm_close(rpm);
   964 	return retval;
   965 }
   966 
   967 /*
   968  * Returns 0 on success, -1 on failure and 1 if a RAZOR_INSTALL_ACTION_COMMIT
   969  * is met (in which case the action is consumed).
   970  */
   971 static int
   972 update_packages(struct razor_transaction *trans,
   973 		struct razor_install_iterator *ii, struct razor_set *system,
   974 		struct razor_set *next, struct razor_atomic *atomic,
   975 		struct razor_relocations *relocations,
   976 		enum razor_stage_type stage)
   977 {
   978 	struct razor_package *package;
   979 	enum razor_install_action action;
   980 	int retval = 0, count;
   981 
   982 	while (!retval && razor_install_iterator_next(ii, &package, &action,
   983 						      &count)) {
   984 		if (action == RAZOR_INSTALL_ACTION_ADD) {
   985 			if (install_package(trans, next, atomic, package,
   986 					    relocations, count, stage))
   987 				retval = -1;
   988 		} else if (action == RAZOR_INSTALL_ACTION_REMOVE) {
   989 			if (razor_package_remove(system, next, atomic, package,
   990 						 install_root, count, stage))
   991 				retval = -1;
   992 		} else if (action == RAZOR_INSTALL_ACTION_COMMIT)
   993 				retval = 1;
   994 	}
   995 
   996 	return retval;
   997 }
   998 
   999 static int
  1000 update_system(const char *install_root, struct razor_relocations *relocations,
  1001 	      struct razor_transaction *trans, struct razor_set *system,
  1002 	      struct razor_set *next, const char *verb)
  1003 {
  1004 	struct razor_root *root;
  1005 	struct razor_set *set;
  1006 	struct razor_atomic *atomic;
  1007 	struct razor_install_iterator *ii;
  1008 	int r, retval = 0;
  1009 	char *description;
  1010 	size_t pos;
  1011 
  1012 	description = razor_concat(verb, " packages", NULL);
  1013 
  1014 	ii = razor_set_create_install_iterator(system, next);
  1015 
  1016 	do {
  1017 		pos = razor_install_iterator_tell(ii);
  1018 
  1019 		atomic = razor_atomic_open(description);
  1020 
  1021 		root = razor_root_open(install_root, atomic);
  1022 		if (root == NULL) {
  1023 			fprintf(stderr, "%s\n",
  1024 				razor_atomic_get_error_msg(atomic));
  1025 			razor_atomic_destroy(atomic);
  1026 			retval = 1;
  1027 			break;
  1028 		}
  1029 
  1030 		r = update_packages(trans, ii, system, next, atomic,
  1031 				    relocations, RAZOR_STAGE_SCRIPTS_PRE);
  1032 		if (r < 0) {
  1033 			fprintf(stderr, "%s aborted\n", verb);
  1034 			razor_atomic_destroy(atomic);
  1035 			retval = r;
  1036 		} else {
  1037 			razor_install_iterator_seek(ii, pos);
  1038 			r = update_packages(trans, ii, system, next, atomic,
  1039 					    relocations, RAZOR_STAGE_FILES);
  1040 
  1041 			if (r == 1) {
  1042 				set = razor_install_iterator_commit_set(ii);
  1043 				razor_root_update(root, set);
  1044 				razor_set_unref(set);
  1045 			} else if (r == 0)
  1046 				razor_root_update(root, next);
  1047 
  1048 			(void)razor_root_commit(root);
  1049 			retval = razor_atomic_commit(atomic);
  1050 			if (retval) {
  1051 				fprintf(stderr, "%s\n",
  1052 					razor_atomic_get_error_msg(atomic));
  1053 				razor_atomic_destroy(atomic);
  1054 			} else {
  1055 				razor_install_iterator_seek(ii, pos);
  1056 				update_packages(trans, ii, system, next,
  1057 						atomic, relocations,
  1058 						RAZOR_STAGE_SCRIPTS_POST);
  1059 			}
  1060 		}
  1061 
  1062 		razor_atomic_destroy(atomic);
  1063 	} while(!retval && r == 1);
  1064 
  1065 	free(description);
  1066 
  1067 	return retval;
  1068 }
  1069 
  1070 static int
  1071 command_install_or_update(int argc, const char *argv[], int do_update)
  1072 {
  1073 	struct razor_relocations *relocations=NULL;
  1074 	struct razor_set *system, *upstream, *next, *set;
  1075 	struct razor_transaction *trans;
  1076 	struct razor_atomic *atomic;
  1077 	int i, retval, len, dependencies = 1;
  1078 	char *oldpath;
  1079 
  1080 	for (i = 0; i < argc; i++) {
  1081 		if (strcmp(argv[i], "--no-dependencies") == 0)
  1082 			dependencies = 0;
  1083 		else if (strcmp(argv[i], "--relocate") == 0) {
  1084 			i++;
  1085 			if (i >= argc || strchr(argv[i], '=') == NULL) {
  1086 				fprintf(stderr,
  1087 				    "Usage: razor %s [OPTION...] RPM\n",
  1088 				    do_update ? "update" : "install");
  1089 				fprintf(stderr, "Options:\n");
  1090 				fprintf(stderr, "    [--no-dependencies]\n");
  1091 				fprintf(stderr,
  1092 				    "    [--relocate OLDPATH=NEWPATH] RPM\n");
  1093 				return -1;
  1094 			}
  1095 			len = strchr(argv[i], '=') - argv[i];
  1096 			oldpath = malloc(len + 1);
  1097 			strncpy(oldpath, argv[i], len);
  1098 			oldpath[len] = '\0';
  1099 			if (!relocations)
  1100 			       relocations = razor_relocations_create();
  1101 			razor_relocations_add(relocations, oldpath,
  1102 					      argv[i] + len + 1);
  1103 			free(oldpath);
  1104 		} else
  1105 			break;
  1106 	}
  1107 
  1108 	if (do_update)
  1109 		atomic = razor_atomic_open("Update packages");
  1110 	else
  1111 		atomic = razor_atomic_open("Install packages");
  1112 
  1113 	upstream = razor_set_open(rawhide_repo_filename, atomic);
  1114 	if (upstream == NULL) {
  1115 		fprintf(stderr, "%s\n", razor_atomic_get_error_msg(atomic));
  1116 		razor_atomic_destroy(atomic);
  1117 		return 1;
  1118 	}
  1119 
  1120 	if (relocations) {
  1121 		set = relocate_packages(upstream, atomic, relocations);
  1122 		if (set == NULL) {
  1123 			fprintf(stderr, "%s\n",
  1124 				razor_atomic_get_error_msg(atomic));
  1125 			razor_atomic_destroy(atomic);
  1126 			razor_set_unref(upstream);
  1127 			return 1;
  1128 		}
  1129 		razor_set_unref(upstream);
  1130 		upstream = set;
  1131 	}
  1132 
  1133 	system = razor_root_open_read_only(install_root, atomic);
  1134 
  1135 	trans = razor_transaction_create(system, upstream);
  1136 
  1137 	if (i == argc && do_update)
  1138 		razor_transaction_update_all(trans);
  1139 	for (; i < argc; i++) {
  1140 		if (do_update &&
  1141 		    mark_packages_for_update(trans, system, argv[i]))
  1142 			continue;
  1143 		if (mark_packages_for_update(trans, upstream, argv[i]) == 0) {
  1144 			fprintf(stderr, "no package matched %s\n", argv[i]);
  1145 			razor_transaction_destroy(trans);
  1146 			razor_set_unref(upstream);
  1147 			razor_set_unref(system);
  1148 			razor_atomic_destroy(atomic);
  1149 			return 1;
  1150 		}
  1151 	}
  1152 
  1153 	if (dependencies) {
  1154 		razor_transaction_resolve(trans);
  1155 		if (razor_transaction_describe(trans) > 0) {
  1156 			razor_transaction_destroy(trans);
  1157 			razor_set_unref(upstream);
  1158 			razor_set_unref(system);
  1159 			razor_atomic_destroy(atomic);
  1160 			return 1;
  1161 		}
  1162 	}
  1163 
  1164 	if (razor_atomic_create_dir(atomic, "rpms",
  1165 				    S_IRWXU | S_IRWXG | S_IRWXO) ||
  1166 	    razor_atomic_commit(atomic)) {
  1167 		fprintf(stderr, "%s\n", razor_atomic_get_error_msg(atomic));
  1168 		razor_transaction_destroy(trans);
  1169 		razor_set_unref(upstream);
  1170 		razor_set_unref(system);
  1171 		razor_atomic_destroy(atomic);
  1172 		return 1;
  1173 	}
  1174 
  1175 	razor_atomic_destroy(atomic);
  1176 
  1177 	next = razor_transaction_commit(trans);
  1178 
  1179 	if (download_packages(system, next) < 0) {
  1180 		razor_set_unref(next);
  1181 		razor_transaction_destroy(trans);
  1182 		razor_set_unref(upstream);
  1183 		razor_set_unref(system);
  1184 		razor_atomic_destroy(atomic);
  1185                 return 1;
  1186         }
  1187 
  1188 	retval = update_system(install_root, relocations, trans, system, next,
  1189 			       do_update ? "Update" : "Install");
  1190 
  1191 	razor_set_unref(upstream);
  1192 
  1193 	razor_transaction_destroy(trans);
  1194 	if (relocations)
  1195 		razor_relocations_destroy(relocations);
  1196 
  1197 	razor_set_unref(next);
  1198 	razor_set_unref(system);
  1199 
  1200 	return retval;
  1201 }
  1202 
  1203 static int
  1204 command_update(int argc, const char *argv[])
  1205 {
  1206 	return command_install_or_update(argc, argv, 1);
  1207 }
  1208 
  1209 static int
  1210 command_install(int argc, const char *argv[])
  1211 {
  1212 	return command_install_or_update(argc, argv, 0);
  1213 }
  1214 
  1215 static int
  1216 command_init(int argc, const char *argv[])
  1217 {
  1218 	return razor_root_create(install_root);
  1219 }
  1220 
  1221 static int
  1222 command_download(int argc, const char *argv[])
  1223 {
  1224 	struct razor_atomic *atomic;
  1225 	struct razor_set *set;
  1226 	struct razor_package_iterator *pi;
  1227 	struct razor_package *package;
  1228 	const char *pattern = argv[0], *name, *version, *arch;
  1229 	char url[256], file[256];
  1230 	int matches = 0;
  1231 
  1232 	atomic = razor_atomic_open("Download packages");
  1233 
  1234 	if (razor_atomic_create_dir(atomic, "rpms", 
  1235 				    S_IRWXU | S_IRWXG | S_IRWXO)) {
  1236 		fprintf(stderr, "%s\n", razor_atomic_get_error_msg(atomic));
  1237 		razor_atomic_destroy(atomic);
  1238 		return 1;
  1239 	}
  1240 
  1241 	set = razor_set_open(rawhide_repo_filename, atomic);
  1242 
  1243 	if (razor_atomic_commit(atomic)) {
  1244 		fprintf(stderr, "%s\n", razor_atomic_get_error_msg(atomic));
  1245 		razor_atomic_destroy(atomic);
  1246 		return 1;
  1247 	}
  1248 	razor_atomic_destroy(atomic);
  1249 
  1250 	pi = razor_package_iterator_create(set);
  1251 	while (razor_package_iterator_next(pi, &package,
  1252 					   RAZOR_DETAIL_NAME, &name,
  1253 					   RAZOR_DETAIL_VERSION, &version,
  1254 					   RAZOR_DETAIL_ARCH, &arch,
  1255 					   RAZOR_DETAIL_LAST)) {
  1256 		if (pattern && fnmatch(pattern, name, 0) != 0)
  1257 			continue;
  1258 
  1259 		matches++;
  1260 		snprintf(url, sizeof url,
  1261 			 "%s/Packages/%s-%s.%s.rpm",
  1262 			 yum_url, name, version, arch);
  1263 		snprintf(file, sizeof file,
  1264 			 "rpms/%s-%s.%s.rpm", name, version, arch);
  1265 		download_if_missing(url, file);
  1266 	}
  1267 	razor_package_iterator_destroy(pi);
  1268 	razor_set_unref(set);
  1269 
  1270 	if (matches == 0)
  1271 		fprintf(stderr, "no packages matched \"%s\"\n", pattern);
  1272 	else if (matches == 1)
  1273 		fprintf(stderr, "downloaded 1 package\n");
  1274 	else
  1275 		fprintf(stderr, "downloaded %d packages\n", matches);
  1276 
  1277 	return 0;
  1278 }
  1279 
  1280 static int
  1281 command_info(int argc, const char *argv[])
  1282 {
  1283 	struct razor_atomic *atomic;
  1284 	struct razor_set *set;
  1285 	struct razor_package_iterator *pi;
  1286 	struct razor_package *package;
  1287 	const char *pattern = argv[0], *name, *version, *arch;
  1288 	const char *summary, *description, *url, *license;
  1289 
  1290 	atomic = razor_atomic_open("Package info");
  1291 	set = razor_root_open_read_only(install_root, atomic);
  1292 	if (set == NULL) {
  1293 		fprintf(stderr, "%s\n", razor_atomic_get_error_msg(atomic));
  1294 		razor_atomic_destroy(atomic);
  1295 		return 1;
  1296 	}
  1297 
  1298 	pi = razor_package_iterator_create(set);
  1299 	while (razor_package_iterator_next(pi, &package,
  1300 					   RAZOR_DETAIL_NAME, &name,
  1301 					   RAZOR_DETAIL_VERSION, &version,
  1302 					   RAZOR_DETAIL_ARCH, &arch,
  1303 					   RAZOR_DETAIL_LAST)) {
  1304 		if (pattern && fnmatch(pattern, name, 0) != 0)
  1305 			continue;
  1306 
  1307 		razor_package_get_details (set, package,
  1308 					   RAZOR_DETAIL_SUMMARY, &summary,
  1309 					   RAZOR_DETAIL_DESCRIPTION, &description,
  1310 					   RAZOR_DETAIL_URL, &url,
  1311 					   RAZOR_DETAIL_LICENSE, &license,
  1312 					   RAZOR_DETAIL_LAST);
  1313 
  1314 		printf ("Name:        %s\n", name);
  1315 		printf ("Arch:        %s\n", arch);
  1316 		printf ("Version:     %s\n", version);
  1317 		printf ("URL:         %s\n", url);
  1318 		printf ("License:     %s\n", license);
  1319 		printf ("Summary:     %s\n", summary);
  1320 		printf ("Description:\n");
  1321 		printf ("%s\n", description);
  1322 		printf ("\n");
  1323 	}
  1324 	razor_package_iterator_destroy(pi);
  1325 	razor_set_unref(set);
  1326 	razor_atomic_destroy(atomic);
  1327 
  1328 	return 0;
  1329 }
  1330 
  1331 #define SEARCH_MAX 256
  1332 
  1333 static int
  1334 command_search(int argc, const char *argv[])
  1335 {
  1336 	struct razor_atomic *atomic;
  1337 	struct razor_set *set;
  1338 	struct razor_package_iterator *pi;
  1339 	struct razor_package *package;
  1340 	char pattern[SEARCH_MAX];
  1341 	const char *name, *version, *arch;
  1342 	const char *summary, *description, *url, *license;
  1343 
  1344 	if (!argv[0]) {
  1345 		fprintf(stderr, "must specify a search term\n");
  1346 		return 1;
  1347 	}
  1348 
  1349 	snprintf(pattern, sizeof pattern, "*%s*", argv[0]);
  1350 
  1351 	atomic = razor_atomic_open("Search packages");
  1352 	set = razor_set_open(rawhide_repo_filename, atomic);
  1353 	if (set == NULL || razor_atomic_commit(atomic)) {
  1354 		fprintf(stderr, "%s\n", razor_atomic_get_error_msg(atomic));
  1355 		razor_atomic_destroy(atomic);
  1356 		return 1;
  1357 	}
  1358 	razor_atomic_destroy(atomic);
  1359 
  1360 	pi = razor_package_iterator_create(set);
  1361 	while (razor_package_iterator_next(pi, &package,
  1362 					   RAZOR_DETAIL_NAME, &name,
  1363 					   RAZOR_DETAIL_VERSION, &version,
  1364 					   RAZOR_DETAIL_ARCH, &arch,
  1365 					   RAZOR_DETAIL_SUMMARY, &summary,
  1366 					   RAZOR_DETAIL_DESCRIPTION, &description,
  1367 					   RAZOR_DETAIL_URL, &url,
  1368 					   RAZOR_DETAIL_LICENSE, &license,
  1369 					   RAZOR_DETAIL_LAST)) {
  1370 		if (!fnmatch(pattern, name, FNM_CASEFOLD) ||
  1371 		    !fnmatch(pattern, url, FNM_CASEFOLD) ||
  1372 		    !fnmatch(pattern, summary, FNM_CASEFOLD) ||
  1373 		    !fnmatch(pattern, description, FNM_CASEFOLD))
  1374 			printf("%s-%s.%s: %s\n", name, version, arch, summary);
  1375 	}
  1376 	razor_package_iterator_destroy(pi);
  1377 	razor_set_unref(set);
  1378 
  1379 	return 0;
  1380 }
  1381 
  1382 static struct {
  1383 	const char *name;
  1384 	const char *description;
  1385 	int (*func)(int argc, const char *argv[]);
  1386 } razor_commands[] = {
  1387 	{ "list", "list all packages", command_list },
  1388 	{ "list-requires", "list all requires for the given package", command_list_requires },
  1389 	{ "list-provides", "list all provides for the given package", command_list_provides },
  1390 	{ "list-obsoletes", "list all obsoletes for the given package", command_list_obsoletes },
  1391 	{ "list-conflicts", "list all conflicts for the given package", command_list_conflicts },
  1392 	{ "list-scripts", "list all scripts for the given package", command_list_scripts },
  1393 	{ "list-files", "list files for package set", command_list_files },
  1394 	{ "list-file-packages", "list packages owning file", command_list_file_packages },
  1395 	{ "list-package-files", "list files in package", command_list_package_files },
  1396 	{ "what-requires", "list the packages that have the given requires", command_what_requires },
  1397 	{ "what-provides", "list the packages that have the given provides", command_what_provides },
  1398 	{ "import-yum", "import yum metadata files", command_import_yum },
  1399 #if HAVE_RPMLIB
  1400 	{ "import-rpmdb", "import the system rpm database", command_import_rpmdb },
  1401 #endif
  1402 	{ "import-rpms", "import rpms from the given directory", command_import_rpms },
  1403 	{ "update", "update all or specified packages", command_update },
  1404 	{ "remove", "remove specified packages", command_remove },
  1405 	{ "diff", "show diff between two package sets", command_diff },
  1406 	{ "install", "install rpm", command_install },
  1407 	{ "init", "init razor root", command_init },
  1408 	{ "download", "download packages", command_download },
  1409 	{ "info", "display package details", command_info },
  1410 	{ "search", "search package details", command_search }
  1411 };
  1412 
  1413 static int
  1414 usage(void)
  1415 {
  1416 	int i;
  1417 
  1418 	printf("usage:\n");
  1419 	for (i = 0; i < ARRAY_SIZE(razor_commands); i++)
  1420 		printf("  %-20s%s\n",
  1421 		       razor_commands[i].name, razor_commands[i].description);
  1422 
  1423 	return 1;
  1424 }
  1425 
  1426 int
  1427 main(int argc, const char *argv[])
  1428 {
  1429 	char *repo, *root;
  1430 	int i;
  1431 
  1432 	repo = getenv("RAZOR_REPO");
  1433 	if (repo != NULL)
  1434 		repo_filename = repo;
  1435 
  1436 	root = getenv("RAZOR_ROOT");
  1437 	if (root != NULL)
  1438 		install_root = root;
  1439 
  1440 	yum_url = getenv("YUM_URL");
  1441 	if (yum_url == NULL)
  1442 		yum_url = YUM_URL;
  1443 
  1444 	if (getenv("RAZOR_NO_ROOT_NAME_CHECKS"))
  1445 		razor_disable_root_name_checks(1);
  1446 
  1447 	if (argc < 2)
  1448 		return usage();
  1449 
  1450 	for (i = 0; i < ARRAY_SIZE(razor_commands); i++)
  1451 		if (strcmp(razor_commands[i].name, argv[1]) == 0)
  1452 			return razor_commands[i].func(argc - 2, argv + 2);
  1453 
  1454 	return usage();
  1455 }