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