main.c
author Kristian H?gsberg <krh@jiraiya.boston.redhat.com>
Wed Apr 09 02:41:03 2008 -0400 (2008-04-09)
changeset 211 cf0ca962262b
parent 210 c78f677d96b8
child 212 e8f493d8ff9a
permissions -rw-r--r--
Use the cpio headers instead of the rpm headers when unpacking.

The files in the cpio payload doesn't actually follow the file order
in the rpm headers, so we need to decode the cpio header and use the
information there.
     1 #include <stdlib.h>
     2 #include <stddef.h>
     3 #include <stdio.h>
     4 #include <stdint.h>
     5 #include <string.h>
     6 #include <sys/stat.h>
     7 #include <unistd.h>
     8 #include <fcntl.h>
     9 #include <dirent.h>
    10 #include <curl/curl.h>
    11 #include <fnmatch.h>
    12 #include <errno.h>
    13 #include "razor.h"
    14 #include "razor-internal.h"
    15 
    16 static const char system_repo_filename[] = "system.repo";
    17 static const char next_repo_filename[] = "system-next.repo";
    18 static const char rawhide_repo_filename[] = "rawhide.repo";
    19 static const char updated_repo_filename[] = "system-updated.repo";
    20 static const char razor_root_path[] = "/var/lib/razor";
    21 static const char root[] = "install";
    22 static const char *repo_filename = system_repo_filename;
    23 
    24 static int
    25 command_list(int argc, const char *argv[])
    26 {
    27 	struct razor_set *set;
    28 	struct razor_package_iterator *pi;
    29 	struct razor_package *package;
    30 	const char *pattern, *name, *version, *arch;
    31 	int only_names = 0, i = 0;
    32 
    33 	if (i < argc && strcmp(argv[i], "--only-names") == 0) {
    34 		only_names = 1;
    35 		i++;
    36 	}
    37 
    38 	pattern = argv[i];
    39 	set = razor_set_open(repo_filename);
    40 	pi = razor_package_iterator_create(set);
    41 	while (razor_package_iterator_next(pi, &package,
    42 					   &name, &version, &arch)) {
    43 		if (pattern && fnmatch(pattern, name, 0) != 0)
    44 			continue;
    45 
    46 		if (only_names)
    47 			printf("%s\n", name);
    48 		else
    49 			printf("%s-%s.%s\n", name, version, arch);
    50 	}
    51 	razor_package_iterator_destroy(pi);
    52 	razor_set_destroy(set);
    53 
    54 	return 0;
    55 }
    56 
    57 static int
    58 list_properties(const char *package_name,
    59 		enum razor_property_type required_type)
    60 {
    61 	struct razor_set *set;
    62 	struct razor_property *property;
    63 	struct razor_package *package;
    64 	struct razor_property_iterator *pi;
    65 	const char *name, *version;
    66 	enum razor_property_type type;
    67 	enum razor_version_relation relation;
    68 
    69 	set = razor_set_open(repo_filename);
    70 	if (package_name)
    71 		package = razor_set_get_package(set, package_name);
    72 	else
    73 		package = NULL;
    74 
    75 	pi = razor_property_iterator_create(set, package);
    76 	while (razor_property_iterator_next(pi, &property,
    77 					    &name, &relation, &version,
    78 					    &type)) {
    79 		if (type != required_type)
    80 			continue;
    81 		if (version[0] == '\0')
    82 			printf("%s\n", name);
    83 		else
    84 			printf("%s %s %s\n", name,
    85 			       razor_version_relations[relation], version);
    86 	}
    87 	razor_property_iterator_destroy(pi);
    88 
    89 	razor_set_destroy(set);
    90 
    91 	return 0;
    92 }
    93 
    94 static int
    95 command_list_requires(int argc, const char *argv[])
    96 {
    97 	return list_properties(argv[0], RAZOR_PROPERTY_REQUIRES);
    98 }
    99 
   100 static int
   101 command_list_provides(int argc, const char *argv[])
   102 {
   103 	return list_properties(argv[0], RAZOR_PROPERTY_PROVIDES);
   104 }
   105 
   106 static int
   107 command_list_obsoletes(int argc, const char *argv[])
   108 {
   109 	return list_properties(argv[0], RAZOR_PROPERTY_OBSOLETES);
   110 }
   111 
   112 static int
   113 command_list_conflicts(int argc, const char *argv[])
   114 {
   115 	return list_properties(argv[0], RAZOR_PROPERTY_CONFLICTS);
   116 }
   117 
   118 static int
   119 command_list_files(int argc, const char *argv[])
   120 {
   121 	struct razor_set *set;
   122 
   123 	set = razor_set_open(repo_filename);
   124 	if (set == NULL)
   125 		return 1;
   126 	razor_set_list_files(set, argv[0]);
   127 	razor_set_destroy(set);
   128 
   129 	return 0;
   130 }
   131 
   132 static int
   133 command_list_file_packages(int argc, const char *argv[])
   134 {
   135 	struct razor_set *set;
   136 	struct razor_package_iterator *pi;
   137 	struct razor_package *package;
   138 	const char *name, *version, *arch;
   139 
   140 	set = razor_set_open(repo_filename);
   141 	if (set == NULL)
   142 		return 1;
   143 
   144 	pi = razor_package_iterator_create_for_file(set, argv[0]);
   145 	while (razor_package_iterator_next(pi, &package,
   146 					   &name, &version, &arch))
   147 		printf("%s-%s\n", name, version);
   148 	razor_package_iterator_destroy(pi);
   149 
   150 	razor_set_destroy(set);
   151 
   152 	return 0;
   153 }
   154 
   155 static int
   156 command_list_package_files(int argc, const char *argv[])
   157 {
   158 	struct razor_set *set;
   159 
   160 	set = razor_set_open(repo_filename);
   161 	if (set == NULL)
   162 		return 1;
   163 	razor_set_list_package_files(set, argv[0]);
   164 	razor_set_destroy(set);
   165 
   166 	return 0;
   167 }
   168 
   169 static void
   170 list_packages_for_property(struct razor_set *set,
   171 			   struct razor_property *property)
   172 {
   173 	struct razor_package_iterator *pi;
   174 	struct razor_package *package;
   175 	const char *name, *version, *arch;
   176 
   177 	pi = razor_package_iterator_create_for_property(set, property);
   178 	while (razor_package_iterator_next(pi, &package,
   179 					   &name, &version, &arch))
   180 		printf("%s-%s.%s\n", name, version, arch);
   181 	razor_package_iterator_destroy(pi);
   182 }
   183 
   184 static int
   185 list_property_packages(const char *ref_name,
   186 		       const char *ref_version,
   187 		       enum razor_property_type ref_type)
   188 {
   189 	struct razor_set *set;
   190 	struct razor_property *property;
   191 	struct razor_property_iterator *pi;
   192 	const char *name, *version;
   193 	enum razor_property_type type;
   194 	enum razor_version_relation relation;
   195 
   196 	if (ref_name == NULL)
   197 		return 0;
   198 
   199 	set = razor_set_open(repo_filename);
   200 	if (set == NULL)
   201 		return 1;
   202 
   203 	pi = razor_property_iterator_create(set, NULL);
   204 	while (razor_property_iterator_next(pi, &property,
   205 					    &name, &relation, &version,
   206 					    &type)) {
   207 		if (strcmp(ref_name, name) != 0)
   208 			continue;
   209 		if (ref_version && relation == RAZOR_VERSION_EQUAL &&
   210 		    strcmp(ref_version, version) != 0)
   211 			continue;
   212 		if (ref_type != type)
   213 			continue;
   214 
   215 		list_packages_for_property(set, property);
   216 	}
   217 	razor_property_iterator_destroy(pi);
   218 
   219 	return 0;
   220 }
   221 
   222 static int
   223 command_what_requires(int argc, const char *argv[])
   224 {
   225 	return list_property_packages(argv[0], argv[1],
   226 				      RAZOR_PROPERTY_REQUIRES);
   227 }
   228 
   229 static int
   230 command_what_provides(int argc, const char *argv[])
   231 {
   232 	return list_property_packages(argv[0], argv[1],
   233 				      RAZOR_PROPERTY_PROVIDES);
   234 }
   235 
   236 static int
   237 show_progress(void *clientp,
   238 	      double dltotal, double dlnow, double ultotal, double ulnow)
   239 {
   240 	const char *file = clientp;
   241 
   242 	if (!dlnow < dltotal)
   243 		fprintf(stderr, "\rdownloading %s, %dkB/%dkB",
   244 			file, (int) dlnow / 1024, (int) dltotal / 1024);
   245 
   246 	return 0;
   247 }
   248 
   249 static int
   250 download_if_missing(const char *url, const char *file)
   251 {
   252 	CURL *curl;
   253 	struct stat buf;
   254 	char error[256];
   255 	FILE *fp;
   256 	CURLcode res;
   257 	long response;
   258 
   259 	curl = curl_easy_init();
   260 	if (curl == NULL)
   261 		return 1;
   262 
   263 	curl_easy_setopt(curl, CURLOPT_ERRORBUFFER, error);
   264 	curl_easy_setopt(curl, CURLOPT_NOPROGRESS, 0);
   265 	curl_easy_setopt(curl, CURLOPT_PROGRESSFUNCTION, show_progress);
   266 	curl_easy_setopt(curl, CURLOPT_PROGRESSDATA, file);
   267 
   268 	if (stat(file, &buf) < 0) {
   269 		fp = fopen(file, "w");
   270 		if (fp == NULL) {
   271 			fprintf(stderr,
   272 				"failed to open %s for writing\n", file);
   273 			return -1;
   274 		}
   275 		curl_easy_setopt(curl, CURLOPT_WRITEDATA, fp);
   276 		curl_easy_setopt(curl, CURLOPT_URL, url);
   277 		res = curl_easy_perform(curl);
   278 		fclose(fp);
   279 		if (res != CURLE_OK) {
   280 			fprintf(stderr, "curl error: %s\n", error);
   281 			unlink(file);
   282 			return -1;
   283 		}
   284 		res = curl_easy_getinfo(curl,
   285 					CURLINFO_RESPONSE_CODE, &response);
   286 		if (res != CURLE_OK) {
   287 			fprintf(stderr, "curl error: %s\n", error);
   288                         unlink(file);
   289                         return -1;
   290 		}
   291 		if (response != 200) {
   292 			fprintf(stderr, " - failed %ld\n", response);
   293                         unlink(file);
   294                         return -1;
   295 		}
   296 		fprintf(stderr, "\n");
   297 	}
   298 
   299 	curl_easy_cleanup(curl);
   300 
   301 	return 0;
   302 }
   303 
   304 #define REPO_URL "http://download.fedora.redhat.com" \
   305 	"/pub/fedora/linux/development/i386/os"
   306 
   307 static int
   308 command_import_yum(int argc, const char *argv[])
   309 {
   310 	struct razor_set *set;
   311 
   312 	if (download_if_missing(REPO_URL "/repodata/primary.xml.gz",
   313 				"primary.xml.gz") < 0)
   314 		return -1;
   315 	if (download_if_missing(REPO_URL "/repodata/filelists.xml.gz",
   316 				"filelists.xml.gz") < 0)
   317 		return -1;
   318 
   319 	set = razor_set_create_from_yum();
   320 	if (set == NULL)
   321 		return 1;
   322 	razor_set_write(set, rawhide_repo_filename);
   323 	razor_set_destroy(set);
   324 	printf("wrote %s\n", rawhide_repo_filename);
   325 
   326 	return 0;
   327 }
   328 
   329 static int
   330 command_import_rpmdb(int argc, const char *argv[])
   331 {
   332 	struct razor_set *set;
   333 
   334 	set = razor_set_create_from_rpmdb();
   335 	if (set == NULL)
   336 		return 1;
   337 	razor_set_write(set, repo_filename);
   338 	razor_set_destroy(set);
   339 	printf("wrote %s\n", repo_filename);
   340 
   341 	return 0;
   342 }
   343 
   344 static int
   345 command_validate(int argc, const char *argv[])
   346 {
   347 	struct razor_set *set;
   348 
   349 	set = razor_set_open(repo_filename);
   350 	if (set == NULL)
   351 		return 1;
   352 	razor_set_list_unsatisfied(set);
   353 	razor_set_destroy(set);
   354 
   355 	return 0;
   356 }
   357 
   358 static int
   359 mark_packages_for_update(struct razor_transaction *trans,
   360 			 struct razor_set *set, const char *pattern)
   361 {
   362 	struct razor_package_iterator *pi;
   363 	struct razor_package *package;
   364 	const char *name, *version, *arch;
   365 	int matches = 0;
   366 
   367 	pi = razor_package_iterator_create(set);
   368 	while (razor_package_iterator_next(pi, &package,
   369 					   &name, &version, &arch)) {
   370 		if (pattern && fnmatch(pattern, name, 0) == 0) {
   371 			razor_transaction_install_package(trans, package);
   372 			matches++;
   373 		}
   374 	}
   375 	razor_package_iterator_destroy(pi);
   376 
   377 	return matches;
   378 }
   379 
   380 static int
   381 mark_packages_for_removal(struct razor_transaction *trans,
   382 			  struct razor_set *set, const char *pattern)
   383 {
   384 	struct razor_package_iterator *pi;
   385 	struct razor_package *package;
   386 	const char *name, *version, *arch;
   387 	int matches = 0;
   388 
   389 	pi = razor_package_iterator_create(set);
   390 	while (razor_package_iterator_next(pi, &package,
   391 					   &name, &version, &arch)) {
   392 		if (pattern && fnmatch(pattern, name, 0) == 0) {
   393 			razor_transaction_remove_package(trans, package);
   394 			matches++;
   395 		}
   396 	}
   397 	razor_package_iterator_destroy(pi);
   398 
   399 	return matches;
   400 }
   401 
   402 static int
   403 command_update(int argc, const char *argv[])
   404 {
   405 	struct razor_set *set, *upstream;
   406 	struct razor_transaction *trans;
   407 	int i, errors;
   408 
   409 	set = razor_set_open(repo_filename);
   410 	upstream = razor_set_open(rawhide_repo_filename);
   411 	if (set == NULL || upstream == NULL)
   412 		return 1;
   413 
   414 	trans = razor_transaction_create(set, upstream);
   415 	if (argc == 0)
   416 		razor_transaction_update_all(trans);
   417 	for (i = 0; i < argc; i++) {
   418 		if (mark_packages_for_update(trans, upstream, argv[i]) == 0) {
   419 			fprintf(stderr, "no match for %s\n", argv[i]);
   420 			return 1;
   421 		}
   422 	}
   423 		
   424 	errors = razor_transaction_resolve(trans);
   425 	if (errors)
   426 		return 1;
   427 
   428 	set = razor_transaction_finish(trans);
   429 	razor_set_write(set, updated_repo_filename);
   430 	razor_set_destroy(set);
   431 	razor_set_destroy(upstream);
   432 	printf("wrote system-updated.repo\n");
   433 
   434 	return 0;
   435 }
   436 
   437 static int
   438 command_remove(int argc, const char *argv[])
   439 {
   440 	struct razor_set *set;
   441 	struct razor_transaction *trans;
   442 	int i, errors;
   443 
   444 	set = razor_set_open(repo_filename);
   445 	if (set == NULL)
   446 		return 1;
   447 
   448 	trans = razor_transaction_create(set, NULL);
   449 	for (i = 0; i < argc; i++) {
   450 		if (mark_packages_for_removal(trans, set, argv[i]) == 0) {
   451 			fprintf(stderr, "no match for %s\n", argv[i]);
   452 			return 1;
   453 		}
   454 	}
   455 
   456 	errors = razor_transaction_resolve(trans);
   457 	if (errors)
   458 		return 1;
   459 
   460 	set = razor_transaction_finish(trans);
   461 	razor_set_write(set, updated_repo_filename);
   462 	razor_set_destroy(set);
   463 	printf("wrote system-updated.repo\n");
   464 
   465 	return 0;
   466 }
   467 
   468 static void
   469 print_diff(const char *name,
   470 	   const char *old_version, const char *new_version, const char *arch,
   471 	   void *data)
   472 {
   473 	if (old_version)
   474 		printf("removing %s %s\n", name, old_version);
   475 	else
   476 		printf("install %s %s\n", name, new_version);
   477 }
   478 
   479 static int
   480 command_diff(int argc, const char *argv[])
   481 {
   482 	struct razor_set *set, *updated;
   483 
   484 	set = razor_set_open(repo_filename);
   485 	updated = razor_set_open(updated_repo_filename);
   486 	if (set == NULL || updated == NULL)
   487 		return 1;
   488 
   489 	razor_set_diff(set, updated, print_diff, NULL);	
   490 
   491 	razor_set_destroy(set);
   492 	razor_set_destroy(updated);
   493 
   494 	return 0;
   495 }
   496 
   497 static int
   498 command_import_rpms(int argc, const char *argv[])
   499 {
   500 	DIR *dir;
   501 	struct dirent *de;
   502 	struct razor_importer *importer;
   503 	struct razor_set *set;
   504 	struct razor_rpm *rpm;
   505 	int len;
   506 	char filename[256];
   507 	const char *dirname = argv[0];
   508 
   509 	if (dirname == NULL) {
   510 		fprintf(stderr, "usage: razor import-rpms DIR\n");
   511 		return -1;
   512 	}
   513 
   514 	dir = opendir(dirname);
   515 	if (dir == NULL) {
   516 		fprintf(stderr, "couldn't read dir %s\n", dirname);
   517 		return -1;
   518 	}
   519 
   520 	importer = razor_importer_new();
   521 
   522 	while (de = readdir(dir), de != NULL) {
   523 		len = strlen(de->d_name);
   524 		if (len < 5 || strcmp(de->d_name + len - 4, ".rpm") != 0)
   525 		    continue;
   526 		snprintf(filename, sizeof filename,
   527 			 "%s/%s", dirname, de->d_name);
   528 		rpm = razor_rpm_open(filename);
   529 		if (rpm == NULL) {
   530 			fprintf(stderr,
   531 				"failed to open rpm \"%s\"\n", filename);
   532 			continue;
   533 		}
   534 		if (razor_importer_add_rpm(importer, rpm)) {
   535 			fprintf(stderr, "couldn't import %s\n", filename);
   536 			break;
   537 		}
   538 		razor_rpm_close(rpm);
   539 	}
   540 
   541 	if (de != NULL) {
   542 		razor_importer_destroy(importer);
   543 		return -1;
   544 	}
   545 
   546 	set = razor_importer_finish(importer);
   547 
   548 	razor_set_write(set, repo_filename);
   549 	razor_set_destroy(set);
   550 	printf("wrote %s\n", repo_filename);
   551 
   552 	return 0;
   553 }
   554 
   555 static void
   556 download_package(const char *name,
   557 		 const char *old_version,
   558 		 const char *new_version,
   559 		 const char *arch,
   560 		 void *data)
   561 {
   562 	char file[PATH_MAX], url[256];
   563 	const char *v;
   564 	int *errors = data;
   565 
   566 	if (old_version)
   567 		return;
   568 
   569 	/* Skip epoch */
   570 	v = strchr(new_version, ':');
   571 	if (v != NULL)
   572 		v = v + 1;
   573 	else
   574 		v = new_version;
   575 
   576 	snprintf(url, sizeof url,
   577 		 REPO_URL "/Packages/%s-%s.%s.rpm", name, v, arch);
   578 	snprintf(file, sizeof file,
   579 		 "rpms/%s-%s.%s.rpm", name, v, arch);
   580 	if (download_if_missing(url, file) < 0)
   581 		(*errors)++;
   582 }
   583 
   584 static void
   585 install_package(const char *name,
   586 		const char *old_version,
   587 		const char *new_version,
   588 		const char *arch,
   589 		void *data)
   590 {
   591 	const char *v, *root = data;
   592 	char file[PATH_MAX];
   593 	struct razor_rpm *rpm;
   594 
   595 	if (old_version) {
   596 		printf("removing %s %s not handled\n", name, old_version);
   597 		return;
   598 	}
   599 
   600 	/* Skip epoch */
   601 	v = strchr(new_version, ':');
   602 	if (v != NULL)
   603 		v = v + 1;
   604 	else
   605 		v = new_version;
   606 
   607 	printf("install %s %s\n", name, v);
   608 	snprintf(file, sizeof file, "rpms/%s-%s.%s.rpm", name, v, arch);
   609 
   610  	rpm = razor_rpm_open(file);
   611 	if (rpm == NULL) {
   612 		fprintf(stderr, "failed to open rpm %s\n", file);
   613 		return;
   614 	}
   615 	if (razor_rpm_install(rpm, root) < 0) {
   616 		fprintf(stderr,
   617 			"failed to install rpm %s\n", file);
   618 		return;
   619 	}
   620 	razor_rpm_close(rpm);
   621 }
   622 
   623 static int
   624 command_install(int argc, const char *argv[])
   625 {
   626 	struct razor_set *system, *upstream, *next;
   627 	struct razor_transaction *trans;
   628 	char path[PATH_MAX], new_path[PATH_MAX];
   629 	int i = 0, errors, fd, dependencies = 1;
   630 
   631 	if (i < argc && strcmp(argv[i], "--no-dependencies") == 0) {
   632 		dependencies = 0;
   633 		i++;
   634 	}
   635 
   636 	/* Create the new next repo file up front to ensure exclusive
   637 	 * access. */
   638 	snprintf(new_path, sizeof new_path,
   639 		 "%s%s/%s", root, razor_root_path, next_repo_filename);
   640 	fd = open(new_path, O_CREAT | O_WRONLY | O_TRUNC | O_EXCL, 0666);
   641 	if (fd < 0) {
   642 		fprintf(stderr, "failed to get lock file, "
   643 			"maybe previous operation crashed?\n");
   644 
   645 		/* FIXME: Use fcntl advisory locking to figure out
   646 		 * whether previous operation crashed or is still in
   647 		 * progress. */
   648 
   649 		return -1;
   650 	}
   651 
   652 	upstream = razor_set_open(rawhide_repo_filename);
   653 	snprintf(path, sizeof path,
   654 		 "%s%s/%s", root, razor_root_path, system_repo_filename);
   655 	system = razor_set_open(path);
   656 	if (system == NULL || upstream == NULL) {
   657 		unlink(new_path);
   658 		return 1;
   659 	}
   660 	trans = razor_transaction_create(system, upstream);
   661 	for (; i < argc; i++) {
   662 		if (mark_packages_for_update(trans, upstream, argv[i]) == 0) {
   663 			fprintf(stderr, "no package matched %s\n", argv[i]);
   664 			unlink(new_path);
   665 			return 1;
   666 		}
   667 	}
   668 
   669 	if (dependencies) {
   670 		errors = razor_transaction_resolve(trans);
   671 		if (errors) {
   672 			unlink(new_path);
   673 			return 1;
   674 		}
   675 	}
   676 
   677 	next = razor_transaction_finish(trans);
   678 
   679 	razor_set_write_to_fd(next, fd);
   680 	printf("wrote %s\n", new_path);
   681 
   682 	if (mkdir("rpms", 0777) && errno != EEXIST) {
   683 		fprintf(stderr, "failed to create rpms directory.\n");
   684 		return 1;
   685 	}
   686 
   687 	razor_set_diff(system, next, download_package, &errors);
   688 	if (errors > 0) {
   689 		fprintf(stderr, "failed to download %d packages\n", errors);
   690 		unlink(new_path);
   691                 return 1;
   692         }
   693 
   694 	/* FIXME: We need to figure out the right install order here,
   695 	 * so the post and pre scripts can run. */
   696 	razor_set_diff(system, next, install_package, (void *) root);
   697 
   698 	razor_set_destroy(next);
   699 	razor_set_destroy(system);
   700 	razor_set_destroy(upstream);
   701 
   702 	/* Make it so. */
   703 	rename(new_path, path);
   704 	printf("renamed %s to %s\n", new_path, path);
   705 
   706 	return 0;
   707 }
   708 
   709 static int
   710 command_init(int argc, const char *argv[])
   711 {
   712 	struct stat buf;
   713 	struct razor_set *set;
   714 	char path[PATH_MAX];
   715 
   716 	if (stat(root, &buf) < 0) {
   717 		if (mkdir(root, 0777) < 0) {
   718 			fprintf(stderr,
   719 				"could not create install root \"%s\"\n",
   720 				root);
   721 			return -1;
   722 		}
   723 		fprintf(stderr, "created install root \"%s\"\n", root);
   724 	} else if (!S_ISDIR(buf.st_mode)) {
   725 		fprintf(stderr,
   726 			"install root \"%s\" exists, but is not a directory\n",
   727 			root);
   728 		return -1;
   729 	}
   730 
   731 	snprintf(path, sizeof path, "%s/%s",
   732 		 razor_root_path, system_repo_filename);
   733 	if (razor_create_dir(root, path) < 0) {
   734 		fprintf(stderr, "could not create %s%s\n",
   735 			root, razor_root_path);
   736 		return -1;
   737 	}
   738 
   739 	set = razor_set_create();
   740 	snprintf(path, sizeof path, "%s%s/%s",
   741 		 root, razor_root_path, system_repo_filename);
   742 	if (razor_set_write(set, path) < 0) {
   743 		fprintf(stderr, "could not write initial package set\n");
   744 		return -1;
   745 	}
   746 	razor_set_destroy(set);
   747 
   748 	return 0;
   749 }
   750 
   751 static int
   752 command_download(int argc, const char *argv[])
   753 {
   754 	struct razor_set *set;
   755 	struct razor_package_iterator *pi;
   756 	struct razor_package *package;
   757 	const char *pattern = argv[0], *name, *version, *arch;
   758 	char url[256], file[256];
   759 	int matches = 0;
   760 
   761 	if (mkdir("rpms", 0777) && errno != EEXIST) {
   762 		fprintf(stderr, "failed to create rpms directory.\n");
   763 		return 1;
   764 	}
   765 
   766 	set = razor_set_open(rawhide_repo_filename);
   767 	pi = razor_package_iterator_create(set);
   768 	while (razor_package_iterator_next(pi, &package,
   769 					   &name, &version, &arch)) {
   770 		if (pattern && fnmatch(pattern, name, 0) != 0)
   771 			continue;
   772 
   773 		matches++;
   774 		snprintf(url, sizeof url,
   775 			 REPO_URL "/Packages/%s-%s.%s.rpm",
   776 			 name, version, arch);
   777 		snprintf(file, sizeof file,
   778 			 "rpms/%s-%s.%s.rpm", name, version, arch);
   779 		download_if_missing(url, file);
   780 	}
   781 	razor_package_iterator_destroy(pi);
   782 	razor_set_destroy(set);
   783 
   784 	if (matches == 0)
   785 		fprintf(stderr, "no packages matched \"%s\"\n", pattern);
   786 	else if (matches == 1)
   787 		fprintf(stderr, "downloaded 1 package\n");
   788 	else
   789 		fprintf(stderr, "downloaded %d packages\n", matches);
   790 
   791 	return 0;
   792 }
   793 
   794 static struct {
   795 	const char *name;
   796 	const char *description;
   797 	int (*func)(int argc, const char *argv[]);
   798 } razor_commands[] = {
   799 	{ "list", "list all packages", command_list },
   800 	{ "list-requires", "list all requires for the given package", command_list_requires },
   801 	{ "list-provides", "list all provides for the given package", command_list_provides },
   802 	{ "list-obsoletes", "list all obsoletes for the given package", command_list_obsoletes },
   803 	{ "list-conflicts", "list all conflicts for the given package", command_list_conflicts },
   804 	{ "list-files", "list files for package set", command_list_files },
   805 	{ "list-file-packages", "list packages owning file", command_list_file_packages },
   806 	{ "list-package-files", "list files in package", command_list_package_files },
   807 	{ "what-requires", "list the packages that have the given requires", command_what_requires },
   808 	{ "what-provides", "list the packages that have the given provides", command_what_provides },
   809 	{ "import-yum", "import yum metadata files", command_import_yum },
   810 	{ "import-rpmdb", "import the system rpm database", command_import_rpmdb },
   811 	{ "import-rpms", "import rpms from the given directory", command_import_rpms },
   812 	{ "validate", "validate a package set", command_validate },
   813 	{ "update", "update all or specified packages", command_update },
   814 	{ "remove", "remove specified packages", command_remove },
   815 	{ "diff", "show diff between two package sets", command_diff },
   816 	{ "install", "install rpm", command_install },
   817 	{ "init", "init razor root", command_init },
   818 	{ "download", "download packages", command_download }
   819 };
   820 
   821 static int
   822 usage(void)
   823 {
   824 	int i;
   825 
   826 	printf("usage:\n");
   827 	for (i = 0; i < ARRAY_SIZE(razor_commands); i++)
   828 		printf("  %-20s%s\n",
   829 		       razor_commands[i].name, razor_commands[i].description);
   830 
   831 	return 1;
   832 }
   833 
   834 int
   835 main(int argc, const char *argv[])
   836 {
   837 	char *repo;
   838 	int i;
   839 
   840 	repo = getenv("RAZOR_REPO");
   841 	if (repo != NULL)
   842 		repo_filename = repo;
   843 
   844 	if (argc < 2)
   845 		return usage();
   846 
   847 	for (i = 0; i < ARRAY_SIZE(razor_commands); i++)
   848 		if (strcmp(razor_commands[i].name, argv[1]) == 0)
   849 			return razor_commands[i].func(argc - 2, argv + 2);
   850 
   851 	return usage();
   852 }