import.c
author Kristian H?gsberg <krh@redhat.com>
Sun Nov 04 00:58:57 2007 -0400 (2007-11-04)
changeset 69 35ca1ba469ec
parent 67 cfe57117efee
child 70 e94d16f789e5
permissions -rw-r--r--
Set the property type when merging package sets.
     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 razor_importer *importer, 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 	razor_importer_begin_package(importer, name, version);
    37 }
    38 
    39 enum {
    40 	RZR_REQUIRES, RZR_PROVIDES
    41 };
    42 
    43 static void
    44 parse_property(struct razor_importer *importer, const char **atts, void *data)
    45 {
    46 	const char *name = NULL, *version = NULL;
    47 	int i;
    48 
    49 	for (i = 0; atts[i]; i += 2) {
    50 		if (strcmp(atts[i], "name") == 0)
    51 			name = atts[i + 1];
    52 		if (strcmp(atts[i], "version") == 0)
    53 			version = atts[i + 1];
    54 	}
    55 	
    56 	if (name == NULL) {
    57 		fprintf(stderr, "invalid tag, missing name attribute\n");
    58 		return;
    59 	}
    60 
    61 	switch ((int) data) {
    62 	case RZR_REQUIRES:
    63 		razor_importer_add_property(importer, name, version,
    64 					    RAZOR_PROPERTY_REQUIRES);
    65 		break;
    66 	case RZR_PROVIDES:
    67 		razor_importer_add_property(importer, name, version,
    68 					    RAZOR_PROPERTY_PROVIDES);
    69 		break;
    70 	}
    71 }
    72 
    73 static void
    74 start_element(void *data, const char *name, const char **atts)
    75 {
    76 	struct razor_importer *importer = data;
    77 
    78 	if (strcmp(name, "package") == 0)
    79 		parse_package(importer, atts, NULL);
    80 	else if (strcmp(name, "requires") == 0)
    81 		parse_property(importer, atts, (void *) RZR_REQUIRES);
    82 	else if (strcmp(name, "provides") == 0)
    83 		parse_property(importer, atts, (void*) RZR_PROVIDES);
    84 }
    85 
    86 static void
    87 end_element (void *data, const char *name)
    88 {
    89 	struct razor_importer *importer = data;
    90 
    91 	if (strcmp(name, "package") == 0)
    92 		razor_importer_finish_package(importer);
    93 }
    94 
    95 static int
    96 import_rzr_file(struct razor_importer *importer, const char *filename)
    97 {
    98 	SHA_CTX sha1;
    99 	XML_Parser parser;
   100 	int fd;
   101 	void *p;
   102 	struct stat stat;
   103 	unsigned char hash[20];
   104 
   105 	fd = open(filename, O_RDONLY);
   106 	if (fstat(fd, &stat) < 0)
   107 		return -1;
   108 	p = mmap(NULL, stat.st_size, PROT_READ, MAP_PRIVATE, fd, 0);
   109 	if (p == MAP_FAILED)
   110 		return -1;
   111 
   112 	parser = XML_ParserCreate(NULL);
   113 	XML_SetUserData(parser, importer);
   114 	XML_SetElementHandler(parser, start_element, end_element);
   115 	if (XML_Parse(parser, p, stat.st_size, 1) == XML_STATUS_ERROR) {
   116 		fprintf(stderr,
   117 			"%s at line %ld, %s\n",
   118 			XML_ErrorString(XML_GetErrorCode(parser)),
   119 			XML_GetCurrentLineNumber(parser),
   120 			filename);
   121 		return 1;
   122 	}
   123 
   124 	XML_ParserFree(parser);
   125 
   126 	SHA1_Init(&sha1);
   127 	SHA1_Update(&sha1, p, stat.st_size);
   128 	SHA1_Final(hash, &sha1);
   129 
   130 	close(fd);
   131 
   132 	munmap(p, stat.st_size);
   133 
   134 	return 0;
   135 }
   136 
   137 struct razor_set *
   138 razor_import_rzr_files(int count, const char *files[])
   139 {
   140 	struct razor_importer *importer;
   141 	int i;
   142 
   143 	importer = razor_importer_new();
   144 
   145 	for (i = 0; i < count; i++) {
   146 		if (import_rzr_file(importer, files[i]) < 0) {
   147 			fprintf(stderr, "failed to import %s\n", files[i]);
   148 			exit(-1);
   149 		}
   150 	}
   151 
   152 	return razor_importer_finish(importer);
   153 }
   154 
   155 /* Import a yum filelist as a razor package set. */
   156 
   157 enum {
   158 	YUM_STATE_BEGIN,
   159 	YUM_STATE_PACKAGE_NAME,
   160 	YUM_STATE_REQUIRES,
   161 	YUM_STATE_PROVIDES,
   162 	YUM_STATE_OBSOLETES,
   163 	YUM_STATE_CONFLICTS,
   164 	YUM_STATE_FILE
   165 };
   166 
   167 struct yum_context {
   168 	struct razor_importer *importer;
   169 	struct import_property_context *current_property_context;
   170 	char name[256], buffer[512], *p;
   171 	int state;
   172 };
   173 
   174 static void
   175 yum_start_element(void *data, const char *name, const char **atts)
   176 {
   177 	struct yum_context *ctx = data;
   178 	const char *n, *version, *release;
   179 	char buffer[128];
   180 	int i;
   181 
   182 	if (strcmp(name, "name") == 0) {
   183 		ctx->state = YUM_STATE_PACKAGE_NAME;
   184 		ctx->p = ctx->name;
   185 	} else if (strcmp(name, "version") == 0) {
   186 		version = NULL;
   187 		release = NULL;
   188 		for (i = 0; atts[i]; i += 2) {
   189 			if (strcmp(atts[i], "ver") == 0)
   190 				version = atts[i + 1];
   191 			else if (strcmp(atts[i], "rel") == 0)
   192 				release = atts[i + 1];
   193 		}
   194 		if (version == NULL || release == NULL) {
   195 			fprintf(stderr, "invalid version tag, "
   196 				"missing version or  release attribute\n");
   197 			return;
   198 		}
   199 
   200 		snprintf(buffer, sizeof buffer, "%s-%s", version, release);
   201 		razor_importer_begin_package(ctx->importer, ctx->name, buffer);
   202 	} else if (strcmp(name, "rpm:requires") == 0) {
   203 		ctx->state = YUM_STATE_REQUIRES;
   204 	} else if (strcmp(name, "rpm:provides") == 0) {
   205 		ctx->state = YUM_STATE_PROVIDES;
   206 	} else if (strcmp(name, "rpm:obsoletes") == 0) {
   207 		ctx->state = YUM_STATE_OBSOLETES;
   208 	} else if (strcmp(name, "rpm:conflicts") == 0) {
   209 		ctx->state = YUM_STATE_CONFLICTS;
   210 	} else if (strcmp(name, "rpm:entry") == 0 &&
   211 		   ctx->state != YUM_STATE_BEGIN) {
   212 		n = NULL;
   213 		version = NULL;
   214 		release = NULL;
   215 		for (i = 0; atts[i]; i += 2) {
   216 			if (strcmp(atts[i], "name") == 0)
   217 				n = atts[i + 1];
   218 			else if (strcmp(atts[i], "ver") == 0)
   219 				version = atts[i + 1];
   220 			else if (strcmp(atts[i], "rel") == 0)
   221 				release = atts[i + 1];
   222 		}
   223 
   224 		if (n == NULL) {
   225 			fprintf(stderr, "invalid rpm:entry, "
   226 				"missing name or version attributes\n");
   227 			return;
   228 		}
   229 
   230 		if (version && release)
   231 			snprintf(buffer, sizeof buffer,
   232 				 "%s-%s", version, release);
   233 		else if (version)
   234 			strcpy(buffer, version);
   235 		else
   236 			buffer[0] = '\0';
   237 			
   238 		switch (ctx->state) {
   239 		case YUM_STATE_REQUIRES:
   240 			razor_importer_add_property(ctx->importer, n, buffer,
   241 						    RAZOR_PROPERTY_REQUIRES);
   242 			break;
   243 		case YUM_STATE_PROVIDES:
   244 			razor_importer_add_property(ctx->importer, n, buffer,
   245 						    RAZOR_PROPERTY_PROVIDES);
   246 			break;
   247 		case YUM_STATE_OBSOLETES:
   248 			razor_importer_add_property(ctx->importer, n, buffer,
   249 						    RAZOR_PROPERTY_OBSOLETES);
   250 			break;
   251 		case YUM_STATE_CONFLICTS:
   252 			razor_importer_add_property(ctx->importer, n, buffer,
   253 						    RAZOR_PROPERTY_CONFLICTS);
   254 			break;
   255 		}
   256 	} else if (strcmp(name, "file") == 0) {
   257 		ctx->state = YUM_STATE_FILE;
   258 		ctx->p = ctx->buffer;
   259 	}
   260 }
   261 
   262 static void
   263 yum_end_element (void *data, const char *name)
   264 {
   265 	struct yum_context *ctx = data;
   266 
   267 	switch (ctx->state) {
   268 	case YUM_STATE_PACKAGE_NAME:
   269 	case YUM_STATE_FILE:
   270 		ctx->state = YUM_STATE_BEGIN;
   271 		break;
   272 	}
   273 
   274 	if (strcmp(name, "package") == 0)
   275 		razor_importer_finish_package(ctx->importer);
   276 	else if (strcmp(name, "file") == 0)
   277 		razor_importer_add_file(ctx->importer, ctx->buffer);
   278 }
   279 
   280 static void
   281 yum_character_data (void *data, const XML_Char *s, int len)
   282 {
   283 	struct yum_context *ctx = data;
   284 
   285 	switch (ctx->state) {
   286 	case YUM_STATE_PACKAGE_NAME:
   287 	case YUM_STATE_FILE:
   288 		memcpy(ctx->p, s, len);
   289 		ctx->p += len;
   290 		*ctx->p = '\0';
   291 		break;
   292 	}
   293 }
   294 
   295 struct razor_set *
   296 razor_set_create_from_yum_filelist(int fd)
   297 {
   298 	struct yum_context ctx;
   299 	XML_Parser parser;
   300 	char buf[4096];
   301 	int len;
   302 
   303 	ctx.importer = razor_importer_new();	
   304 	ctx.state = YUM_STATE_BEGIN;
   305 
   306 	parser = XML_ParserCreate(NULL);
   307 	XML_SetUserData(parser, &ctx);
   308 	XML_SetElementHandler(parser, yum_start_element, yum_end_element);
   309 	XML_SetCharacterDataHandler(parser, yum_character_data);
   310 
   311 	while (1) {
   312 		len = read(fd, buf, sizeof buf);
   313 		if (len < 0) {
   314 			fprintf(stderr,
   315 				"couldn't read input: %s\n", strerror(errno));
   316 			return NULL;
   317 		} else if (len == 0)
   318 			break;
   319 
   320 		if (XML_Parse(parser, buf, len, 0) == XML_STATUS_ERROR) {
   321 			fprintf(stderr,
   322 				"%s at line %ld\n",
   323 				XML_ErrorString(XML_GetErrorCode(parser)),
   324 				XML_GetCurrentLineNumber(parser));
   325 			return NULL;
   326 		}
   327 	}
   328 
   329 	XML_ParserFree(parser);
   330 
   331 	return razor_importer_finish(ctx.importer);
   332 }
   333 
   334 union rpm_entry {
   335 	void *p;
   336 	char *string;
   337 	char **list;
   338 	unsigned int *flags;
   339 };
   340 
   341 struct razor_set *
   342 razor_set_create_from_rpmdb(void)
   343 {
   344 	struct razor_importer *importer;
   345 	rpmdbMatchIterator iter;
   346 	Header h;
   347 	int_32 type, count, i;
   348 	union rpm_entry name, version, release;
   349 	union rpm_entry property_names, property_versions, property_flags;
   350 	union rpm_entry basenames, dirnames, dirindexes;
   351 	char filename[PATH_MAX];
   352 	rpmdb db;
   353 
   354 	rpmReadConfigFiles(NULL, NULL);
   355 
   356 	if (rpmdbOpen("", &db, O_RDONLY, 0644) != 0) {
   357 		fprintf(stderr, "cannot open rpm database\n");
   358 		exit(1);
   359 	}
   360 
   361 	importer = razor_importer_new();
   362 
   363 	iter = rpmdbInitIterator(db, 0, NULL, 0);
   364 	while (h = rpmdbNextIterator(iter), h != NULL) {
   365 		headerGetEntry(h, RPMTAG_NAME, &type, &name.p, &count);
   366 		headerGetEntry(h, RPMTAG_VERSION, &type, &version.p, &count);
   367 		headerGetEntry(h, RPMTAG_RELEASE, &type, &release.p, &count);
   368 		snprintf(filename, sizeof filename, "%s-%s",
   369 			 version.string, release.string);
   370 		razor_importer_begin_package(importer, name.string, filename);
   371 
   372 		headerGetEntry(h, RPMTAG_REQUIRENAME, &type,
   373 			       &property_names.p, &count);
   374 		headerGetEntry(h, RPMTAG_REQUIREVERSION, &type,
   375 			       &property_versions.p, &count);
   376 		headerGetEntry(h, RPMTAG_REQUIREFLAGS, &type,
   377 			       &property_flags.p, &count);
   378 		for (i = 0; i < count; i++)
   379 			razor_importer_add_property(importer,
   380 						    property_names.list[i],
   381 						    property_versions.list[i],
   382 						    RAZOR_PROPERTY_REQUIRES);
   383 
   384 		headerGetEntry(h, RPMTAG_PROVIDENAME, &type,
   385 			       &property_names.p, &count);
   386 		headerGetEntry(h, RPMTAG_PROVIDEVERSION, &type,
   387 			       &property_versions.p, &count);
   388 		headerGetEntry(h, RPMTAG_PROVIDEFLAGS, &type,
   389 			       &property_flags.p, &count);
   390 		for (i = 0; i < count; i++)
   391 			razor_importer_add_property(importer,
   392 						    property_names.list[i],
   393 						    property_versions.list[i],
   394 						    RAZOR_PROPERTY_PROVIDES);
   395 
   396 		headerGetEntry(h, RPMTAG_OBSOLETENAME, &type,
   397 			       &property_names.p, &count);
   398 		headerGetEntry(h, RPMTAG_OBSOLETEVERSION, &type,
   399 			       &property_versions.p, &count);
   400 		headerGetEntry(h, RPMTAG_OBSOLETEFLAGS, &type,
   401 			       &property_flags.p, &count);
   402 		for (i = 0; i < count; i++)
   403 			razor_importer_add_property(importer,
   404 						    property_names.list[i],
   405 						    property_versions.list[i],
   406 						    RAZOR_PROPERTY_OBSOLETES);
   407 
   408 		headerGetEntry(h, RPMTAG_CONFLICTNAME, &type,
   409 			       &property_names.p, &count);
   410 		headerGetEntry(h, RPMTAG_CONFLICTVERSION, &type,
   411 			       &property_versions.p, &count);
   412 		headerGetEntry(h, RPMTAG_CONFLICTFLAGS, &type,
   413 			       &property_flags.p, &count);
   414 		for (i = 0; i < count; i++)
   415 			razor_importer_add_property(importer,
   416 						    property_names.list[i],
   417 						    property_versions.list[i],
   418 						    RAZOR_PROPERTY_CONFLICTS);
   419 
   420 		headerGetEntry(h, RPMTAG_BASENAMES, &type,
   421 			       &basenames.p, &count);
   422 		headerGetEntry(h, RPMTAG_DIRNAMES, &type,
   423 			       &dirnames.p, &count);
   424 		headerGetEntry(h, RPMTAG_DIRINDEXES, &type,
   425 			       &dirindexes.p, &count);
   426 		for (i = 0; i < count; i++) {
   427 			snprintf(filename, sizeof filename, "%s%s",
   428 				 dirnames.list[dirindexes.flags[i]],
   429 				 basenames.list[i]);
   430 			razor_importer_add_file(importer, filename);
   431 		}
   432 
   433 		razor_importer_finish_package(importer);
   434 	}
   435 
   436 	rpmdbClose(db);
   437 
   438 	return razor_importer_finish(importer);
   439 }