src/import-yum.c
author Kristian H?gsberg <krh@redhat.com>
Fri Jun 20 23:13:09 2008 -0400 (2008-06-20)
changeset 257 0c3db660514d
parent 247 63444a10fb8e
child 259 5b0601d184ed
permissions -rw-r--r--
When uniquifying properties, also sort them on the owning package.

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