src/import-yum.c
author Kristian H?gsberg <krh@redhat.com>
Fri Jun 20 21:56:43 2008 -0400 (2008-06-20)
changeset 254 ccb1c11968ab
parent 247 63444a10fb8e
child 259 5b0601d184ed
permissions -rw-r--r--
Introduce install/remove iterators.

These iterator constructors lets you pass in two sets and creates
an iterator for the packages to remove or the packages to install.
The iterators will step through the packages in a sequence that respects
the pre, post, preun and postun modifiers.

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