import.c
author Kristian H?gsberg <krh@redhat.com>
Thu Jan 17 23:36:12 2008 -0500 (2008-01-17)
changeset 102 337a7a55e2c6
parent 76 773e6a26707f
child 104 705f6dbf0a7e
permissions -rw-r--r--
Use the package iterator for looping over file owners too.
     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 <zlib.h>
    13 #include <rpm/rpmlib.h>
    14 #include <rpm/rpmdb.h>
    15 #include "razor.h"
    16 
    17 /* Import a yum filelist as a razor package set. */
    18 
    19 enum {
    20 	YUM_STATE_BEGIN,
    21 	YUM_STATE_PACKAGE_NAME,
    22 	YUM_STATE_CHECKSUM,
    23 	YUM_STATE_REQUIRES,
    24 	YUM_STATE_PROVIDES,
    25 	YUM_STATE_OBSOLETES,
    26 	YUM_STATE_CONFLICTS,
    27 	YUM_STATE_FILE
    28 };
    29 
    30 struct yum_context {
    31 	XML_Parser primary_parser;
    32 	XML_Parser filelists_parser;
    33 	XML_Parser current_parser;
    34 
    35 	struct razor_importer *importer;
    36 	struct import_property_context *current_property_context;
    37 	char name[256], buffer[512], *p;
    38 	char pkgid[128];
    39 	int state;
    40 };
    41 
    42 static void
    43 yum_primary_start_element(void *data, const char *name, const char **atts)
    44 {
    45 	struct yum_context *ctx = data;
    46 	const char *n, *version, *release;
    47 	char buffer[128];
    48 	int i;
    49 
    50 	if (strcmp(name, "name") == 0) {
    51 		ctx->state = YUM_STATE_PACKAGE_NAME;
    52 		ctx->p = ctx->name;
    53 	} else if (strcmp(name, "version") == 0) {
    54 		version = NULL;
    55 		release = NULL;
    56 		for (i = 0; atts[i]; i += 2) {
    57 			if (strcmp(atts[i], "ver") == 0)
    58 				version = atts[i + 1];
    59 			else if (strcmp(atts[i], "rel") == 0)
    60 				release = atts[i + 1];
    61 		}
    62 		if (version == NULL || release == NULL) {
    63 			fprintf(stderr, "invalid version tag, "
    64 				"missing version or  release attribute\n");
    65 			return;
    66 		}
    67 
    68 		snprintf(buffer, sizeof buffer, "%s-%s", version, release);
    69 		razor_importer_begin_package(ctx->importer, ctx->name, buffer);
    70 	} else if (strcmp(name, "checksum") == 0) {
    71 		ctx->p = ctx->pkgid;
    72 		ctx->state = YUM_STATE_CHECKSUM;
    73 	} else if (strcmp(name, "rpm:requires") == 0) {
    74 		ctx->state = YUM_STATE_REQUIRES;
    75 	} else if (strcmp(name, "rpm:provides") == 0) {
    76 		ctx->state = YUM_STATE_PROVIDES;
    77 	} else if (strcmp(name, "rpm:obsoletes") == 0) {
    78 		ctx->state = YUM_STATE_OBSOLETES;
    79 	} else if (strcmp(name, "rpm:conflicts") == 0) {
    80 		ctx->state = YUM_STATE_CONFLICTS;
    81 	} else if (strcmp(name, "rpm:entry") == 0 &&
    82 		   ctx->state != YUM_STATE_BEGIN) {
    83 		n = NULL;
    84 		version = NULL;
    85 		release = NULL;
    86 		for (i = 0; atts[i]; i += 2) {
    87 			if (strcmp(atts[i], "name") == 0)
    88 				n = atts[i + 1];
    89 			else if (strcmp(atts[i], "ver") == 0)
    90 				version = atts[i + 1];
    91 			else if (strcmp(atts[i], "rel") == 0)
    92 				release = atts[i + 1];
    93 		}
    94 
    95 		if (n == NULL) {
    96 			fprintf(stderr, "invalid rpm:entry, "
    97 				"missing name or version attributes\n");
    98 			return;
    99 		}
   100 
   101 		if (version && release)
   102 			snprintf(buffer, sizeof buffer,
   103 				 "%s-%s", version, release);
   104 		else if (version)
   105 			strcpy(buffer, version);
   106 		else
   107 			buffer[0] = '\0';
   108 			
   109 		switch (ctx->state) {
   110 		case YUM_STATE_REQUIRES:
   111 			razor_importer_add_property(ctx->importer, n, buffer,
   112 						    RAZOR_PROPERTY_REQUIRES);
   113 			break;
   114 		case YUM_STATE_PROVIDES:
   115 			razor_importer_add_property(ctx->importer, n, buffer,
   116 						    RAZOR_PROPERTY_PROVIDES);
   117 			break;
   118 		case YUM_STATE_OBSOLETES:
   119 			razor_importer_add_property(ctx->importer, n, buffer,
   120 						    RAZOR_PROPERTY_OBSOLETES);
   121 			break;
   122 		case YUM_STATE_CONFLICTS:
   123 			razor_importer_add_property(ctx->importer, n, buffer,
   124 						    RAZOR_PROPERTY_CONFLICTS);
   125 			break;
   126 		}
   127 	}
   128 }
   129 
   130 static void
   131 yum_primary_end_element (void *data, const char *name)
   132 {
   133 	struct yum_context *ctx = data;
   134 
   135 	switch (ctx->state) {
   136 	case YUM_STATE_PACKAGE_NAME:
   137 	case YUM_STATE_CHECKSUM:
   138 	case YUM_STATE_FILE:
   139 		ctx->state = YUM_STATE_BEGIN;
   140 		break;
   141 	}
   142 
   143 	if (strcmp(name, "package") == 0) {
   144 		XML_StopParser(ctx->current_parser, XML_TRUE);
   145 		ctx->current_parser = ctx->filelists_parser;
   146 	}
   147 }
   148 
   149 static void
   150 yum_character_data (void *data, const XML_Char *s, int len)
   151 {
   152 	struct yum_context *ctx = data;
   153 
   154 	switch (ctx->state) {
   155 	case YUM_STATE_PACKAGE_NAME:
   156 	case YUM_STATE_CHECKSUM:
   157 	case YUM_STATE_FILE:
   158 		memcpy(ctx->p, s, len);
   159 		ctx->p += len;
   160 		*ctx->p = '\0';
   161 		break;
   162 	}
   163 }
   164 
   165 static void
   166 yum_filelists_start_element(void *data, const char *name, const char **atts)
   167 {
   168 	struct yum_context *ctx = data;
   169 	const char *pkg, *pkgid;
   170 	int i;
   171 
   172 	if (strcmp(name, "package") == 0) {
   173 		pkg = NULL;
   174 		pkgid = NULL;
   175 		for (i = 0; atts[i]; i += 2) {
   176 			if (strcmp(atts[i], "name") == 0)
   177 				pkg = atts[i + 1];
   178 			else if (strcmp(atts[i], "pkgid") == 0)
   179 				pkgid = atts[i + 1];
   180 		}
   181 		if (strcmp(pkgid, ctx->pkgid) != 0)
   182 			fprintf(stderr, "primary.xml and filelists.xml "
   183 				"mismatch for %s: %s vs %s",
   184 				pkg, pkgid, ctx->pkgid);
   185 	} else if (strcmp(name, "file") == 0) {
   186 		ctx->state = YUM_STATE_FILE;
   187 		ctx->p = ctx->buffer;
   188 	}
   189 }
   190 
   191 
   192 static void
   193 yum_filelists_end_element (void *data, const char *name)
   194 {
   195 	struct yum_context *ctx = data;
   196 
   197 	ctx->state = YUM_STATE_BEGIN;
   198 	if (strcmp(name, "package") == 0) {
   199 		XML_StopParser(ctx->current_parser, XML_TRUE);
   200 		ctx->current_parser = ctx->primary_parser;
   201 		razor_importer_finish_package(ctx->importer);
   202 	} else if (strcmp(name, "file") == 0)
   203 		razor_importer_add_file(ctx->importer, ctx->buffer);
   204 
   205 }
   206 
   207 #define XML_BUFFER_SIZE 4096
   208 
   209 struct razor_set *
   210 razor_set_create_from_yum(void)
   211 {
   212 	struct yum_context ctx;
   213 	void *buf;
   214 	int len, ret;
   215 	gzFile primary, filelists;
   216 	XML_ParsingStatus status;
   217 
   218 	ctx.importer = razor_importer_new();	
   219 	ctx.state = YUM_STATE_BEGIN;
   220 
   221 	ctx.primary_parser = XML_ParserCreate(NULL);
   222 	XML_SetUserData(ctx.primary_parser, &ctx);
   223 	XML_SetElementHandler(ctx.primary_parser,
   224 			      yum_primary_start_element,
   225 			      yum_primary_end_element);
   226 	XML_SetCharacterDataHandler(ctx.primary_parser,
   227 				    yum_character_data);
   228 
   229 	ctx.filelists_parser = XML_ParserCreate(NULL);
   230 	XML_SetUserData(ctx.filelists_parser, &ctx);
   231 	XML_SetElementHandler(ctx.filelists_parser,
   232 			      yum_filelists_start_element,
   233 			      yum_filelists_end_element);
   234 	XML_SetCharacterDataHandler(ctx.filelists_parser,
   235 				    yum_character_data);
   236 
   237 	primary = gzopen("primary.xml.gz", "rb");
   238 	if (primary == NULL)
   239 		return NULL;
   240 	filelists = gzopen("filelists.xml.gz", "rb");
   241 	if (filelists == NULL)
   242 		return NULL;
   243 
   244 	ctx.current_parser = ctx.primary_parser;
   245 
   246 	do {
   247 		XML_GetParsingStatus(ctx.current_parser, &status);
   248 		switch (status.parsing) {
   249 		case XML_SUSPENDED:
   250 			ret = XML_ResumeParser(ctx.current_parser);
   251 			break;
   252 		case XML_PARSING:
   253 		case XML_INITIALIZED:
   254 			buf = XML_GetBuffer(ctx.current_parser,
   255 					    XML_BUFFER_SIZE);
   256 			if (ctx.current_parser == ctx.primary_parser)
   257 				len = gzread(primary, buf, XML_BUFFER_SIZE);
   258 			else
   259 				len = gzread(filelists, buf, XML_BUFFER_SIZE);
   260 			if (len < 0) {
   261 				fprintf(stderr,
   262 					"couldn't read input: %s\n",
   263 					strerror(errno));
   264 				return NULL;
   265 			}
   266 
   267 			XML_ParseBuffer(ctx.current_parser, len, len == 0);
   268 			break;
   269 		case XML_FINISHED:
   270 			break;
   271 		}
   272 	} while (status.parsing != XML_FINISHED);
   273 
   274 
   275 	XML_ParserFree(ctx.primary_parser);
   276 	XML_ParserFree(ctx.filelists_parser);
   277 
   278 	gzclose(primary);
   279 	gzclose(filelists);
   280 
   281 	return razor_importer_finish(ctx.importer);
   282 }
   283 
   284 union rpm_entry {
   285 	void *p;
   286 	char *string;
   287 	char **list;
   288 	unsigned int *flags;
   289 };
   290 
   291 struct razor_set *
   292 razor_set_create_from_rpmdb(void)
   293 {
   294 	struct razor_importer *importer;
   295 	rpmdbMatchIterator iter;
   296 	Header h;
   297 	int_32 type, count, i;
   298 	union rpm_entry name, version, release;
   299 	union rpm_entry property_names, property_versions, property_flags;
   300 	union rpm_entry basenames, dirnames, dirindexes;
   301 	char filename[PATH_MAX];
   302 	rpmdb db;
   303 
   304 	rpmReadConfigFiles(NULL, NULL);
   305 
   306 	if (rpmdbOpen("", &db, O_RDONLY, 0644) != 0) {
   307 		fprintf(stderr, "cannot open rpm database\n");
   308 		exit(1);
   309 	}
   310 
   311 	importer = razor_importer_new();
   312 
   313 	iter = rpmdbInitIterator(db, 0, NULL, 0);
   314 	while (h = rpmdbNextIterator(iter), h != NULL) {
   315 		headerGetEntry(h, RPMTAG_NAME, &type, &name.p, &count);
   316 		headerGetEntry(h, RPMTAG_VERSION, &type, &version.p, &count);
   317 		headerGetEntry(h, RPMTAG_RELEASE, &type, &release.p, &count);
   318 		snprintf(filename, sizeof filename, "%s-%s",
   319 			 version.string, release.string);
   320 		razor_importer_begin_package(importer, name.string, filename);
   321 
   322 		headerGetEntry(h, RPMTAG_REQUIRENAME, &type,
   323 			       &property_names.p, &count);
   324 		headerGetEntry(h, RPMTAG_REQUIREVERSION, &type,
   325 			       &property_versions.p, &count);
   326 		headerGetEntry(h, RPMTAG_REQUIREFLAGS, &type,
   327 			       &property_flags.p, &count);
   328 		for (i = 0; i < count; i++)
   329 			razor_importer_add_property(importer,
   330 						    property_names.list[i],
   331 						    property_versions.list[i],
   332 						    RAZOR_PROPERTY_REQUIRES);
   333 
   334 		headerGetEntry(h, RPMTAG_PROVIDENAME, &type,
   335 			       &property_names.p, &count);
   336 		headerGetEntry(h, RPMTAG_PROVIDEVERSION, &type,
   337 			       &property_versions.p, &count);
   338 		headerGetEntry(h, RPMTAG_PROVIDEFLAGS, &type,
   339 			       &property_flags.p, &count);
   340 		for (i = 0; i < count; i++)
   341 			razor_importer_add_property(importer,
   342 						    property_names.list[i],
   343 						    property_versions.list[i],
   344 						    RAZOR_PROPERTY_PROVIDES);
   345 
   346 		headerGetEntry(h, RPMTAG_OBSOLETENAME, &type,
   347 			       &property_names.p, &count);
   348 		headerGetEntry(h, RPMTAG_OBSOLETEVERSION, &type,
   349 			       &property_versions.p, &count);
   350 		headerGetEntry(h, RPMTAG_OBSOLETEFLAGS, &type,
   351 			       &property_flags.p, &count);
   352 		for (i = 0; i < count; i++)
   353 			razor_importer_add_property(importer,
   354 						    property_names.list[i],
   355 						    property_versions.list[i],
   356 						    RAZOR_PROPERTY_OBSOLETES);
   357 
   358 		headerGetEntry(h, RPMTAG_CONFLICTNAME, &type,
   359 			       &property_names.p, &count);
   360 		headerGetEntry(h, RPMTAG_CONFLICTVERSION, &type,
   361 			       &property_versions.p, &count);
   362 		headerGetEntry(h, RPMTAG_CONFLICTFLAGS, &type,
   363 			       &property_flags.p, &count);
   364 		for (i = 0; i < count; i++)
   365 			razor_importer_add_property(importer,
   366 						    property_names.list[i],
   367 						    property_versions.list[i],
   368 						    RAZOR_PROPERTY_CONFLICTS);
   369 
   370 		headerGetEntry(h, RPMTAG_BASENAMES, &type,
   371 			       &basenames.p, &count);
   372 		headerGetEntry(h, RPMTAG_DIRNAMES, &type,
   373 			       &dirnames.p, &count);
   374 		headerGetEntry(h, RPMTAG_DIRINDEXES, &type,
   375 			       &dirindexes.p, &count);
   376 		for (i = 0; i < count; i++) {
   377 			snprintf(filename, sizeof filename, "%s%s",
   378 				 dirnames.list[dirindexes.flags[i]],
   379 				 basenames.list[i]);
   380 			razor_importer_add_file(importer, filename);
   381 		}
   382 
   383 		razor_importer_finish_package(importer);
   384 	}
   385 
   386 	rpmdbClose(db);
   387 
   388 	return razor_importer_finish(importer);
   389 }