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