import.c
author Dan Winship <danw@gnome.org>
Mon Feb 04 10:46:29 2008 -0500 (2008-02-04)
changeset 108 340d92912f49
parent 90 7bd64a40cb03
permissions -rw-r--r--
Fix repo format on x86_64 by using uint32_t instead of unsigned long
     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 static void
   292 add_properties(struct razor_importer *importer,
   293 	       enum razor_property_type property_type,
   294 	       Header h, int_32 name_tag, int_32 version_tag, int_32 flags_tag)
   295 {
   296 	union rpm_entry names, versions, flags;
   297 	int_32 i, type, count;
   298 
   299 	headerGetEntry(h, name_tag, &type, &names.p, &count);
   300 	headerGetEntry(h, version_tag, &type, &versions.p, &count);
   301 	headerGetEntry(h, flags_tag, &type, &flags.p, &count);
   302 
   303 	for (i = 0; i < count; i++)
   304 		razor_importer_add_property(importer,
   305 					    names.list[i],
   306 					    versions.list[i],
   307 					    property_type);
   308 }
   309 
   310 struct razor_set *
   311 razor_set_create_from_rpmdb(void)
   312 {
   313 	struct razor_importer *importer;
   314 	rpmdbMatchIterator iter;
   315 	Header h;
   316 	int_32 type, count, i;
   317 	union rpm_entry name, version, release;
   318 	union rpm_entry basenames, dirnames, dirindexes;
   319 	char filename[PATH_MAX];
   320 	rpmdb db;
   321 
   322 	rpmReadConfigFiles(NULL, NULL);
   323 
   324 	if (rpmdbOpen("", &db, O_RDONLY, 0644) != 0) {
   325 		fprintf(stderr, "cannot open rpm database\n");
   326 		exit(1);
   327 	}
   328 
   329 	importer = razor_importer_new();
   330 
   331 	iter = rpmdbInitIterator(db, 0, NULL, 0);
   332 	while (h = rpmdbNextIterator(iter), h != NULL) {
   333 		headerGetEntry(h, RPMTAG_NAME, &type, &name.p, &count);
   334 		headerGetEntry(h, RPMTAG_VERSION, &type, &version.p, &count);
   335 		headerGetEntry(h, RPMTAG_RELEASE, &type, &release.p, &count);
   336 		snprintf(filename, sizeof filename, "%s-%s",
   337 			 version.string, release.string);
   338 		razor_importer_begin_package(importer, name.string, filename);
   339 
   340 		add_properties(importer, RAZOR_PROPERTY_REQUIRES, h,
   341 			       RPMTAG_REQUIRENAME,
   342 			       RPMTAG_REQUIREVERSION,
   343 			       RPMTAG_REQUIREFLAGS);
   344 
   345 		add_properties(importer, RAZOR_PROPERTY_PROVIDES, h,
   346 			       RPMTAG_PROVIDENAME,
   347 			       RPMTAG_PROVIDEVERSION,
   348 			       RPMTAG_PROVIDEFLAGS);
   349 
   350 		add_properties(importer, RAZOR_PROPERTY_OBSOLETES, h,
   351 			       RPMTAG_OBSOLETENAME,
   352 			       RPMTAG_OBSOLETEVERSION,
   353 			       RPMTAG_OBSOLETEFLAGS);
   354 
   355 		add_properties(importer, RAZOR_PROPERTY_CONFLICTS, h,
   356 			       RPMTAG_CONFLICTNAME,
   357 			       RPMTAG_CONFLICTVERSION,
   358 			       RPMTAG_CONFLICTFLAGS);
   359 
   360 		headerGetEntry(h, RPMTAG_BASENAMES, &type,
   361 			       &basenames.p, &count);
   362 		headerGetEntry(h, RPMTAG_DIRNAMES, &type,
   363 			       &dirnames.p, &count);
   364 		headerGetEntry(h, RPMTAG_DIRINDEXES, &type,
   365 			       &dirindexes.p, &count);
   366 		for (i = 0; i < count; i++) {
   367 			snprintf(filename, sizeof filename, "%s%s",
   368 				 dirnames.list[dirindexes.flags[i]],
   369 				 basenames.list[i]);
   370 			razor_importer_add_file(importer, filename);
   371 		}
   372 
   373 		razor_importer_finish_package(importer);
   374 	}
   375 
   376 	rpmdbClose(db);
   377 
   378 	return razor_importer_finish(importer);
   379 }