yum.c
author Dan Winship <danw@gnome.org>
Fri Feb 29 12:45:08 2008 -0500 (2008-02-29)
changeset 138 49deac048d07
child 143 59a9513fac54
permissions -rw-r--r--
implement file dependencies for installs

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