src/import-yum.c
author James Bowes <jbowes@redhat.com>
Wed Jul 09 10:11:13 2008 -0400 (2008-07-09)
changeset 318 829d6711b316
parent 259 5b0601d184ed
child 333 1829493b5fb9
permissions -rw-r--r--
Use strings to identify section types in the on-disk repo format.

Previously, a given razor file type had a fixed number of sections in a
fixed order, identified by an integer type. Now, sections are identified
by a named string (stored in a string pool after the section lists).

This will allow for razor files to contain arbitrary sections.

For bonus points, also drop the 4k section alignment and change the
magic byte string to "RZDB".

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