yum.c
author Dan Winship <danw@gnome.org>
Fri Feb 15 15:08:38 2008 -0500 (2008-02-15)
changeset 124 feef7736a439
child 143 59a9513fac54
permissions -rw-r--r--
misc fixes for edge cases

1) sets with only one package
2) packages with only one property
3) sets with only one property
     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 "razor.h"
    14 
    15 /* Import a yum filelist as a razor package set. */
    16 
    17 enum {
    18 	YUM_STATE_BEGIN,
    19 	YUM_STATE_PACKAGE_NAME,
    20 	YUM_STATE_CHECKSUM,
    21 	YUM_STATE_REQUIRES,
    22 	YUM_STATE_PROVIDES,
    23 	YUM_STATE_OBSOLETES,
    24 	YUM_STATE_CONFLICTS,
    25 	YUM_STATE_FILE
    26 };
    27 
    28 struct yum_context {
    29 	XML_Parser primary_parser;
    30 	XML_Parser filelists_parser;
    31 	XML_Parser current_parser;
    32 
    33 	struct razor_importer *importer;
    34 	struct import_property_context *current_property_context;
    35 	char name[256], buffer[512], *p;
    36 	char pkgid[128];
    37 	int state;
    38 };
    39 
    40 static enum razor_version_relation
    41 yum_to_razor_flags (const char *flags)
    42 {
    43 	/* FIXME? */
    44 	if (!flags)
    45 		return RAZOR_VERSION_EQUAL;
    46 
    47 	if (flags[0] == 'L') {
    48 		if (flags[1] == 'T')
    49 			return RAZOR_VERSION_LESS;
    50 		else
    51 			return RAZOR_VERSION_LESS_OR_EQUAL;
    52 	} else if (flags[0] == 'G') {
    53 		if (flags[1] == 'T')
    54 			return RAZOR_VERSION_GREATER;
    55 		else
    56 			return RAZOR_VERSION_GREATER_OR_EQUAL;
    57 	} else
    58 		return RAZOR_VERSION_EQUAL;
    59 }
    60 
    61 static void
    62 yum_primary_start_element(void *data, const char *name, const char **atts)
    63 {
    64 	struct yum_context *ctx = data;
    65 	const char *n, *version, *release, *flags;
    66 	char buffer[128];
    67 	int i;
    68 
    69 	if (strcmp(name, "name") == 0) {
    70 		ctx->state = YUM_STATE_PACKAGE_NAME;
    71 		ctx->p = ctx->name;
    72 	} else if (strcmp(name, "version") == 0) {
    73 		version = NULL;
    74 		release = NULL;
    75 		for (i = 0; atts[i]; i += 2) {
    76 			if (strcmp(atts[i], "ver") == 0)
    77 				version = atts[i + 1];
    78 			else if (strcmp(atts[i], "rel") == 0)
    79 				release = atts[i + 1];
    80 		}
    81 		if (version == NULL || release == NULL) {
    82 			fprintf(stderr, "invalid version tag, "
    83 				"missing version or  release attribute\n");
    84 			return;
    85 		}
    86 
    87 		snprintf(buffer, sizeof buffer, "%s-%s", version, release);
    88 		razor_importer_begin_package(ctx->importer, ctx->name, buffer);
    89 	} else if (strcmp(name, "checksum") == 0) {
    90 		ctx->p = ctx->pkgid;
    91 		ctx->state = YUM_STATE_CHECKSUM;
    92 	} else if (strcmp(name, "rpm:requires") == 0) {
    93 		ctx->state = YUM_STATE_REQUIRES;
    94 	} else if (strcmp(name, "rpm:provides") == 0) {
    95 		ctx->state = YUM_STATE_PROVIDES;
    96 	} else if (strcmp(name, "rpm:obsoletes") == 0) {
    97 		ctx->state = YUM_STATE_OBSOLETES;
    98 	} else if (strcmp(name, "rpm:conflicts") == 0) {
    99 		ctx->state = YUM_STATE_CONFLICTS;
   100 	} else if (strcmp(name, "rpm:entry") == 0 &&
   101 		   ctx->state != YUM_STATE_BEGIN) {
   102 		n = NULL;
   103 		version = NULL;
   104 		release = NULL;
   105 		flags = NULL;
   106 		for (i = 0; atts[i]; i += 2) {
   107 			if (strcmp(atts[i], "name") == 0)
   108 				n = atts[i + 1];
   109 			else if (strcmp(atts[i], "ver") == 0)
   110 				version = atts[i + 1];
   111 			else if (strcmp(atts[i], "rel") == 0)
   112 				release = atts[i + 1];
   113 			else if (strcmp(atts[i], "flags") == 0)
   114 				flags = atts[i + 1];
   115 		}
   116 
   117 		if (n == NULL) {
   118 			fprintf(stderr, "invalid rpm:entry, "
   119 				"missing name or version attributes\n");
   120 			return;
   121 		}
   122 
   123 		if (version && release)
   124 			snprintf(buffer, sizeof buffer,
   125 				 "%s-%s", version, release);
   126 		else if (version)
   127 			strcpy(buffer, version);
   128 		else
   129 			buffer[0] = '\0';
   130 			
   131 		switch (ctx->state) {
   132 		case YUM_STATE_REQUIRES:
   133 			razor_importer_add_property(ctx->importer, n,
   134 						    yum_to_razor_flags (flags),
   135 						    buffer,
   136 						    RAZOR_PROPERTY_REQUIRES);
   137 			break;
   138 		case YUM_STATE_PROVIDES:
   139 			razor_importer_add_property(ctx->importer, n,
   140 						    yum_to_razor_flags (flags),
   141 						    buffer,
   142 						    RAZOR_PROPERTY_PROVIDES);
   143 			break;
   144 		case YUM_STATE_OBSOLETES:
   145 			razor_importer_add_property(ctx->importer, n,
   146 						    yum_to_razor_flags (flags),
   147 						    buffer,
   148 						    RAZOR_PROPERTY_OBSOLETES);
   149 			break;
   150 		case YUM_STATE_CONFLICTS:
   151 			razor_importer_add_property(ctx->importer, n,
   152 						    yum_to_razor_flags (flags),
   153 						    buffer,
   154 						    RAZOR_PROPERTY_CONFLICTS);
   155 			break;
   156 		}
   157 	}
   158 }
   159 
   160 static void
   161 yum_primary_end_element (void *data, const char *name)
   162 {
   163 	struct yum_context *ctx = data;
   164 
   165 	switch (ctx->state) {
   166 	case YUM_STATE_PACKAGE_NAME:
   167 	case YUM_STATE_CHECKSUM:
   168 	case YUM_STATE_FILE:
   169 		ctx->state = YUM_STATE_BEGIN;
   170 		break;
   171 	}
   172 
   173 	if (strcmp(name, "package") == 0) {
   174 		XML_StopParser(ctx->current_parser, XML_TRUE);
   175 		ctx->current_parser = ctx->filelists_parser;
   176 	}
   177 }
   178 
   179 static void
   180 yum_character_data (void *data, const XML_Char *s, int len)
   181 {
   182 	struct yum_context *ctx = data;
   183 
   184 	switch (ctx->state) {
   185 	case YUM_STATE_PACKAGE_NAME:
   186 	case YUM_STATE_CHECKSUM:
   187 	case YUM_STATE_FILE:
   188 		memcpy(ctx->p, s, len);
   189 		ctx->p += len;
   190 		*ctx->p = '\0';
   191 		break;
   192 	}
   193 }
   194 
   195 static void
   196 yum_filelists_start_element(void *data, const char *name, const char **atts)
   197 {
   198 	struct yum_context *ctx = data;
   199 	const char *pkg, *pkgid;
   200 	int i;
   201 
   202 	if (strcmp(name, "package") == 0) {
   203 		pkg = NULL;
   204 		pkgid = NULL;
   205 		for (i = 0; atts[i]; i += 2) {
   206 			if (strcmp(atts[i], "name") == 0)
   207 				pkg = atts[i + 1];
   208 			else if (strcmp(atts[i], "pkgid") == 0)
   209 				pkgid = atts[i + 1];
   210 		}
   211 		if (strcmp(pkgid, ctx->pkgid) != 0)
   212 			fprintf(stderr, "primary.xml and filelists.xml "
   213 				"mismatch for %s: %s vs %s",
   214 				pkg, pkgid, ctx->pkgid);
   215 	} else if (strcmp(name, "file") == 0) {
   216 		ctx->state = YUM_STATE_FILE;
   217 		ctx->p = ctx->buffer;
   218 	}
   219 }
   220 
   221 
   222 static void
   223 yum_filelists_end_element (void *data, const char *name)
   224 {
   225 	struct yum_context *ctx = data;
   226 
   227 	ctx->state = YUM_STATE_BEGIN;
   228 	if (strcmp(name, "package") == 0) {
   229 		XML_StopParser(ctx->current_parser, XML_TRUE);
   230 		ctx->current_parser = ctx->primary_parser;
   231 		razor_importer_finish_package(ctx->importer);
   232 	} else if (strcmp(name, "file") == 0)
   233 		razor_importer_add_file(ctx->importer, ctx->buffer);
   234 
   235 }
   236 
   237 #define XML_BUFFER_SIZE 4096
   238 
   239 struct razor_set *
   240 razor_set_create_from_yum(void)
   241 {
   242 	struct yum_context ctx;
   243 	void *buf;
   244 	int len, ret;
   245 	gzFile primary, filelists;
   246 	XML_ParsingStatus status;
   247 
   248 	ctx.importer = razor_importer_new();	
   249 	ctx.state = YUM_STATE_BEGIN;
   250 
   251 	ctx.primary_parser = XML_ParserCreate(NULL);
   252 	XML_SetUserData(ctx.primary_parser, &ctx);
   253 	XML_SetElementHandler(ctx.primary_parser,
   254 			      yum_primary_start_element,
   255 			      yum_primary_end_element);
   256 	XML_SetCharacterDataHandler(ctx.primary_parser,
   257 				    yum_character_data);
   258 
   259 	ctx.filelists_parser = XML_ParserCreate(NULL);
   260 	XML_SetUserData(ctx.filelists_parser, &ctx);
   261 	XML_SetElementHandler(ctx.filelists_parser,
   262 			      yum_filelists_start_element,
   263 			      yum_filelists_end_element);
   264 	XML_SetCharacterDataHandler(ctx.filelists_parser,
   265 				    yum_character_data);
   266 
   267 	primary = gzopen("primary.xml.gz", "rb");
   268 	if (primary == NULL)
   269 		return NULL;
   270 	filelists = gzopen("filelists.xml.gz", "rb");
   271 	if (filelists == NULL)
   272 		return NULL;
   273 
   274 	ctx.current_parser = ctx.primary_parser;
   275 
   276 	do {
   277 		XML_GetParsingStatus(ctx.current_parser, &status);
   278 		switch (status.parsing) {
   279 		case XML_SUSPENDED:
   280 			ret = XML_ResumeParser(ctx.current_parser);
   281 			break;
   282 		case XML_PARSING:
   283 		case XML_INITIALIZED:
   284 			buf = XML_GetBuffer(ctx.current_parser,
   285 					    XML_BUFFER_SIZE);
   286 			if (ctx.current_parser == ctx.primary_parser)
   287 				len = gzread(primary, buf, XML_BUFFER_SIZE);
   288 			else
   289 				len = gzread(filelists, buf, XML_BUFFER_SIZE);
   290 			if (len < 0) {
   291 				fprintf(stderr,
   292 					"couldn't read input: %s\n",
   293 					strerror(errno));
   294 				return NULL;
   295 			}
   296 
   297 			XML_ParseBuffer(ctx.current_parser, len, len == 0);
   298 			break;
   299 		case XML_FINISHED:
   300 			break;
   301 		}
   302 	} while (status.parsing != XML_FINISHED);
   303 
   304 
   305 	XML_ParserFree(ctx.primary_parser);
   306 	XML_ParserFree(ctx.filelists_parser);
   307 
   308 	gzclose(primary);
   309 	gzclose(filelists);
   310 
   311 	return razor_importer_finish(ctx.importer);
   312 }