src/main.c
author J. Ali Harlow <ali@juiblex.co.uk>
Wed Apr 29 17:00:01 2009 +0100 (2009-04-29)
changeset 361 2523d03a840e
parent 351 48b0adfe3059
child 363 c75a2d5caae9
permissions -rw-r--r--
Add support for preloading lua modules. This is useful both when
providing lua bindings to applications based on librazor and when
producing static binaries using librazor (where otherwise the lua
POSIX library would need to be included as an additional dynamic
object).
     1 /*
     2  * Copyright (C) 2008  Kristian Høgsberg <krh@redhat.com>
     3  * Copyright (C) 2008  Red Hat, Inc
     4  * Copyright (C) 2009  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 updated_repo_filename[] = "system-updated.rzdb";
    46 static const char *install_root = "";
    47 static const char *repo_filename = system_repo_filename;
    48 static const char *yum_url;
    49 
    50 #define ARRAY_SIZE(a) (sizeof(a) / sizeof((a)[0]))
    51 
    52 static struct razor_package_iterator *
    53 create_iterator_from_argv(struct razor_set *set, int argc, const char *argv[])
    54 {
    55 	struct razor_package_query *query;
    56 	struct razor_package_iterator *iter;
    57 	struct razor_package *package;
    58 	const char *name, *pattern;
    59 	int i, count;
    60 
    61 	if (argc == 0)
    62 		return razor_package_iterator_create(set);
    63 
    64 	query = razor_package_query_create(set);
    65 
    66 	for (i = 0; i < argc; i++) {
    67 		iter = razor_package_iterator_create(set);
    68 		pattern = argv[i];
    69 		count = 0;
    70 		while (razor_package_iterator_next(iter, &package,
    71 						   RAZOR_DETAIL_NAME, &name,
    72 						   RAZOR_DETAIL_LAST)) {
    73 			if (fnmatch(pattern, name, 0) != 0)
    74 				continue;
    75 
    76 			razor_package_query_add_package(query, package);
    77 			count++;
    78 		}
    79 		razor_package_iterator_destroy(iter);
    80 
    81 		if (count == 0)
    82 			fprintf(stderr,
    83 				"no package matches \"%s\"\n", pattern);
    84 	}
    85 
    86 	return razor_package_query_finish(query);
    87 }
    88 
    89 #define LIST_PACKAGES_ONLY_NAMES 0x01
    90 
    91 static void
    92 list_packages(struct razor_package_iterator *iter, uint32_t flags)
    93 {
    94 	struct razor_package *package;
    95 	const char *name, *version, *arch;
    96 
    97 	while (razor_package_iterator_next(iter, &package,
    98 					   RAZOR_DETAIL_NAME, &name,
    99 					   RAZOR_DETAIL_VERSION, &version,
   100 					   RAZOR_DETAIL_ARCH, &arch,
   101 					   RAZOR_DETAIL_LAST)) {
   102 		if (flags & LIST_PACKAGES_ONLY_NAMES)
   103 			printf("%s\n", name);
   104 		else
   105 			printf("%s-%s.%s\n", name, version, arch);
   106 	}
   107 }
   108 
   109 static int
   110 command_list(int argc, const char *argv[])
   111 {
   112 	struct razor_package_iterator *pi;
   113 	struct razor_set *set;
   114 	uint32_t flags = 0;
   115 	int i = 0;
   116 
   117 	if (i < argc && strcmp(argv[i], "--only-names") == 0) {
   118 		flags |= LIST_PACKAGES_ONLY_NAMES;
   119 		i++;
   120 	}
   121 
   122 	set = razor_root_open_read_only(install_root);
   123 	if (set == NULL)
   124 		return 1;
   125 
   126 	pi = create_iterator_from_argv(set, argc - i, argv + i);
   127 	list_packages(pi, flags);
   128 	razor_package_iterator_destroy(pi);
   129 	razor_set_destroy(set);
   130 
   131 	return 0;
   132 }
   133 
   134 static void
   135 list_package_properties(struct razor_set *set,
   136 			struct razor_package *package, uint32_t type)
   137 {
   138 	struct razor_property_iterator *pi;
   139 	struct razor_property *property;
   140 	const char *name, *version;
   141 	uint32_t flags;
   142 
   143 	pi = razor_property_iterator_create(set, package);
   144 	while (razor_property_iterator_next(pi, &property,
   145 					    &name, &flags, &version)) {
   146 		if ((flags & RAZOR_PROPERTY_TYPE_MASK) != type)
   147 			continue;
   148 		printf("%s", name);
   149 		if (version[0] != '\0')
   150 			printf(" %s %s",
   151 			       razor_property_relation_to_string(property),
   152 			       version);
   153 
   154 		if (flags & ~(RAZOR_PROPERTY_RELATION_MASK | RAZOR_PROPERTY_TYPE_MASK)) {
   155 			printf(" [");
   156 			if (flags & RAZOR_PROPERTY_PRE)
   157 				printf(" pre");
   158 			if (flags & RAZOR_PROPERTY_POST)
   159 				printf(" post");
   160 			if (flags & RAZOR_PROPERTY_PREUN)
   161 				printf(" preun");
   162 			if (flags & RAZOR_PROPERTY_POSTUN)
   163 				printf(" postun");
   164 			printf(" ]");
   165 		}
   166 		printf("\n");
   167 	}
   168 	razor_property_iterator_destroy(pi);
   169 }
   170 
   171 static int
   172 list_properties(int argc, const char *argv[], uint32_t type)
   173 {
   174 	struct razor_set *set;
   175 	struct razor_package *package;
   176 	struct razor_package_iterator *pi;
   177 	const char *name, *version, *arch;
   178 
   179 	set = razor_root_open_read_only(install_root);
   180 	if (set == NULL)
   181 		return 1;
   182 
   183 	pi = create_iterator_from_argv(set, argc, argv);
   184 	while (razor_package_iterator_next(pi, &package,
   185 					   RAZOR_DETAIL_NAME, &name,
   186 					   RAZOR_DETAIL_VERSION, &version,
   187 					   RAZOR_DETAIL_ARCH, &arch,
   188 					   RAZOR_DETAIL_LAST))
   189 		list_package_properties(set, package, type);
   190 	razor_package_iterator_destroy(pi);
   191 	razor_set_destroy(set);
   192 
   193 	return 0;
   194 }
   195 
   196 static int
   197 command_list_requires(int argc, const char *argv[])
   198 {
   199 	return list_properties(argc, argv, RAZOR_PROPERTY_REQUIRES);
   200 }
   201 
   202 static int
   203 command_list_provides(int argc, const char *argv[])
   204 {
   205 	return list_properties(argc, argv, RAZOR_PROPERTY_PROVIDES);
   206 }
   207 
   208 static int
   209 command_list_obsoletes(int argc, const char *argv[])
   210 {
   211 	return list_properties(argc, argv, RAZOR_PROPERTY_OBSOLETES);
   212 }
   213 
   214 static int
   215 command_list_conflicts(int argc, const char *argv[])
   216 {
   217 	return list_properties(argc, argv, RAZOR_PROPERTY_CONFLICTS);
   218 }
   219 
   220 static int
   221 command_list_files(int argc, const char *argv[])
   222 {
   223 	struct razor_set *set;
   224 
   225 	set = razor_root_open_read_only(install_root);
   226 	if (set == NULL)
   227 		return 1;
   228 
   229 	razor_set_list_files(set, argv[0]);
   230 	razor_set_destroy(set);
   231 
   232 	return 0;
   233 }
   234 
   235 static int
   236 command_list_file_packages(int argc, const char *argv[])
   237 {
   238 	struct razor_set *set;
   239 	struct razor_package_iterator *pi;
   240 
   241 	set = razor_root_open_read_only(install_root);
   242 	if (set == NULL)
   243 		return 1;
   244 
   245 	pi = razor_package_iterator_create_for_file(set, argv[0]);
   246 	list_packages(pi, 0);
   247 	razor_package_iterator_destroy(pi);
   248 
   249 	razor_set_destroy(set);
   250 
   251 	return 0;
   252 }
   253 
   254 static int
   255 command_list_package_files(int argc, const char *argv[])
   256 {
   257 	struct razor_set *set;
   258 	struct razor_package_iterator *pi;
   259 	struct razor_package *package;
   260 	const char *name, *version, *arch;
   261 
   262 	set = razor_root_open_read_only(install_root);
   263 	if (set == NULL)
   264 		return 1;
   265 
   266 	pi = create_iterator_from_argv(set, argc, argv);
   267 	while (razor_package_iterator_next(pi, &package,
   268 					   RAZOR_DETAIL_NAME, &name,
   269 					   RAZOR_DETAIL_VERSION, &version,
   270 					   RAZOR_DETAIL_ARCH, &arch,
   271 					   RAZOR_DETAIL_LAST))
   272 		razor_set_list_package_files(set, package);
   273 	razor_package_iterator_destroy(pi);
   274 
   275 	razor_set_destroy(set);
   276 
   277 	return 0;
   278 }
   279 
   280 static int
   281 list_property_packages(const char *ref_name,
   282 		       const char *ref_version,
   283 		       uint32_t type)
   284 {
   285 	struct razor_set *set;
   286 	struct razor_property *property;
   287 	struct razor_property_iterator *prop_iter;
   288 	struct razor_package_iterator *pkg_iter;
   289 	const char *name, *version;
   290 	uint32_t flags;
   291 
   292 	if (ref_name == NULL)
   293 		return 0;
   294 
   295 	set = razor_root_open_read_only(install_root);
   296 	if (set == NULL)
   297 		return 1;
   298 
   299 	prop_iter = razor_property_iterator_create(set, NULL);
   300 	while (razor_property_iterator_next(prop_iter, &property,
   301 					    &name, &flags, &version)) {
   302 		if (strcmp(ref_name, name) != 0)
   303 			continue;
   304 		if (ref_version &&
   305 		    (flags & RAZOR_PROPERTY_RELATION_MASK) == RAZOR_PROPERTY_EQUAL &&
   306 		    strcmp(ref_version, version) != 0)
   307 			continue;
   308 		if ((flags & RAZOR_PROPERTY_TYPE_MASK) != type)
   309 			continue;
   310 
   311 		pkg_iter =
   312 			razor_package_iterator_create_for_property(set,
   313 								   property);
   314 		list_packages(pkg_iter, 0);
   315 		razor_package_iterator_destroy(pkg_iter);
   316 	}
   317 	razor_property_iterator_destroy(prop_iter);
   318 
   319 	razor_set_destroy(set);
   320 
   321 	return 0;
   322 }
   323 
   324 static int
   325 command_what_requires(int argc, const char *argv[])
   326 {
   327 	return list_property_packages(argv[0], argv[1],
   328 				      RAZOR_PROPERTY_REQUIRES);
   329 }
   330 
   331 static int
   332 command_what_provides(int argc, const char *argv[])
   333 {
   334 	return list_property_packages(argv[0], argv[1],
   335 				      RAZOR_PROPERTY_PROVIDES);
   336 }
   337 
   338 static int
   339 show_progress(void *clientp,
   340 	      double dltotal, double dlnow, double ultotal, double ulnow)
   341 {
   342 	const char *file = clientp;
   343 
   344 	if (!dlnow < dltotal)
   345 		fprintf(stderr, "\rdownloading %s, %dkB/%dkB",
   346 			file, (int) dlnow / 1024, (int) dltotal / 1024);
   347 
   348 	return 0;
   349 }
   350 
   351 static int
   352 download_if_missing(const char *url, const char *file)
   353 {
   354 #ifndef HAVE_CURL
   355 	return 1;
   356 #else
   357 	CURL *curl;
   358 	struct stat buf;
   359 	char error[256];
   360 	FILE *fp;
   361 	CURLcode res;
   362 	long response;
   363 
   364 	curl = curl_easy_init();
   365 	if (curl == NULL)
   366 		return 1;
   367 
   368 	curl_easy_setopt(curl, CURLOPT_ERRORBUFFER, error);
   369 	curl_easy_setopt(curl, CURLOPT_NOPROGRESS, 0);
   370 	curl_easy_setopt(curl, CURLOPT_PROGRESSFUNCTION, show_progress);
   371 	curl_easy_setopt(curl, CURLOPT_PROGRESSDATA, file);
   372 
   373 	if (stat(file, &buf) < 0) {
   374 		fp = fopen(file, "wb");
   375 		if (fp == NULL) {
   376 			fprintf(stderr,
   377 				"failed to open %s for writing\n", file);
   378 			return -1;
   379 		}
   380 		curl_easy_setopt(curl, CURLOPT_WRITEDATA, fp);
   381 		curl_easy_setopt(curl, CURLOPT_URL, url);
   382 		res = curl_easy_perform(curl);
   383 		fclose(fp);
   384 		if (res != CURLE_OK) {
   385 			fprintf(stderr, "curl error: %s\n", error);
   386 			unlink(file);
   387 			return -1;
   388 		}
   389 		res = curl_easy_getinfo(curl,
   390 					CURLINFO_RESPONSE_CODE, &response);
   391 		if (res != CURLE_OK) {
   392 			fprintf(stderr, "curl error: %s\n", error);
   393                         unlink(file);
   394                         return -1;
   395 		}
   396 		if (response != 200) {
   397 			fprintf(stderr, " - failed %ld\n", response);
   398                         unlink(file);
   399                         return -1;
   400 		}
   401 		fprintf(stderr, "\n");
   402 	}
   403 
   404 	curl_easy_cleanup(curl);
   405 
   406 	return 0;
   407 #endif	/* HAVE_CURL */
   408 }
   409 
   410 #define YUM_URL "http://download.fedora.redhat.com" \
   411 	"/pub/fedora/linux/development/i386/os"
   412 
   413 static int
   414 command_import_yum(int argc, const char *argv[])
   415 {
   416 	struct razor_set *set;
   417 	char buffer[512];
   418 
   419 	printf("downloading from %s.\n", yum_url);
   420 	snprintf(buffer, sizeof buffer,
   421 		 "%s/repodata/primary.xml.gz", yum_url);
   422 	if (download_if_missing(buffer, "primary.xml.gz") < 0)
   423 		return -1;
   424 	snprintf(buffer, sizeof buffer,
   425 		 "%s/repodata/filelists.xml.gz", yum_url);
   426 	if (download_if_missing(buffer, "filelists.xml.gz") < 0)
   427 		return -1;
   428 
   429 	set = razor_set_create_from_yum();
   430 	if (set == NULL)
   431 		return 1;
   432 	if (razor_set_write(set, rawhide_repo_filename, RAZOR_REPO_FILE_MAIN)) {
   433 		perror(rawhide_repo_filename);
   434 		return -1;
   435 	}
   436 	if (razor_set_write(set, "rawhide-details.rzdb",
   437 	    RAZOR_REPO_FILE_DETAILS)) {
   438 		perror("rawhide-details.rzdb");
   439 		return -1;
   440 	}
   441 	if (razor_set_write(set, "rawhide-files.rzdb", RAZOR_REPO_FILE_FILES)) {
   442 		perror("rawhide-files.rzdb");
   443 		return -1;
   444 	}
   445 	razor_set_destroy(set);
   446 	printf("wrote %s\n", rawhide_repo_filename);
   447 
   448 	return 0;
   449 }
   450 
   451 #if HAVE_RPMLIB
   452 static int
   453 command_import_rpmdb(int argc, const char *argv[])
   454 {
   455 	struct razor_set *set;
   456 	struct razor_root *root;
   457 
   458 	root = razor_root_open(install_root);
   459 	if (root == NULL)
   460 		return 1;
   461 
   462 	set = razor_set_create_from_rpmdb();
   463 	if (set == NULL)
   464 		return 1;
   465 
   466 	razor_root_update(root, set);
   467 
   468 	return razor_root_commit(root);
   469 }
   470 #endif
   471 
   472 static int
   473 mark_packages_for_update(struct razor_transaction *trans,
   474 			 struct razor_set *set, const char *pattern)
   475 {
   476 	struct razor_package_iterator *pi;
   477 	struct razor_package *package;
   478 	const char *name;
   479 	int matches = 0;
   480 
   481 	pi = razor_package_iterator_create(set);
   482 	while (razor_package_iterator_next(pi, &package,
   483 					   RAZOR_DETAIL_NAME, &name,
   484 					   RAZOR_DETAIL_LAST)) {
   485 		if (pattern && fnmatch(pattern, name, 0) == 0) {
   486 			razor_transaction_update_package(trans, package);
   487 			matches++;
   488 		}
   489 	}
   490 	razor_package_iterator_destroy(pi);
   491 
   492 	return matches;
   493 }
   494 
   495 static int
   496 mark_packages_for_removal(struct razor_transaction *trans,
   497 			  struct razor_set *set, const char *pattern)
   498 {
   499 	struct razor_package_iterator *pi;
   500 	struct razor_package *package;
   501 	const char *name;
   502 	int matches = 0;
   503 
   504 	pi = razor_package_iterator_create(set);
   505 	while (razor_package_iterator_next(pi, &package,
   506 					   RAZOR_DETAIL_NAME, &name,
   507 					   RAZOR_DETAIL_LAST)) {
   508 		if (pattern && fnmatch(pattern, name, 0) == 0) {
   509 			razor_transaction_remove_package(trans, package);
   510 			matches++;
   511 		}
   512 	}
   513 	razor_package_iterator_destroy(pi);
   514 
   515 	return matches;
   516 }
   517 
   518 static int
   519 command_update(int argc, const char *argv[])
   520 {
   521 	struct razor_set *set, *upstream;
   522 	struct razor_transaction *trans;
   523 	int i, errors;
   524 
   525 	set = razor_root_open_read_only(install_root);
   526 	if (set == NULL)
   527 		return 1;
   528 
   529 	upstream = razor_set_open(rawhide_repo_filename);
   530 	if (upstream == NULL ||
   531 	    razor_set_open_details(upstream, "rawhide-details.rzdb") ||
   532 	    razor_set_open_files(upstream, "rawhide-files.rzdb"))
   533 		return 1;
   534 
   535 	trans = razor_transaction_create(set, upstream);
   536 	if (argc == 0)
   537 		razor_transaction_update_all(trans);
   538 	for (i = 0; i < argc; i++) {
   539 		if (mark_packages_for_update(trans, set, argv[i]) == 0) {
   540 			fprintf(stderr, "no match for %s\n", argv[i]);
   541 			return 1;
   542 		}
   543 	}
   544 
   545 	razor_transaction_resolve(trans);
   546 	errors = razor_transaction_describe(trans);
   547 	if (errors) {
   548 		fprintf(stderr, "unresolved dependencies\n");
   549 		return 1;
   550 	}
   551 
   552 	set = razor_transaction_finish(trans);
   553 	razor_set_write(set, updated_repo_filename, RAZOR_REPO_FILE_MAIN);
   554 	razor_set_destroy(set);
   555 	razor_set_destroy(upstream);
   556 	printf("wrote system-updated.rzdb\n");
   557 
   558 	return 0;
   559 }
   560 
   561 static int
   562 command_remove(int argc, const char *argv[])
   563 {
   564 	struct razor_set *set, *upstream;
   565 	struct razor_transaction *trans;
   566 	int i, errors;
   567 
   568 	set = razor_root_open_read_only(install_root);
   569 	if (set == NULL)
   570 		return 1;
   571 
   572 	upstream = razor_set_create();
   573 	trans = razor_transaction_create(set, upstream);
   574 	for (i = 0; i < argc; i++) {
   575 		if (mark_packages_for_removal(trans, set, argv[i]) == 0) {
   576 			fprintf(stderr, "no match for %s\n", argv[i]);
   577 			return 1;
   578 		}
   579 	}
   580 
   581 	razor_transaction_resolve(trans);
   582 	errors = razor_transaction_describe(trans);
   583 	if (errors)
   584 		return 1;
   585 
   586 	set = razor_transaction_finish(trans);
   587 	razor_set_write(set, updated_repo_filename, RAZOR_REPO_FILE_MAIN);
   588 	razor_set_destroy(set);
   589 	razor_set_destroy(upstream);
   590 	printf("wrote system-updated.rzdb\n");
   591 
   592 	return 0;
   593 }
   594 
   595 static void
   596 print_diff(enum razor_diff_action action,
   597 	   struct razor_package *package,
   598 	   const char *name,
   599 	   const char *version,
   600 	   const char *arch,
   601 	   void *data)
   602 {
   603 	if (action == RAZOR_DIFF_ACTION_ADD)
   604 		printf("install %s-%s.%s\n", name, version, arch);
   605 	if (action == RAZOR_DIFF_ACTION_REMOVE)
   606 		printf("remove %s-%s.%s\n", name, version, arch);
   607 }
   608 
   609 static int
   610 command_diff(int argc, const char *argv[])
   611 {
   612 	struct razor_set *set, *updated;
   613 
   614 	set = razor_root_open_read_only(install_root);
   615 	updated = razor_set_open(updated_repo_filename);
   616 	if (set == NULL || updated == NULL)
   617 		return 1;
   618 
   619 	razor_set_diff(set, updated, print_diff, NULL);
   620 
   621 	razor_set_destroy(set);
   622 	razor_set_destroy(updated);
   623 
   624 	return 0;
   625 }
   626 
   627 static int
   628 command_import_rpms(int argc, const char *argv[])
   629 {
   630 	DIR *dir;
   631 	struct dirent *de;
   632 	struct razor_importer *importer;
   633 	struct razor_set *set;
   634 	struct razor_rpm *rpm;
   635 	int len, imported_count = 0;
   636 	char filename[256];
   637 	const char *dirname = argv[0];
   638 
   639 	if (dirname == NULL) {
   640 		fprintf(stderr, "usage: razor import-rpms DIR\n");
   641 		return -1;
   642 	}
   643 
   644 	dir = opendir(dirname);
   645 	if (dir == NULL) {
   646 		fprintf(stderr, "couldn't read dir %s\n", dirname);
   647 		return -1;
   648 	}
   649 
   650 	importer = razor_importer_create();
   651 
   652 	while (de = readdir(dir), de != NULL) {
   653 		len = strlen(de->d_name);
   654 		if (len < 5 || strcmp(de->d_name + len - 4, ".rpm") != 0)
   655 		    continue;
   656 		snprintf(filename, sizeof filename,
   657 			 "%s/%s", dirname, de->d_name);
   658 		rpm = razor_rpm_open(filename);
   659 		if (rpm == NULL) {
   660 			fprintf(stderr,
   661 				"failed to open rpm \"%s\"\n", filename);
   662 			continue;
   663 		}
   664 		if (razor_importer_add_rpm(importer, rpm)) {
   665 			fprintf(stderr, "couldn't import %s\n", filename);
   666 			break;
   667 		}
   668 		razor_rpm_close(rpm);
   669 
   670 		printf("\rimporting %d", ++imported_count);
   671 		fflush(stdout);
   672 	}
   673 
   674 	if (de != NULL) {
   675 		razor_importer_destroy(importer);
   676 		return -1;
   677 	}
   678 
   679 	printf("\nsaving\n");
   680 	set = razor_importer_finish(importer);
   681 
   682 	razor_set_write(set, repo_filename, RAZOR_REPO_FILE_MAIN);
   683 	razor_set_write(set, "system-details.rzdb", RAZOR_REPO_FILE_DETAILS);
   684 	razor_set_write(set, "system-files.rzdb", RAZOR_REPO_FILE_FILES);
   685 	razor_set_destroy(set);
   686 	printf("wrote %s\n", repo_filename);
   687 
   688 	return 0;
   689 }
   690 
   691 static const char *
   692 rpm_filename(const char *name, const char *version, const char *arch)
   693 {
   694 	static char file[PATH_MAX];
   695  	const char *v;
   696  
   697  	/* Skip epoch */
   698 	v = strchr(version, ':');
   699  	if (v != NULL)
   700  		v = v + 1;
   701  	else
   702 		v = version;
   703 
   704 	snprintf(file, sizeof file, "%s-%s.%s.rpm", name, v, arch);
   705 
   706 	return file;
   707 }
   708 
   709 static int
   710 download_packages(struct razor_set *system, struct razor_set *next)
   711 {
   712 	struct razor_install_iterator *ii;
   713 	struct razor_package *package;
   714 	struct razor_set *set;
   715 	enum razor_install_action action;
   716 	const char *name, *version, *arch;
   717 	char file[PATH_MAX], url[256];
   718 	int errors = 0, count;
   719 
   720 	ii = razor_set_create_install_iterator(system, next);
   721 	while (razor_install_iterator_next(ii, &set, &package,
   722 					   &action, &count)) {
   723 		if (action == RAZOR_INSTALL_ACTION_REMOVE)
   724 			continue;
   725 
   726 		razor_package_get_details(set, package,
   727 					  RAZOR_DETAIL_NAME, &name,
   728 					  RAZOR_DETAIL_VERSION, &version,
   729 					  RAZOR_DETAIL_ARCH, &arch,
   730 					  RAZOR_DETAIL_LAST);
   731 		
   732 		snprintf(url, sizeof url,
   733 			 "%s/Packages/%s",
   734 			 yum_url, rpm_filename(name, version, arch));
   735 		snprintf(file, sizeof file,
   736 			 "rpms/%s", rpm_filename(name, version, arch));
   737 		if (download_if_missing(url, file) < 0)
   738 			errors++;
   739 	}
   740 	razor_install_iterator_destroy(ii);
   741 
   742 	if (errors > 0) {
   743 		fprintf(stderr, "failed to download %d packages\n", errors);
   744                 return -1;
   745         }
   746 
   747 	return 0;
   748 }
   749 
   750 static struct razor_set *
   751 relocate_packages(struct razor_set *set, struct razor_relocations *relocations)
   752 {
   753 	struct razor_importer *importer;
   754 	struct razor_property_iterator *prop_iter;
   755 	struct razor_package_iterator *pkg_iter;
   756  	struct razor_file_iterator *file_iter;
   757  	struct razor_package *package;
   758 	struct razor_property *property;
   759 	struct razor_rpm *rpm;
   760 	const char *name, *version, *arch, *summary, *desc, *url, *license;
   761 	char file[PATH_MAX];
   762 	uint32_t flags;
   763 
   764 	importer = razor_importer_create();
   765 	pkg_iter = razor_package_iterator_create(set);
   766 
   767 	while (razor_package_iterator_next(pkg_iter, &package,
   768 					   RAZOR_DETAIL_NAME, &name,
   769 					   RAZOR_DETAIL_VERSION, &version,
   770 					   RAZOR_DETAIL_ARCH, &arch,
   771 					   RAZOR_DETAIL_SUMMARY, &summary,
   772 					   RAZOR_DETAIL_DESCRIPTION, &desc,
   773 					   RAZOR_DETAIL_URL, &url,
   774 					   RAZOR_DETAIL_LICENSE, &license,
   775 					   RAZOR_DETAIL_LAST)) {
   776 		snprintf(file, sizeof file,
   777 			 "rpms/%s", rpm_filename(name, version, arch));
   778 		rpm = razor_rpm_open(file);
   779 		if (rpm == NULL) {
   780 			fprintf(stderr, "failed to open rpm %s\n", file);
   781 			razor_package_iterator_destroy(pkg_iter);
   782 			razor_importer_destroy(importer);
   783 			return NULL;
   784 		}
   785 
   786 		razor_relocations_set_rpm(relocations, rpm);
   787 		razor_rpm_close(rpm);
   788 
   789 		razor_importer_begin_package(importer, name, version, arch);
   790 		razor_importer_add_details(importer,
   791 					   summary, desc, url, license);
   792 
   793 		prop_iter = razor_property_iterator_create(set, package);
   794 		while (razor_property_iterator_next(prop_iter, &property,
   795 						    &name, &flags, &version))
   796 			razor_importer_add_property(importer,
   797 						    name, flags, version);
   798 		razor_property_iterator_destroy(prop_iter);
   799 
   800 		file_iter = razor_file_iterator_create(set, package);
   801 		while (razor_file_iterator_next(file_iter, &name)) {
   802 			name = razor_relocations_apply(relocations, name);
   803 			razor_importer_add_file(importer, name);
   804 		}
   805 		razor_file_iterator_destroy(file_iter);
   806 
   807 		razor_importer_finish_package(importer);
   808 	}
   809 
   810 	razor_package_iterator_destroy(pkg_iter);
   811 	return razor_importer_finish(importer);
   812 }
   813 
   814 static int
   815 install_packages(struct razor_set *system, struct razor_set *next,
   816 		 struct razor_relocations *relocations)
   817 {
   818 	struct razor_install_iterator *ii;
   819 	struct razor_package *package;
   820 	struct razor_set *set;
   821 	enum razor_install_action action;
   822 	struct razor_rpm *rpm;
   823 	const char *name, *version, *arch;
   824 	char file[PATH_MAX];
   825 	int count;
   826 
   827 	ii = razor_set_create_install_iterator(system, next);
   828 	while (razor_install_iterator_next(ii, &set, &package,
   829 					   &action, &count)) {
   830 		if (action == RAZOR_INSTALL_ACTION_REMOVE)
   831 			continue;
   832 
   833 		razor_package_get_details(set, package,
   834 					  RAZOR_DETAIL_NAME, &name,
   835 					  RAZOR_DETAIL_VERSION, &version,
   836 					  RAZOR_DETAIL_ARCH, &arch,
   837 					  RAZOR_DETAIL_LAST);
   838 
   839 		printf("install %s-%s\n", name, version);
   840 
   841 		snprintf(file, sizeof file,
   842 			 "rpms/%s", rpm_filename(name, version, arch));
   843 		rpm = razor_rpm_open(file);
   844 		if (rpm == NULL) {
   845 			fprintf(stderr, "failed to open rpm %s\n", file);
   846 			return -1;
   847 		}
   848 		if (relocations)
   849 			razor_rpm_set_relocations(rpm, relocations);
   850 		if (razor_rpm_install(rpm, install_root) < 0) {
   851 			fprintf(stderr,
   852 				"failed to install rpm %s\n", file);
   853 			return -1;
   854 		}
   855 		razor_rpm_close(rpm);
   856 	}
   857 	razor_install_iterator_destroy(ii);
   858 
   859 	return 0;
   860 }
   861 
   862 static int
   863 command_install(int argc, const char *argv[])
   864 {
   865 	struct razor_root *root;
   866 	struct razor_relocations *relocations=NULL;
   867 	struct razor_set *system, *upstream, *next, *set;
   868 	struct razor_transaction *trans;
   869 	int i, len, dependencies = 1;
   870 	char *oldpath;
   871 
   872 	root = razor_root_open(install_root);
   873 	if (root == NULL)
   874 		return 1;
   875 
   876 	for (i = 0; i < argc; i++) {
   877 		if (strcmp(argv[i], "--no-dependencies") == 0)
   878 			dependencies = 0;
   879 		else if (strcmp(argv[i], "--relocate") == 0) {
   880 			i++;
   881 			if (i >= argc || strchr(argv[i], '=') == NULL) {
   882 				fprintf(stderr,
   883 				    "Usage: razor install [OPTION...] RPM\n");
   884 				fprintf(stderr, "Options:\n");
   885 				fprintf(stderr, "    [--no-dependencies]\n");
   886 				fprintf(stderr,
   887 				    "    [--relocate OLDPATH=NEWPATH] RPM\n");
   888 				return -1;
   889 			}
   890 			len = strchr(argv[i], '=') - argv[i];
   891 			oldpath = malloc(len + 1);
   892 			strncpy(oldpath, argv[i], len);
   893 			oldpath[len] = '\0';
   894 			if (!relocations)
   895 			       relocations = razor_relocations_create();
   896 			razor_relocations_add(relocations, oldpath,
   897 					      argv[i] + len + 1);
   898 			free(oldpath);
   899 		} else
   900 			break;
   901 	}
   902 
   903 	system = razor_root_get_system_set(root);
   904 	upstream = razor_set_open(rawhide_repo_filename);
   905 	if (upstream == NULL ||
   906 	    razor_set_open_details(upstream, "rawhide-details.rzdb") ||
   907 	    razor_set_open_files(upstream, "rawhide-files.rzdb")) {
   908 			fprintf(stderr, "couldn't open rawhide repo\n");
   909 			razor_root_close(root);
   910 			return 1;
   911 	}		
   912 
   913 	if (relocations) {
   914 		set = relocate_packages(upstream, relocations);
   915 		razor_set_destroy(upstream);
   916 		upstream = set;
   917 	}
   918 
   919 	trans = razor_transaction_create(system, upstream);
   920 
   921 	for (; i < argc; i++) {
   922 		if (mark_packages_for_update(trans, upstream, argv[i]) == 0) {
   923 			fprintf(stderr, "no package matched %s\n", argv[i]);
   924 			razor_root_close(root);
   925 			return 1;
   926 		}
   927 	}
   928 
   929 	if (dependencies) {
   930 		razor_transaction_resolve(trans);
   931 		if (razor_transaction_describe(trans) > 0) {
   932 			razor_root_close(root);
   933 			return 1;
   934 		}
   935 	}
   936 
   937 	next = razor_transaction_finish(trans);
   938 
   939 	razor_root_update(root, next);
   940 
   941 	if (mkdir("rpms", 0777) && errno != EEXIST) {
   942 		fprintf(stderr, "failed to create rpms directory.\n");
   943 		razor_root_close(root);
   944 		return 1;
   945 	}
   946 
   947 	if (download_packages(system, next) < 0) {
   948 		razor_root_close(root);
   949                 return 1;
   950         }
   951 
   952 	install_packages(system, next, relocations);
   953 
   954 	if (relocations)
   955 		razor_relocations_destroy(relocations);
   956 	razor_set_destroy(next);
   957 	razor_set_destroy(upstream);
   958 
   959 	return razor_root_commit(root);
   960 }
   961 
   962 static int
   963 command_init(int argc, const char *argv[])
   964 {
   965 	return razor_root_create(install_root);
   966 }
   967 
   968 static int
   969 command_download(int argc, const char *argv[])
   970 {
   971 	struct razor_set *set;
   972 	struct razor_package_iterator *pi;
   973 	struct razor_package *package;
   974 	const char *pattern = argv[0], *name, *version, *arch;
   975 	char url[256], file[256];
   976 	int matches = 0;
   977 
   978 	if (mkdir("rpms", 0777) && errno != EEXIST) {
   979 		fprintf(stderr, "failed to create rpms directory.\n");
   980 		return 1;
   981 	}
   982 
   983 	set = razor_set_open(rawhide_repo_filename);
   984 	pi = razor_package_iterator_create(set);
   985 	while (razor_package_iterator_next(pi, &package,
   986 					   RAZOR_DETAIL_NAME, &name,
   987 					   RAZOR_DETAIL_VERSION, &version,
   988 					   RAZOR_DETAIL_ARCH, &arch,
   989 					   RAZOR_DETAIL_LAST)) {
   990 		if (pattern && fnmatch(pattern, name, 0) != 0)
   991 			continue;
   992 
   993 		matches++;
   994 		snprintf(url, sizeof url,
   995 			 "%s/Packages/%s-%s.%s.rpm",
   996 			 yum_url, name, version, arch);
   997 		snprintf(file, sizeof file,
   998 			 "rpms/%s-%s.%s.rpm", name, version, arch);
   999 		download_if_missing(url, file);
  1000 	}
  1001 	razor_package_iterator_destroy(pi);
  1002 	razor_set_destroy(set);
  1003 
  1004 	if (matches == 0)
  1005 		fprintf(stderr, "no packages matched \"%s\"\n", pattern);
  1006 	else if (matches == 1)
  1007 		fprintf(stderr, "downloaded 1 package\n");
  1008 	else
  1009 		fprintf(stderr, "downloaded %d packages\n", matches);
  1010 
  1011 	return 0;
  1012 }
  1013 
  1014 static int
  1015 command_info(int argc, const char *argv[])
  1016 {
  1017 	struct razor_set *set;
  1018 	struct razor_package_iterator *pi;
  1019 	struct razor_package *package;
  1020 	const char *pattern = argv[0], *name, *version, *arch;
  1021 	const char *summary, *description, *url, *license;
  1022 
  1023 	set = razor_root_open_read_only(install_root);
  1024 	if (set == NULL)
  1025 		return 1;
  1026 
  1027 	pi = razor_package_iterator_create(set);
  1028 	while (razor_package_iterator_next(pi, &package,
  1029 					   RAZOR_DETAIL_NAME, &name,
  1030 					   RAZOR_DETAIL_VERSION, &version,
  1031 					   RAZOR_DETAIL_ARCH, &arch,
  1032 					   RAZOR_DETAIL_LAST)) {
  1033 		if (pattern && fnmatch(pattern, name, 0) != 0)
  1034 			continue;
  1035 
  1036 		razor_package_get_details (set, package,
  1037 					   RAZOR_DETAIL_SUMMARY, &summary,
  1038 					   RAZOR_DETAIL_DESCRIPTION, &description,
  1039 					   RAZOR_DETAIL_URL, &url,
  1040 					   RAZOR_DETAIL_LICENSE, &license,
  1041 					   RAZOR_DETAIL_LAST);
  1042 
  1043 		printf ("Name:        %s\n", name);
  1044 		printf ("Arch:        %s\n", arch);
  1045 		printf ("Version:     %s\n", version);
  1046 		printf ("URL:         %s\n", url);
  1047 		printf ("License:     %s\n", license);
  1048 		printf ("Summary:     %s\n", summary);
  1049 		printf ("Description:\n");
  1050 		printf ("%s\n", description);
  1051 		printf ("\n");
  1052 	}
  1053 	razor_package_iterator_destroy(pi);
  1054 	razor_set_destroy(set);
  1055 
  1056 	return 0;
  1057 }
  1058 
  1059 #define SEARCH_MAX 256
  1060 
  1061 static int
  1062 command_search(int argc, const char *argv[])
  1063 {
  1064 	struct razor_set *set;
  1065 	struct razor_package_iterator *pi;
  1066 	struct razor_package *package;
  1067 	char pattern[SEARCH_MAX];
  1068 	const char *name, *version, *arch;
  1069 	const char *summary, *description, *url, *license;
  1070 
  1071 	if (!argv[0]) {
  1072 		fprintf(stderr, "must specify a search term\n");
  1073 		return 1;
  1074 	}
  1075 
  1076 	snprintf(pattern, sizeof pattern, "*%s*", argv[0]);
  1077 
  1078 	set = razor_set_open(rawhide_repo_filename);
  1079 	if (set == NULL)
  1080 		return 1;
  1081 
  1082 	if (razor_set_open_details(set, "rawhide-details.rzdb"))
  1083 		return 1;
  1084 
  1085 	pi = razor_package_iterator_create(set);
  1086 	while (razor_package_iterator_next(pi, &package,
  1087 					   RAZOR_DETAIL_NAME, &name,
  1088 					   RAZOR_DETAIL_VERSION, &version,
  1089 					   RAZOR_DETAIL_ARCH, &arch,
  1090 					   RAZOR_DETAIL_SUMMARY, &summary,
  1091 					   RAZOR_DETAIL_DESCRIPTION, &description,
  1092 					   RAZOR_DETAIL_URL, &url,
  1093 					   RAZOR_DETAIL_LICENSE, &license,
  1094 					   RAZOR_DETAIL_LAST)) {
  1095 		if (!fnmatch(pattern, name, FNM_CASEFOLD) ||
  1096 		    !fnmatch(pattern, url, FNM_CASEFOLD) ||
  1097 		    !fnmatch(pattern, summary, FNM_CASEFOLD) ||
  1098 		    !fnmatch(pattern, description, FNM_CASEFOLD))
  1099 			printf("%s-%s.%s: %s\n", name, version, arch, summary);
  1100 	}
  1101 	razor_package_iterator_destroy(pi);
  1102 	razor_set_destroy(set);
  1103 
  1104 	return 0;
  1105 }
  1106 
  1107 static struct {
  1108 	const char *name;
  1109 	const char *description;
  1110 	int (*func)(int argc, const char *argv[]);
  1111 } razor_commands[] = {
  1112 	{ "list", "list all packages", command_list },
  1113 	{ "list-requires", "list all requires for the given package", command_list_requires },
  1114 	{ "list-provides", "list all provides for the given package", command_list_provides },
  1115 	{ "list-obsoletes", "list all obsoletes for the given package", command_list_obsoletes },
  1116 	{ "list-conflicts", "list all conflicts for the given package", command_list_conflicts },
  1117 	{ "list-files", "list files for package set", command_list_files },
  1118 	{ "list-file-packages", "list packages owning file", command_list_file_packages },
  1119 	{ "list-package-files", "list files in package", command_list_package_files },
  1120 	{ "what-requires", "list the packages that have the given requires", command_what_requires },
  1121 	{ "what-provides", "list the packages that have the given provides", command_what_provides },
  1122 	{ "import-yum", "import yum metadata files", command_import_yum },
  1123 #if HAVE_RPMLIB
  1124 	{ "import-rpmdb", "import the system rpm database", command_import_rpmdb },
  1125 #endif
  1126 	{ "import-rpms", "import rpms from the given directory", command_import_rpms },
  1127 	{ "update", "update all or specified packages", command_update },
  1128 	{ "remove", "remove specified packages", command_remove },
  1129 	{ "diff", "show diff between two package sets", command_diff },
  1130 	{ "install", "install rpm", command_install },
  1131 	{ "init", "init razor root", command_init },
  1132 	{ "download", "download packages", command_download },
  1133 	{ "info", "display package details", command_info },
  1134 	{ "search", "search package details", command_search }
  1135 };
  1136 
  1137 static int
  1138 usage(void)
  1139 {
  1140 	int i;
  1141 
  1142 	printf("usage:\n");
  1143 	for (i = 0; i < ARRAY_SIZE(razor_commands); i++)
  1144 		printf("  %-20s%s\n",
  1145 		       razor_commands[i].name, razor_commands[i].description);
  1146 
  1147 	return 1;
  1148 }
  1149 
  1150 int
  1151 main(int argc, const char *argv[])
  1152 {
  1153 	char *repo, *root;
  1154 	int i;
  1155 
  1156 	repo = getenv("RAZOR_REPO");
  1157 	if (repo != NULL)
  1158 		repo_filename = repo;
  1159 
  1160 	root = getenv("RAZOR_ROOT");
  1161 	if (root != NULL)
  1162 		install_root = root;
  1163 
  1164 	yum_url = getenv("YUM_URL");
  1165 	if (yum_url == NULL)
  1166 		yum_url = YUM_URL;
  1167 
  1168 	if (getenv("RAZOR_NO_ROOT_NAME_CHECKS"))
  1169 		razor_disable_root_name_checks(1);
  1170 
  1171 	if (argc < 2)
  1172 		return usage();
  1173 
  1174 	for (i = 0; i < ARRAY_SIZE(razor_commands); i++)
  1175 		if (strcmp(razor_commands[i].name, argv[1]) == 0)
  1176 			return razor_commands[i].func(argc - 2, argv + 2);
  1177 
  1178 	return usage();
  1179 }