yum.c
author Kristian H?gsberg <krh@jiraiya.boston.redhat.com>
Wed Apr 09 02:41:03 2008 -0400 (2008-04-09)
changeset 211 cf0ca962262b
parent 143 59a9513fac54
child 212 e8f493d8ff9a
permissions -rw-r--r--
Use the cpio headers instead of the rpm headers when unpacking.

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