import.c
author Kristian H?gsberg <krh@redhat.com>
Wed Sep 19 14:09:03 2007 -0400 (2007-09-19)
changeset 28 c8958f67afd8
parent 27 5dbd81809d26
child 30 702c01e59497
permissions -rw-r--r--
Add importer for system rpm database.
     1 #define _GNU_SOURCE
     2 
     3 #include <string.h>
     4 #include <stdio.h>
     5 #include <sys/stat.h>
     6 #include <sys/mman.h>
     7 #include <unistd.h>
     8 #include <fcntl.h>
     9 #include <errno.h>
    10 
    11 #include <expat.h>
    12 #include <rpm/rpmlib.h>
    13 #include <rpm/rpmdb.h>
    14 #include "sha1.h"
    15 #include "razor.h"
    16 
    17 static void
    18 parse_package(struct import_context *ctx, const char **atts, void *data)
    19 {
    20 	const char *name = NULL, *version = NULL;
    21 	int i;
    22 
    23 	for (i = 0; atts[i]; i += 2) {
    24 		if (strcmp(atts[i], "name") == 0)
    25 			name = atts[i + 1];
    26 		else if (strcmp(atts[i], "version") == 0)
    27 			version = atts[i + 1];
    28 	}
    29 
    30 	if (name == NULL || version == NULL) {
    31 		fprintf(stderr, "invalid package tag, "
    32 			"missing name or version attributes\n");
    33 		return;
    34 	}
    35 
    36 	import_context_add_package(ctx, name, version);
    37 }
    38 
    39 static void
    40 parse_property(struct import_context *ctx, const char **atts, void *data)
    41 {
    42 	const char *name = NULL, *version = NULL;
    43 	int i;
    44 
    45 	for (i = 0; atts[i]; i += 2) {
    46 		if (strcmp(atts[i], "name") == 0)
    47 			name = atts[i + 1];
    48 		if (strcmp(atts[i], "version") == 0)
    49 			version = atts[i + 1];
    50 	}
    51 	
    52 	if (name == NULL) {
    53 		fprintf(stderr, "invalid tag, missing name attribute\n");
    54 		return;
    55 	}
    56 
    57 	import_context_add_property(ctx, data, name, version);
    58 }
    59 
    60 static void
    61 start_element(void *data, const char *name, const char **atts)
    62 {
    63 	struct import_context *ctx = data;
    64 
    65 	if (strcmp(name, "package") == 0)
    66 		parse_package(ctx, atts, NULL);
    67 	else if (strcmp(name, "requires") == 0)
    68 		parse_property(ctx, atts, &ctx->requires);
    69 	else if (strcmp(name, "provides") == 0)
    70 		parse_property(ctx, atts, &ctx->provides);
    71 }
    72 
    73 static void
    74 end_element (void *data, const char *name)
    75 {
    76 	struct import_context *ctx = data;
    77 
    78 	if (strcmp(name, "package") == 0)
    79 		import_context_finish_package(ctx);
    80 }
    81 
    82 static int
    83 import_rzr_file(struct import_context *ctx, const char *filename)
    84 {
    85 	SHA_CTX sha1;
    86 	XML_Parser parser;
    87 	int fd;
    88 	void *p;
    89 	struct stat stat;
    90 	unsigned char hash[20];
    91 
    92 	fd = open(filename, O_RDONLY);
    93 	if (fstat(fd, &stat) < 0)
    94 		return -1;
    95 	p = mmap(NULL, stat.st_size, PROT_READ, MAP_PRIVATE, fd, 0);
    96 	if (p == MAP_FAILED)
    97 		return -1;
    98 
    99 	parser = XML_ParserCreate(NULL);
   100 	XML_SetUserData(parser, ctx);
   101 	XML_SetElementHandler(parser, start_element, end_element);
   102 	if (XML_Parse(parser, p, stat.st_size, 1) == XML_STATUS_ERROR) {
   103 		fprintf(stderr,
   104 			"%s at line %d, %s\n",
   105 			XML_ErrorString(XML_GetErrorCode(parser)),
   106 			XML_GetCurrentLineNumber(parser),
   107 			filename);
   108 		return 1;
   109 	}
   110 
   111 	XML_ParserFree(parser);
   112 
   113 	SHA1_Init(&sha1);
   114 	SHA1_Update(&sha1, p, stat.st_size);
   115 	SHA1_Final(hash, &sha1);
   116 
   117 	close(fd);
   118 
   119 	munmap(p, stat.st_size);
   120 
   121 	return 0;
   122 }
   123 
   124 struct razor_set *
   125 razor_import_rzr_files(int count, const char *files[])
   126 {
   127 	struct import_context ctx;
   128 	int i;
   129 
   130 	razor_prepare_import(&ctx);
   131 
   132 	for (i = 0; i < count; i++) {
   133 		if (import_rzr_file(&ctx, files[i]) < 0) {
   134 			fprintf(stderr, "failed to import %s\n", files[i]);
   135 			exit(-1);
   136 		}
   137 	}
   138 
   139 	return razor_finish_import(&ctx);
   140 }
   141 
   142 /* Import a yum filelist as a razor package set. */
   143 
   144 enum {
   145 	YUM_STATE_BEGIN,
   146 	YUM_STATE_PACKAGE_NAME
   147 };
   148 
   149 struct yum_context {
   150 	struct import_context ctx;
   151 	struct import_property_context *current_property_context;
   152 	char *name;
   153 	int state;
   154 };
   155 
   156 static void
   157 yum_start_element(void *data, const char *name, const char **atts)
   158 {
   159 	struct yum_context *ctx = data;
   160 	const char *n, *version;
   161 	int i;
   162 
   163 	if (strcmp(name, "name") == 0) {
   164 		ctx->state = YUM_STATE_PACKAGE_NAME;
   165 	} else if (strcmp(name, "version") == 0) {
   166 		version = NULL;
   167 		for (i = 0; atts[i]; i += 2) {
   168 			if (strcmp(atts[i], "ver") == 0)
   169 				version = atts[i + 1];
   170 		}
   171 		import_context_add_package(&ctx->ctx, ctx->name, version);
   172 	} else if (strcmp(name, "rpm:requires") == 0) {
   173 		ctx->current_property_context = &ctx->ctx.requires;
   174 	} else if (strcmp(name, "rpm:provides") == 0) {
   175 		ctx->current_property_context = &ctx->ctx.provides;
   176 	} else if (strcmp(name, "rpm:entry") == 0 &&
   177 		   ctx->current_property_context != NULL) {
   178 		n = NULL;
   179 		version = NULL;
   180 		for (i = 0; atts[i]; i += 2) {
   181 			if (strcmp(atts[i], "name") == 0)
   182 				n = atts[i + 1];
   183 			else if (strcmp(atts[i], "ver") == 0)
   184 				version = atts[i + 1];
   185 		}
   186 
   187 		if (n == NULL) {
   188 			fprintf(stderr, "invalid rpm:entry, "
   189 				"missing name or version attributes\n");
   190 			return;
   191 		}
   192 
   193 		import_context_add_property(&ctx->ctx,
   194 					    ctx->current_property_context,
   195 					    n, version);
   196 	}
   197 }
   198 
   199 static void
   200 yum_end_element (void *data, const char *name)
   201 {
   202 	struct yum_context *ctx = data;
   203 
   204 	if (strcmp(name, "package") == 0) {
   205 		free(ctx->name);
   206 		import_context_finish_package(&ctx->ctx);
   207 	} else if (strcmp(name, "name") == 0) {
   208 		ctx->state = 0;
   209 	} else if (strcmp(name, "rpm:requires") == 0) {
   210 		ctx->current_property_context = NULL;
   211 	} else if (strcmp(name, "rpm:provides") == 0) {
   212 		ctx->current_property_context = NULL;
   213 	}
   214 }
   215 
   216 static void
   217 yum_character_data (void *data, const XML_Char *s, int len)
   218 {
   219 	struct yum_context *ctx = data;
   220 
   221 	if (ctx->state == YUM_STATE_PACKAGE_NAME)
   222 		ctx->name = strndup(s, len);
   223 }
   224 
   225 struct razor_set *
   226 razor_set_create_from_yum_filelist(int fd)
   227 {
   228 	struct yum_context ctx;
   229 	XML_Parser parser;
   230 	char buf[4096];
   231 	int len;
   232 
   233 	razor_prepare_import(&ctx.ctx);
   234 
   235 	parser = XML_ParserCreate(NULL);
   236 	XML_SetUserData(parser, &ctx);
   237 	XML_SetElementHandler(parser, yum_start_element, yum_end_element);
   238 	XML_SetCharacterDataHandler(parser, yum_character_data);
   239 
   240 	while (1) {
   241 		len = read(fd, buf, sizeof buf);
   242 		if (len < 0) {
   243 			fprintf(stderr,
   244 				"couldn't read input: %s\n", strerror(errno));
   245 			return NULL;
   246 		} else if (len == 0)
   247 			break;
   248 
   249 		if (XML_Parse(parser, buf, len, 0) == XML_STATUS_ERROR) {
   250 			fprintf(stderr,
   251 				"%s at line %d\n",
   252 				XML_ErrorString(XML_GetErrorCode(parser)),
   253 				XML_GetCurrentLineNumber(parser));
   254 			return NULL;
   255 		}
   256 	}
   257 
   258 	XML_ParserFree(parser);
   259 
   260 	return razor_finish_import(&ctx.ctx);
   261 }
   262 
   263 struct razor_set *
   264 razor_set_create_from_rpmdb(void)
   265 {
   266 	struct import_context ctx;
   267 	rpmdbMatchIterator iter;
   268 	Header h;
   269 	int_32 type, count, i;
   270 	char *name, *version, *release;
   271 	char **properties, **property_versions;
   272 	rpmdb db;
   273 
   274 	rpmReadConfigFiles(NULL, NULL);
   275 
   276 	if (rpmdbOpen("", &db, O_RDONLY, 0644) != 0) {
   277 		fprintf(stderr, "cannot open rpm database\n");
   278 		exit(1);
   279 	}
   280 
   281 	razor_prepare_import(&ctx);
   282 
   283 	iter = rpmdbInitIterator(db, 0, NULL, 0);
   284 	while (h = rpmdbNextIterator(iter), h != NULL) {
   285 		headerGetEntry(h, RPMTAG_NAME, &type,
   286 			       (void **) &name, &count);
   287 		headerGetEntry(h, RPMTAG_VERSION, &type,
   288 			       (void **) &version, &count);
   289 		headerGetEntry(h, RPMTAG_RELEASE, &type,
   290 			       (void **) &release, &count);
   291 		import_context_add_package(&ctx, name, version);
   292 
   293 
   294 		headerGetEntry(h, RPMTAG_REQUIRES, &type,
   295 			       (void **) &properties, &count);
   296 		headerGetEntry(h, RPMTAG_REQUIREVERSION, &type,
   297 			       (void **) &property_versions, &count);
   298 		for (i = 0; i < count; i++)
   299 			import_context_add_property(&ctx,
   300 						    &ctx.requires,
   301 						    properties[i],
   302 						    property_versions[i]);
   303 
   304 		headerGetEntry(h, RPMTAG_PROVIDES, &type,
   305 			       (void **) &properties, &count);
   306 		headerGetEntry(h, RPMTAG_PROVIDEVERSION, &type,
   307 			       (void **) &property_versions, &count);
   308 		for (i = 0; i < count; i++)
   309 			import_context_add_property(&ctx,
   310 						    &ctx.provides,
   311 						    properties[i],
   312 						    property_versions[i]);
   313 
   314 		import_context_finish_package(&ctx);
   315 	}
   316 
   317 	rpmdbClose(db);
   318 
   319 	return razor_finish_import(&ctx);
   320 }