main.c
author Dan Winship <danw@gnome.org>
Fri Feb 29 15:09:44 2008 -0500 (2008-02-29)
changeset 139 a416240614e3
parent 129 d221757574c1
child 151 ae6ceb604f54
permissions -rw-r--r--
add somewhat inefficient file dep removal code

(fwiw, the comment on the previous commit was incorrect)
     1 #include <stdlib.h>
     2 #include <stddef.h>
     3 #include <stdio.h>
     4 #include <string.h>
     5 #include <sys/types.h>
     6 #include <sys/stat.h>
     7 #include <unistd.h>
     8 #include <dirent.h>
     9 #include <curl/curl.h>
    10 #include <fnmatch.h>
    11 #include "razor.h"
    12 
    13 static const char *repo_filename = "system.repo";
    14 static const char *rawhide_repo_filename = "rawhide.repo";
    15 static const char *updated_repo_filename = "system-updated.repo";
    16 
    17 static int
    18 command_list(int argc, const char *argv[])
    19 {
    20 	struct razor_set *set;
    21 	struct razor_package_iterator *pi;
    22 	struct razor_package *package;
    23 	const char *pattern = argv[0], *name, *version;
    24 
    25 	set = razor_set_open(repo_filename);
    26 	pi = razor_package_iterator_create(set);
    27 	while (razor_package_iterator_next(pi, &package, &name, &version)) {
    28 		if (pattern && fnmatch(pattern, name, 0) != 0)
    29 			continue;
    30 
    31 		printf("%s-%s\n", name, version);
    32 	}
    33 	razor_package_iterator_destroy(pi);
    34 	razor_set_destroy(set);
    35 
    36 	return 0;
    37 }
    38 
    39 static int
    40 list_properties(const char *package_name,
    41 		enum razor_property_type required_type)
    42 {
    43 	struct razor_set *set;
    44 	struct razor_property *property;
    45 	struct razor_package *package;
    46 	struct razor_property_iterator *pi;
    47 	const char *name, *version;
    48 	enum razor_property_type type;
    49 	enum razor_version_relation relation;
    50 
    51 	set = razor_set_open(repo_filename);
    52 	if (package_name)
    53 		package = razor_set_get_package(set, package_name);
    54 	else
    55 		package = NULL;
    56 
    57 	pi = razor_property_iterator_create(set, package);
    58 	while (razor_property_iterator_next(pi, &property,
    59 					    &name, &relation, &version,
    60 					    &type)) {
    61 		if (type != required_type)
    62 			continue;
    63 		if (version[0] == '\0')
    64 			printf("%s\n", name);
    65 		else
    66 			printf("%s %s %s\n", name,
    67 			       razor_version_relations[relation], version);
    68 	}
    69 	razor_property_iterator_destroy(pi);
    70 
    71 	razor_set_destroy(set);
    72 
    73 	return 0;
    74 }
    75 
    76 static int
    77 command_list_requires(int argc, const char *argv[])
    78 {
    79 	return list_properties(argv[0], RAZOR_PROPERTY_REQUIRES);
    80 }
    81 
    82 static int
    83 command_list_provides(int argc, const char *argv[])
    84 {
    85 	return list_properties(argv[0], RAZOR_PROPERTY_PROVIDES);
    86 }
    87 
    88 static int
    89 command_list_obsoletes(int argc, const char *argv[])
    90 {
    91 	return list_properties(argv[0], RAZOR_PROPERTY_OBSOLETES);
    92 }
    93 
    94 static int
    95 command_list_conflicts(int argc, const char *argv[])
    96 {
    97 	return list_properties(argv[0], RAZOR_PROPERTY_CONFLICTS);
    98 }
    99 
   100 static int
   101 command_list_files(int argc, const char *argv[])
   102 {
   103 	struct razor_set *set;
   104 
   105 	set = razor_set_open(repo_filename);
   106 	if (set == NULL)
   107 		return 1;
   108 	razor_set_list_files(set, argv[0]);
   109 	razor_set_destroy(set);
   110 
   111 	return 0;
   112 }
   113 
   114 static int
   115 command_list_file_packages(int argc, const char *argv[])
   116 {
   117 	struct razor_set *set;
   118 	struct razor_package_iterator *pi;
   119 	struct razor_package *package;
   120 	const char *name, *version;
   121 
   122 	set = razor_set_open(repo_filename);
   123 	if (set == NULL)
   124 		return 1;
   125 
   126 	pi = razor_package_iterator_create_for_file(set, argv[0]);
   127 	while (razor_package_iterator_next(pi, &package, &name, &version))
   128 		printf("%s-%s\n", name, version);
   129 	razor_package_iterator_destroy(pi);
   130 
   131 	razor_set_destroy(set);
   132 
   133 	return 0;
   134 }
   135 
   136 static int
   137 command_list_package_files(int argc, const char *argv[])
   138 {
   139 	struct razor_set *set;
   140 
   141 	set = razor_set_open(repo_filename);
   142 	if (set == NULL)
   143 		return 1;
   144 	razor_set_list_package_files(set, argv[0]);
   145 	razor_set_destroy(set);
   146 
   147 	return 0;
   148 }
   149 
   150 static void
   151 list_packages_for_property(struct razor_set *set,
   152 			   struct razor_property *property)
   153 {
   154 	struct razor_package_iterator *pi;
   155 	struct razor_package *package;
   156 	const char *name, *version;
   157 
   158 	pi = razor_package_iterator_create_for_property(set, property);
   159 	while (razor_package_iterator_next(pi, &package, &name, &version))
   160 		printf("%s-%s\n", name, version);
   161 	razor_package_iterator_destroy(pi);
   162 }
   163 
   164 static int
   165 list_property_packages(const char *ref_name,
   166 		       const char *ref_version,
   167 		       enum razor_property_type ref_type)
   168 {
   169 	struct razor_set *set;
   170 	struct razor_property *property;
   171 	struct razor_property_iterator *pi;
   172 	const char *name, *version;
   173 	enum razor_property_type type;
   174 	enum razor_version_relation relation;
   175 
   176 	if (ref_name == NULL)
   177 		return 0;
   178 
   179 	set = razor_set_open(repo_filename);
   180 	if (set == NULL)
   181 		return 1;
   182 
   183 	pi = razor_property_iterator_create(set, NULL);
   184 	while (razor_property_iterator_next(pi, &property,
   185 					    &name, &relation, &version,
   186 					    &type)) {
   187 		if (strcmp(ref_name, name) != 0)
   188 			continue;
   189 		if (ref_version && relation == RAZOR_VERSION_EQUAL &&
   190 		    strcmp(ref_version, version) != 0)
   191 			continue;
   192 		if (ref_type != type)
   193 			continue;
   194 
   195 		list_packages_for_property(set, property);
   196 	}
   197 	razor_property_iterator_destroy(pi);
   198 
   199 	return 0;
   200 }
   201 
   202 static int
   203 command_what_requires(int argc, const char *argv[])
   204 {
   205 	return list_property_packages(argv[0], argv[1],
   206 				      RAZOR_PROPERTY_REQUIRES);
   207 }
   208 
   209 static int
   210 command_what_provides(int argc, const char *argv[])
   211 {
   212 	return list_property_packages(argv[0], argv[1],
   213 				      RAZOR_PROPERTY_PROVIDES);
   214 }
   215 
   216 static int
   217 show_progress(void *clientp,
   218 	      double dltotal, double dlnow, double ultotal, double ulnow)
   219 {
   220 	const char *file = clientp;
   221 
   222 	if (!dlnow < dltotal)
   223 		fprintf(stderr, "\rdownloading %s, %dkB/%dkB",
   224 			file, (int) dlnow / 1024, (int) dltotal / 1024);
   225 	else
   226 		fprintf(stderr, "\n");
   227 
   228 	return 0;
   229 }
   230 
   231 static int
   232 download_if_missing(CURL *curl, const char *url, const char *file)
   233 {
   234 	struct stat buf;
   235 	char error[256];
   236 	FILE *fp;
   237 	CURLcode res;
   238 	char buffer[256];
   239 
   240 	curl_easy_setopt(curl, CURLOPT_ERRORBUFFER, error);
   241 	curl_easy_setopt(curl, CURLOPT_NOPROGRESS, 0);
   242 	curl_easy_setopt(curl, CURLOPT_PROGRESSFUNCTION, show_progress);
   243 	curl_easy_setopt(curl, CURLOPT_PROGRESSDATA, file);
   244 
   245 	if (stat(file, &buf) < 0) {
   246 		fp = fopen(file, "w");
   247 		snprintf(buffer, sizeof buffer, "%s/%s", url, file);
   248 		curl_easy_setopt(curl, CURLOPT_WRITEDATA, fp);
   249 		curl_easy_setopt(curl, CURLOPT_URL, buffer);
   250 		res = curl_easy_perform(curl);
   251 		fclose(fp);
   252 		if (res != CURLE_OK) {
   253 			fprintf(stderr, "curl error: %s\n", error);
   254 			unlink(file);
   255 			return -1;
   256 		}
   257 	}
   258 
   259 	return 0;
   260 }
   261 
   262 #define REPO_URL "http://download.fedora.redhat.com" \
   263 	"/pub/fedora/linux/development/i386/os/repodata"
   264 
   265 static int
   266 command_import_yum(int argc, const char *argv[])
   267 {
   268 	struct razor_set *set;
   269 	CURL *curl;
   270 
   271 	curl = curl_easy_init();
   272 	if (curl == NULL)
   273 		return 1;
   274 
   275 	if (download_if_missing(curl, REPO_URL, "primary.xml.gz") < 0)
   276 		return -1;
   277 	if (download_if_missing(curl, REPO_URL, "filelists.xml.gz") < 0)
   278 		return -1;
   279 	curl_easy_cleanup(curl);
   280 
   281 	set = razor_set_create_from_yum();
   282 	if (set == NULL)
   283 		return 1;
   284 	razor_set_write(set, rawhide_repo_filename);
   285 	razor_set_destroy(set);
   286 	printf("wrote %s\n", rawhide_repo_filename);
   287 
   288 	return 0;
   289 }
   290 
   291 static int
   292 command_import_rpmdb(int argc, const char *argv[])
   293 {
   294 	struct razor_set *set;
   295 
   296 	set = razor_set_create_from_rpmdb();
   297 	if (set == NULL)
   298 		return 1;
   299 	razor_set_write(set, repo_filename);
   300 	razor_set_destroy(set);
   301 	printf("wrote %s\n", repo_filename);
   302 
   303 	return 0;
   304 }
   305 
   306 static int
   307 command_validate(int argc, const char *argv[])
   308 {
   309 	struct razor_set *set;
   310 
   311 	set = razor_set_open(repo_filename);
   312 	if (set == NULL)
   313 		return 1;
   314 	razor_set_list_unsatisfied(set);
   315 	razor_set_destroy(set);
   316 
   317 	return 0;
   318 }
   319 
   320 static int
   321 command_update(int argc, const char *argv[])
   322 {
   323 	struct razor_set *set, *upstream;
   324 	struct razor_transaction *trans;
   325 
   326 	set = razor_set_open(repo_filename);
   327 	upstream = razor_set_open(rawhide_repo_filename);
   328 	if (set == NULL || upstream == NULL)
   329 		return 1;
   330 	trans = razor_transaction_create(set, upstream, argc, argv, 0, NULL);
   331 	razor_transaction_describe(trans);
   332 	if (trans->errors)
   333 		return 1;
   334 
   335 	set = razor_transaction_run(trans);
   336 	razor_transaction_destroy(trans);
   337 	razor_set_write(set, updated_repo_filename);
   338 	razor_set_destroy(set);
   339 	razor_set_destroy(upstream);
   340 	printf("wrote system-updated.repo\n");
   341 
   342 	return 0;
   343 }
   344 
   345 static int
   346 command_remove(int argc, const char *argv[])
   347 {
   348 	struct razor_set *set;
   349 	struct razor_transaction *trans;
   350 
   351 	set = razor_set_open(repo_filename);
   352 	if (set == NULL)
   353 		return 1;
   354 	trans = razor_transaction_create(set, NULL, 0, NULL, argc, argv);
   355 	razor_transaction_describe(trans);
   356 	if (trans->errors)
   357 		return 1;
   358 
   359 	set = razor_transaction_run(trans);
   360 	razor_transaction_destroy(trans);
   361 	razor_set_write(set, updated_repo_filename);
   362 	razor_set_destroy(set);
   363 	printf("wrote system-updated.repo\n");
   364 
   365 	return 0;
   366 }
   367 
   368 static void
   369 print_diff(const char *name,
   370 	   const char *old_version, const char *new_version, void *data)
   371 {
   372 	if (old_version)
   373 		printf("removing %s %s\n", name, old_version);
   374 	else
   375 		printf("install %s %s\n", name, new_version);
   376 }
   377 
   378 static int
   379 command_diff(int argc, const char *argv[])
   380 {
   381 	struct razor_set *set, *updated;
   382 
   383 	set = razor_set_open(repo_filename);
   384 	updated = razor_set_open(updated_repo_filename);
   385 	if (set == NULL || updated == NULL)
   386 		return 1;
   387 
   388 	razor_set_diff(set, updated, print_diff, NULL);	
   389 
   390 	razor_set_destroy(set);
   391 	razor_set_destroy(updated);
   392 
   393 	return 0;
   394 }
   395 
   396 static int
   397 command_import_rpms(int argc, const char *argv[])
   398 {
   399 	DIR *dir;
   400 	struct dirent *de;
   401 	struct razor_importer *importer;
   402 	struct razor_set *set;
   403 	struct razor_rpm *rpm;
   404 	int len;
   405 	char filename[256];
   406 	const char *dirname = argv[0];
   407 
   408 	if (dirname == NULL) {
   409 		fprintf(stderr, "usage: razor import-rpms DIR\n");
   410 		return -1;
   411 	}
   412 
   413 	dir = opendir(dirname);
   414 	if (dir == NULL) {
   415 		fprintf(stderr, "couldn't read dir %s\n", dirname);
   416 		return -1;
   417 	}
   418 
   419 	importer = razor_importer_new();
   420 
   421 	while (de = readdir(dir), de != NULL) {
   422 		len = strlen(de->d_name);
   423 		if (len < 5 || strcmp(de->d_name + len - 4, ".rpm") != 0)
   424 		    continue;
   425 		snprintf(filename, sizeof filename,
   426 			 "%s/%s", dirname, de->d_name);
   427 		rpm = razor_rpm_open(filename);
   428 		if (rpm == NULL) {
   429 			fprintf(stderr,
   430 				"failed to open rpm \"%s\"\n", filename);
   431 			continue;
   432 		}
   433 		if (razor_importer_add_rpm(importer, rpm)) {
   434 			fprintf(stderr, "couldn't import %s\n", filename);
   435 			break;
   436 		}
   437 		razor_rpm_close(rpm);
   438 	}
   439 
   440 	if (de != NULL) {
   441 		razor_importer_destroy(importer);
   442 		return -1;
   443 	}
   444 
   445 	set = razor_importer_finish(importer);
   446 
   447 	razor_set_write(set, repo_filename);
   448 	razor_set_destroy(set);
   449 	printf("wrote %s\n", repo_filename);
   450 
   451 	return 0;
   452 }
   453 
   454 static int
   455 command_install(int argc, const char *argv[])
   456 {
   457 	struct razor_rpm *rpm;
   458 	const char *filename = argv[0];
   459 	struct stat buf;
   460 	const char root[] = "install";
   461 
   462 	if (stat(root, &buf) < 0) {
   463 		if (mkdir(root, 0777) < 0) {
   464 			fprintf(stderr,
   465 				"could not create install root \"%s\"\n",
   466 				root);
   467 			return -1;
   468 		}
   469 		fprintf(stderr, "created install root \"%s\"\n", root);
   470 	} else if (!S_ISDIR(buf.st_mode)) {
   471 		fprintf(stderr,
   472 			"install root \"%s\" exists, but is not a directory\n",
   473 			root);
   474 		return -1;
   475 	}
   476 
   477 	rpm = razor_rpm_open(filename);
   478 	if (rpm == NULL) {
   479 		fprintf(stderr, "failed to open rpm %s\n", filename);
   480 		return -1;
   481 	}
   482 	if (razor_rpm_install(rpm, root) < 0) {
   483 		fprintf(stderr, "failed to install rpm %s\n", filename);
   484 		return -1;
   485 	}
   486 	
   487 	razor_rpm_close(rpm);
   488 
   489 	return 0;
   490 }
   491 
   492 static struct {
   493 	const char *name;
   494 	const char *description;
   495 	int (*func)(int argc, const char *argv[]);
   496 } razor_commands[] = {
   497 	{ "list", "list all packages", command_list },
   498 	{ "list-requires", "list all requires for the given package", command_list_requires },
   499 	{ "list-provides", "list all provides for the given package", command_list_provides },
   500 	{ "list-obsoletes", "list all obsoletes for the given package", command_list_obsoletes },
   501 	{ "list-conflicts", "list all conflicts for the given package", command_list_conflicts },
   502 	{ "list-files", "list files for package set", command_list_files },
   503 	{ "list-file-packages", "list packages owning file", command_list_file_packages },
   504 	{ "list-package-files", "list files in package", command_list_package_files },
   505 	{ "what-requires", "list the packages that have the given requires", command_what_requires },
   506 	{ "what-provides", "list the packages that have the given provides", command_what_provides },
   507 	{ "import-yum", "import yum metadata files", command_import_yum },
   508 	{ "import-rpmdb", "import the system rpm database", command_import_rpmdb },
   509 	{ "import-rpms", "import rpms from the given directory", command_import_rpms },
   510 	{ "validate", "validate a package set", command_validate },
   511 	{ "update", "update all or specified packages", command_update },
   512 	{ "remove", "remove specified packages", command_remove },
   513 	{ "diff", "show diff between two package sets", command_diff },
   514 	{ "install", "install rpm", command_install }
   515 };
   516 
   517 static int
   518 usage(void)
   519 {
   520 	int i;
   521 
   522 	printf("usage:\n");
   523 	for (i = 0; i < ARRAY_SIZE(razor_commands); i++)
   524 		printf("  %-20s%s\n",
   525 		       razor_commands[i].name, razor_commands[i].description);
   526 
   527 	return 1;
   528 }
   529 
   530 int
   531 main(int argc, const char *argv[])
   532 {
   533 	char *repo;
   534 	int i;
   535 
   536 	repo = getenv("RAZOR_REPO");
   537 	if (repo != NULL)
   538 		repo_filename = repo;
   539 
   540 	if (argc < 2)
   541 		return usage();
   542 
   543 	for (i = 0; i < ARRAY_SIZE(razor_commands); i++)
   544 		if (strcmp(razor_commands[i].name, argv[1]) == 0)
   545 			return razor_commands[i].func(argc - 2, argv + 2);
   546 
   547 	return usage();
   548 }