src/import-yum.c
author J. Ali Harlow <ali@juiblex.co.uk>
Wed Apr 29 17:00:01 2009 +0100 (2009-04-29)
changeset 361 2523d03a840e
parent 263 23c56c3f0449
child 394 afe520f454bd
permissions -rw-r--r--
Add support for preloading lua modules. This is useful both when
providing lua bindings to applications based on librazor and when
producing static binaries using librazor (where otherwise the lua
POSIX library would need to be included as an additional dynamic
object).
     1 /*
     2  * Copyright (C) 2008  Kristian Høgsberg <krh@redhat.com>
     3  * Copyright (C) 2008  Red Hat, Inc
     4  *
     5  * This program is free software; you can redistribute it and/or modify
     6  * it under the terms of the GNU General Public License as published by
     7  * the Free Software Foundation; either version 2 of the License, or
     8  * (at your option) any later version.
     9  *
    10  * This program is distributed in the hope that it will be useful,
    11  * but WITHOUT ANY WARRANTY; without even the implied warranty of
    12  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
    13  * GNU General Public License for more details.
    14  *
    15  * You should have received a copy of the GNU General Public License along
    16  * with this program; if not, write to the Free Software Foundation, Inc.,
    17  * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
    18  */
    19 
    20 #define _GNU_SOURCE
    21 
    22 #include <string.h>
    23 #include <stdio.h>
    24 #include <stdint.h>
    25 #include <sys/stat.h>
    26 #include <unistd.h>
    27 #include <fcntl.h>
    28 #include <errno.h>
    29 
    30 #include <expat.h>
    31 #include <zlib.h>
    32 #include "razor.h"
    33 
    34 /* Import a yum filelist as a razor package set. */
    35 
    36 enum {
    37 	YUM_STATE_BEGIN,
    38 	YUM_STATE_PACKAGE_NAME,
    39 	YUM_STATE_PACKAGE_ARCH,
    40 	YUM_STATE_SUMMARY,
    41 	YUM_STATE_DESCRIPTION,
    42 	YUM_STATE_URL,
    43 	YUM_STATE_LICENSE,
    44 	YUM_STATE_CHECKSUM,
    45 	YUM_STATE_REQUIRES,
    46 	YUM_STATE_PROVIDES,
    47 	YUM_STATE_OBSOLETES,
    48 	YUM_STATE_CONFLICTS,
    49 	YUM_STATE_FILE
    50 };
    51 
    52 struct yum_context {
    53 	XML_Parser primary_parser;
    54 	XML_Parser filelists_parser;
    55 	XML_Parser current_parser;
    56 
    57 	struct razor_importer *importer;
    58 	struct import_property_context *current_property_context;
    59 	char name[256], arch[64], summary[512], description[4096];
    60 	char url[256], license[64], buffer[512], *p;
    61 	char pkgid[128];
    62 	uint32_t property_type;
    63 	int state;
    64 
    65 	int total, current;
    66 };
    67 
    68 static uint32_t
    69 yum_to_razor_relation (const char *flags)
    70 {
    71 	if (flags[0] == 'L') {
    72 		if (flags[1] == 'T')
    73 			return RAZOR_PROPERTY_LESS;
    74 		else
    75 			return RAZOR_PROPERTY_LESS | RAZOR_PROPERTY_EQUAL;
    76 	} else if (flags[0] == 'G') {
    77 		if (flags[1] == 'T')
    78 			return RAZOR_PROPERTY_GREATER;
    79 		else
    80 			return RAZOR_PROPERTY_GREATER | RAZOR_PROPERTY_EQUAL;
    81 	} else
    82 		return RAZOR_PROPERTY_EQUAL;
    83 }
    84 
    85 static void
    86 yum_primary_start_element(void *data, const char *name, const char **atts)
    87 {
    88 	struct yum_context *ctx = data;
    89 	const char *n, *epoch, *version, *release;
    90 	char buffer[128];
    91 	uint32_t pre, relation, flags;
    92 	int i;
    93 
    94 	if (strcmp(name, "metadata") == 0) {
    95 		for (i = 0; atts[i]; i += 2) {
    96 			if (strcmp(atts[i], "packages") == 0)
    97 				ctx->total = atoi(atts[i + 1]);
    98 		}
    99 	} else if (strcmp(name, "name") == 0) {
   100 		ctx->state = YUM_STATE_PACKAGE_NAME;
   101 		ctx->p = ctx->name;
   102 	} else if (strcmp(name, "arch") == 0) {
   103 		ctx->state = YUM_STATE_PACKAGE_ARCH;
   104 		ctx->p = ctx->arch;
   105 	} else if (strcmp(name, "version") == 0) {
   106 		epoch = NULL;
   107 		version = NULL;
   108 		release = NULL;
   109 		for (i = 0; atts[i]; i += 2) {
   110 			if (strcmp(atts[i], "epoch") == 0)
   111 				epoch = atts[i + 1];
   112 			else if (strcmp(atts[i], "ver") == 0)
   113 				version = atts[i + 1];
   114 			else if (strcmp(atts[i], "rel") == 0)
   115 				release = atts[i + 1];
   116 		}
   117 		if (version == NULL || release == NULL) {
   118 			fprintf(stderr, "invalid version tag, "
   119 				"missing version or  release attribute\n");
   120 			return;
   121 		}
   122 
   123 		razor_build_evr(buffer, sizeof buffer, epoch, version, release);
   124 		razor_importer_begin_package(ctx->importer,
   125 					     ctx->name, buffer, ctx->arch);
   126 	} else if (strcmp(name, "summary") == 0) {
   127 		ctx->p = ctx->summary;
   128 		ctx->state = YUM_STATE_SUMMARY;
   129 	} else if (strcmp(name, "description") == 0) {
   130 		ctx->p = ctx->description;
   131 		ctx->state = YUM_STATE_DESCRIPTION;
   132 	} else if (strcmp(name, "url") == 0) {
   133 		ctx->p = ctx->url;
   134 		ctx->state = YUM_STATE_URL;
   135 	} else if (strcmp(name, "checksum") == 0) {
   136 		ctx->p = ctx->pkgid;
   137 		ctx->state = YUM_STATE_CHECKSUM;
   138 	} else if (strcmp(name, "rpm:license") == 0) {
   139 		ctx->p = ctx->license;
   140 		ctx->state = YUM_STATE_LICENSE;
   141 	} else if (strcmp(name, "rpm:requires") == 0) {
   142 		ctx->state = YUM_STATE_REQUIRES;
   143 		ctx->property_type = RAZOR_PROPERTY_REQUIRES;
   144 	} else if (strcmp(name, "rpm:provides") == 0) {
   145 		ctx->state = YUM_STATE_PROVIDES;
   146 		ctx->property_type = RAZOR_PROPERTY_PROVIDES;
   147 	} else if (strcmp(name, "rpm:obsoletes") == 0) {
   148 		ctx->state = YUM_STATE_OBSOLETES;
   149 		ctx->property_type = RAZOR_PROPERTY_OBSOLETES;
   150 	} else if (strcmp(name, "rpm:conflicts") == 0) {
   151 		ctx->state = YUM_STATE_CONFLICTS;
   152 		ctx->property_type = RAZOR_PROPERTY_CONFLICTS;
   153 	} else if (strcmp(name, "rpm:entry") == 0 &&
   154 		   ctx->state != YUM_STATE_BEGIN) {
   155 		n = NULL;
   156 		epoch = NULL;
   157 		version = NULL;
   158 		release = NULL;
   159 		relation = RAZOR_PROPERTY_EQUAL;
   160 		pre = 0;
   161 		for (i = 0; atts[i]; i += 2) {
   162 			if (strcmp(atts[i], "name") == 0)
   163 				n = atts[i + 1];
   164 			else if (strcmp(atts[i], "epoch") == 0)
   165 				epoch = atts[i + 1];
   166 			else if (strcmp(atts[i], "ver") == 0)
   167 				version = atts[i + 1];
   168 			else if (strcmp(atts[i], "rel") == 0)
   169 				release = atts[i + 1];
   170 			else if (strcmp(atts[i], "flags") == 0)
   171 				relation = yum_to_razor_relation(atts[i + 1]);
   172 			else if (strcmp(atts[i], "pre") == 0)
   173 				pre = 
   174 					RAZOR_PROPERTY_PRE |
   175 					RAZOR_PROPERTY_POST |
   176 					RAZOR_PROPERTY_PREUN |
   177 					RAZOR_PROPERTY_POSTUN;
   178 		}
   179 
   180 		if (n == NULL) {
   181 			fprintf(stderr, "invalid rpm:entry, "
   182 				"missing name or version attributes\n");
   183 			return;
   184 		}
   185 
   186 		razor_build_evr(buffer, sizeof buffer, epoch, version, release);
   187 		flags = ctx->property_type | relation | pre;
   188 		razor_importer_add_property(ctx->importer, n, flags, buffer);
   189 	}
   190 }
   191 
   192 static void
   193 yum_primary_end_element (void *data, const char *name)
   194 {
   195 	struct yum_context *ctx = data;
   196 
   197 	switch (ctx->state) {
   198 	case YUM_STATE_PACKAGE_NAME:
   199 	case YUM_STATE_PACKAGE_ARCH:
   200 	case YUM_STATE_SUMMARY:
   201 	case YUM_STATE_DESCRIPTION:
   202 	case YUM_STATE_URL:
   203 	case YUM_STATE_LICENSE:
   204 	case YUM_STATE_CHECKSUM:
   205 	case YUM_STATE_FILE:
   206 		ctx->state = YUM_STATE_BEGIN;
   207 		break;
   208 	}
   209 
   210 	if (strcmp(name, "package") == 0) {
   211 		razor_importer_add_details(ctx->importer, ctx->summary,
   212 					   ctx->description, ctx->url,
   213 					   ctx->license);
   214 
   215 		XML_StopParser(ctx->current_parser, XML_TRUE);
   216 		ctx->current_parser = ctx->filelists_parser;
   217 
   218 		printf("\rimporting %d/%d", ++ctx->current, ctx->total);
   219 		fflush(stdout);
   220 	}
   221 }
   222 
   223 static void
   224 yum_character_data (void *data, const XML_Char *s, int len)
   225 {
   226 	struct yum_context *ctx = data;
   227 
   228 	switch (ctx->state) {
   229 	case YUM_STATE_PACKAGE_NAME:
   230 	case YUM_STATE_PACKAGE_ARCH:
   231 	case YUM_STATE_SUMMARY:
   232 	case YUM_STATE_DESCRIPTION:
   233 	case YUM_STATE_URL:
   234 	case YUM_STATE_LICENSE:
   235 	case YUM_STATE_CHECKSUM:
   236 	case YUM_STATE_FILE:
   237 		memcpy(ctx->p, s, len);
   238 		ctx->p += len;
   239 		*ctx->p = '\0';
   240 		break;
   241 	}
   242 }
   243 
   244 static void
   245 yum_filelists_start_element(void *data, const char *name, const char **atts)
   246 {
   247 	struct yum_context *ctx = data;
   248 	const char *pkg, *pkgid;
   249 	int i;
   250 
   251 	if (strcmp(name, "package") == 0) {
   252 		pkg = NULL;
   253 		pkgid = NULL;
   254 		for (i = 0; atts[i]; i += 2) {
   255 			if (strcmp(atts[i], "name") == 0)
   256 				pkg = atts[i + 1];
   257 			else if (strcmp(atts[i], "pkgid") == 0)
   258 				pkgid = atts[i + 1];
   259 		}
   260 		if (strcmp(pkgid, ctx->pkgid) != 0)
   261 			fprintf(stderr, "primary.xml and filelists.xml "
   262 				"mismatch for %s: %s vs %s",
   263 				pkg, pkgid, ctx->pkgid);
   264 	} else if (strcmp(name, "file") == 0) {
   265 		ctx->state = YUM_STATE_FILE;
   266 		ctx->p = ctx->buffer;
   267 	}
   268 }
   269 
   270 
   271 static void
   272 yum_filelists_end_element (void *data, const char *name)
   273 {
   274 	struct yum_context *ctx = data;
   275 
   276 	ctx->state = YUM_STATE_BEGIN;
   277 	if (strcmp(name, "package") == 0) {
   278 		XML_StopParser(ctx->current_parser, XML_TRUE);
   279 		ctx->current_parser = ctx->primary_parser;
   280 		razor_importer_finish_package(ctx->importer);
   281 	} else if (strcmp(name, "file") == 0)
   282 		razor_importer_add_file(ctx->importer, ctx->buffer);
   283 
   284 }
   285 
   286 #define XML_BUFFER_SIZE 4096
   287 
   288 struct razor_set *
   289 razor_set_create_from_yum(void)
   290 {
   291 	struct yum_context ctx;
   292 	void *buf;
   293 	int len, ret;
   294 	gzFile primary, filelists;
   295 	XML_ParsingStatus status;
   296 
   297 	ctx.importer = razor_importer_create();
   298 	ctx.state = YUM_STATE_BEGIN;
   299 
   300 	ctx.primary_parser = XML_ParserCreate(NULL);
   301 	XML_SetUserData(ctx.primary_parser, &ctx);
   302 	XML_SetElementHandler(ctx.primary_parser,
   303 			      yum_primary_start_element,
   304 			      yum_primary_end_element);
   305 	XML_SetCharacterDataHandler(ctx.primary_parser,
   306 				    yum_character_data);
   307 
   308 	ctx.filelists_parser = XML_ParserCreate(NULL);
   309 	XML_SetUserData(ctx.filelists_parser, &ctx);
   310 	XML_SetElementHandler(ctx.filelists_parser,
   311 			      yum_filelists_start_element,
   312 			      yum_filelists_end_element);
   313 	XML_SetCharacterDataHandler(ctx.filelists_parser,
   314 				    yum_character_data);
   315 
   316 	primary = gzopen("primary.xml.gz", "rb");
   317 	if (primary == NULL)
   318 		return NULL;
   319 	filelists = gzopen("filelists.xml.gz", "rb");
   320 	if (filelists == NULL)
   321 		return NULL;
   322 
   323 	ctx.current_parser = ctx.primary_parser;
   324 
   325 	ctx.current = 0;
   326 
   327 	do {
   328 		XML_GetParsingStatus(ctx.current_parser, &status);
   329 		switch (status.parsing) {
   330 		case XML_SUSPENDED:
   331 			ret = XML_ResumeParser(ctx.current_parser);
   332 			break;
   333 		case XML_PARSING:
   334 		case XML_INITIALIZED:
   335 			buf = XML_GetBuffer(ctx.current_parser,
   336 					    XML_BUFFER_SIZE);
   337 			if (ctx.current_parser == ctx.primary_parser)
   338 				len = gzread(primary, buf, XML_BUFFER_SIZE);
   339 			else
   340 				len = gzread(filelists, buf, XML_BUFFER_SIZE);
   341 			if (len < 0) {
   342 				fprintf(stderr,
   343 					"couldn't read input: %s\n",
   344 					strerror(errno));
   345 				return NULL;
   346 			}
   347 
   348 			XML_ParseBuffer(ctx.current_parser, len, len == 0);
   349 			break;
   350 		case XML_FINISHED:
   351 			break;
   352 		}
   353 	} while (status.parsing != XML_FINISHED);
   354 
   355 
   356 	XML_ParserFree(ctx.primary_parser);
   357 	XML_ParserFree(ctx.filelists_parser);
   358 
   359 	gzclose(primary);
   360 	gzclose(filelists);
   361 
   362 	printf ("\nsaving\n");
   363 	return razor_importer_finish(ctx.importer);
   364 }