yum.c
author Kristian H?gsberg <krh@jiraiya.boston.redhat.com>
Wed Apr 09 02:41:03 2008 -0400 (2008-04-09)
changeset 211 cf0ca962262b
parent 143 59a9513fac54
child 212 e8f493d8ff9a
permissions -rw-r--r--
Use the cpio headers instead of the rpm headers when unpacking.

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