src/main.c
author Kristian H?gsberg <krh@redhat.com>
Fri Jun 20 23:13:09 2008 -0400 (2008-06-20)
changeset 257 0c3db660514d
parent 254 ccb1c11968ab
child 259 5b0601d184ed
permissions -rw-r--r--
When uniquifying properties, also sort them on the owning package.

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