src/main.c
author James Bowes <jbowes@redhat.com>
Wed Jul 09 10:11:13 2008 -0400 (2008-07-09)
changeset 318 829d6711b316
parent 316 5ebed314390c
child 320 53e1185e2366
permissions -rw-r--r--
Use strings to identify section types in the on-disk repo format.

Previously, a given razor file type had a fixed number of sections in a
fixed order, identified by an integer type. Now, sections are identified
by a named string (stored in a string pool after the section lists).

This will allow for razor files to contain arbitrary sections.

For bonus points, also drop the 4k section alignment and change the
magic byte string to "RZDB".

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