src/import-yum.c
author J. Ali Harlow <ali@juiblex.co.uk>
Thu Feb 09 20:45:27 2012 +0000 (2012-02-09)
changeset 418 33b825d3128d
parent 394 afe520f454bd
child 438 fab0b8a61dcb
permissions -rw-r--r--
Add transaction barriers
These allow packages to be installed and removed which have scripts
that depend on each other when atomic transactions are involved.
Note that yum supports pre, but not other requires flags. post will
need similar support to the post scripts themselves pulling in the
requires flags from the rpms. Likewise preun and postun will need
similar handling to those scrips since the requires flags will need
to be stored in the razor database.
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 <unistd.h>
rhughes@241
    27
#include <fcntl.h>
rhughes@241
    28
#include <errno.h>
rhughes@241
    29
rhughes@241
    30
#include <expat.h>
rhughes@241
    31
#include <zlib.h>
rhughes@241
    32
#include "razor.h"
rhughes@241
    33
rhughes@241
    34
/* Import a yum filelist as a razor package set. */
rhughes@241
    35
rhughes@241
    36
enum {
rhughes@241
    37
	YUM_STATE_BEGIN,
rhughes@241
    38
	YUM_STATE_PACKAGE_NAME,
rhughes@241
    39
	YUM_STATE_PACKAGE_ARCH,
jbowes@258
    40
	YUM_STATE_SUMMARY,
jbowes@258
    41
	YUM_STATE_DESCRIPTION,
jbowes@258
    42
	YUM_STATE_URL,
jbowes@258
    43
	YUM_STATE_LICENSE,
rhughes@241
    44
	YUM_STATE_CHECKSUM,
rhughes@241
    45
	YUM_STATE_REQUIRES,
rhughes@241
    46
	YUM_STATE_PROVIDES,
rhughes@241
    47
	YUM_STATE_OBSOLETES,
rhughes@241
    48
	YUM_STATE_CONFLICTS,
rhughes@241
    49
	YUM_STATE_FILE
rhughes@241
    50
};
rhughes@241
    51
rhughes@241
    52
struct yum_context {
rhughes@241
    53
	XML_Parser primary_parser;
rhughes@241
    54
	XML_Parser filelists_parser;
rhughes@241
    55
	XML_Parser current_parser;
rhughes@241
    56
rhughes@241
    57
	struct razor_importer *importer;
rhughes@241
    58
	struct import_property_context *current_property_context;
jbowes@258
    59
	char name[256], arch[64], summary[512], description[4096];
jbowes@258
    60
	char url[256], license[64], buffer[512], *p;
rhughes@241
    61
	char pkgid[128];
krh@247
    62
	uint32_t property_type;
rhughes@241
    63
	int state;
jbowes@263
    64
jbowes@263
    65
	int total, current;
rhughes@241
    66
};
rhughes@241
    67
krh@247
    68
static uint32_t
krh@247
    69
yum_to_razor_relation (const char *flags)
rhughes@241
    70
{
rhughes@241
    71
	if (flags[0] == 'L') {
rhughes@241
    72
		if (flags[1] == 'T')
krh@247
    73
			return RAZOR_PROPERTY_LESS;
rhughes@241
    74
		else
krh@247
    75
			return RAZOR_PROPERTY_LESS | RAZOR_PROPERTY_EQUAL;
rhughes@241
    76
	} else if (flags[0] == 'G') {
rhughes@241
    77
		if (flags[1] == 'T')
krh@247
    78
			return RAZOR_PROPERTY_GREATER;
rhughes@241
    79
		else
krh@247
    80
			return RAZOR_PROPERTY_GREATER | RAZOR_PROPERTY_EQUAL;
rhughes@241
    81
	} else
krh@247
    82
		return RAZOR_PROPERTY_EQUAL;
rhughes@241
    83
}
rhughes@241
    84
rhughes@241
    85
static void
rhughes@241
    86
yum_primary_start_element(void *data, const char *name, const char **atts)
rhughes@241
    87
{
rhughes@241
    88
	struct yum_context *ctx = data;
krh@247
    89
	const char *n, *epoch, *version, *release;
rhughes@241
    90
	char buffer[128];
krh@247
    91
	uint32_t pre, relation, flags;
rhughes@241
    92
	int i;
rhughes@241
    93
jbowes@263
    94
	if (strcmp(name, "metadata") == 0) {
jbowes@263
    95
		for (i = 0; atts[i]; i += 2) {
jbowes@263
    96
			if (strcmp(atts[i], "packages") == 0)
jbowes@263
    97
				ctx->total = atoi(atts[i + 1]);
jbowes@263
    98
		}
jbowes@263
    99
	} else if (strcmp(name, "name") == 0) {
rhughes@241
   100
		ctx->state = YUM_STATE_PACKAGE_NAME;
rhughes@241
   101
		ctx->p = ctx->name;
rhughes@241
   102
	} else if (strcmp(name, "arch") == 0) {
rhughes@241
   103
		ctx->state = YUM_STATE_PACKAGE_ARCH;
rhughes@241
   104
		ctx->p = ctx->arch;
rhughes@241
   105
	} else if (strcmp(name, "version") == 0) {
rhughes@241
   106
		epoch = NULL;
rhughes@241
   107
		version = NULL;
rhughes@241
   108
		release = NULL;
rhughes@241
   109
		for (i = 0; atts[i]; i += 2) {
rhughes@241
   110
			if (strcmp(atts[i], "epoch") == 0)
rhughes@241
   111
				epoch = atts[i + 1];
rhughes@241
   112
			else if (strcmp(atts[i], "ver") == 0)
rhughes@241
   113
				version = atts[i + 1];
rhughes@241
   114
			else if (strcmp(atts[i], "rel") == 0)
rhughes@241
   115
				release = atts[i + 1];
rhughes@241
   116
		}
rhughes@241
   117
		if (version == NULL || release == NULL) {
rhughes@241
   118
			fprintf(stderr, "invalid version tag, "
rhughes@241
   119
				"missing version or  release attribute\n");
rhughes@241
   120
			return;
rhughes@241
   121
		}
rhughes@241
   122
rhughes@241
   123
		razor_build_evr(buffer, sizeof buffer, epoch, version, release);
rhughes@241
   124
		razor_importer_begin_package(ctx->importer,
rhughes@241
   125
					     ctx->name, buffer, ctx->arch);
jbowes@258
   126
	} else if (strcmp(name, "summary") == 0) {
jbowes@258
   127
		ctx->p = ctx->summary;
jbowes@258
   128
		ctx->state = YUM_STATE_SUMMARY;
jbowes@258
   129
	} else if (strcmp(name, "description") == 0) {
jbowes@258
   130
		ctx->p = ctx->description;
jbowes@258
   131
		ctx->state = YUM_STATE_DESCRIPTION;
jbowes@258
   132
	} else if (strcmp(name, "url") == 0) {
jbowes@258
   133
		ctx->p = ctx->url;
jbowes@258
   134
		ctx->state = YUM_STATE_URL;
rhughes@241
   135
	} else if (strcmp(name, "checksum") == 0) {
rhughes@241
   136
		ctx->p = ctx->pkgid;
rhughes@241
   137
		ctx->state = YUM_STATE_CHECKSUM;
jbowes@258
   138
	} else if (strcmp(name, "rpm:license") == 0) {
jbowes@258
   139
		ctx->p = ctx->license;
jbowes@258
   140
		ctx->state = YUM_STATE_LICENSE;
rhughes@241
   141
	} else if (strcmp(name, "rpm:requires") == 0) {
rhughes@241
   142
		ctx->state = YUM_STATE_REQUIRES;
krh@247
   143
		ctx->property_type = RAZOR_PROPERTY_REQUIRES;
rhughes@241
   144
	} else if (strcmp(name, "rpm:provides") == 0) {
rhughes@241
   145
		ctx->state = YUM_STATE_PROVIDES;
krh@247
   146
		ctx->property_type = RAZOR_PROPERTY_PROVIDES;
rhughes@241
   147
	} else if (strcmp(name, "rpm:obsoletes") == 0) {
rhughes@241
   148
		ctx->state = YUM_STATE_OBSOLETES;
krh@247
   149
		ctx->property_type = RAZOR_PROPERTY_OBSOLETES;
rhughes@241
   150
	} else if (strcmp(name, "rpm:conflicts") == 0) {
rhughes@241
   151
		ctx->state = YUM_STATE_CONFLICTS;
krh@247
   152
		ctx->property_type = RAZOR_PROPERTY_CONFLICTS;
rhughes@241
   153
	} else if (strcmp(name, "rpm:entry") == 0 &&
rhughes@241
   154
		   ctx->state != YUM_STATE_BEGIN) {
rhughes@241
   155
		n = NULL;
rhughes@241
   156
		epoch = NULL;
rhughes@241
   157
		version = NULL;
rhughes@241
   158
		release = NULL;
krh@247
   159
		relation = RAZOR_PROPERTY_EQUAL;
krh@247
   160
		pre = 0;
rhughes@241
   161
		for (i = 0; atts[i]; i += 2) {
rhughes@241
   162
			if (strcmp(atts[i], "name") == 0)
rhughes@241
   163
				n = atts[i + 1];
rhughes@241
   164
			else if (strcmp(atts[i], "epoch") == 0)
rhughes@241
   165
				epoch = atts[i + 1];
rhughes@241
   166
			else if (strcmp(atts[i], "ver") == 0)
rhughes@241
   167
				version = atts[i + 1];
rhughes@241
   168
			else if (strcmp(atts[i], "rel") == 0)
rhughes@241
   169
				release = atts[i + 1];
rhughes@241
   170
			else if (strcmp(atts[i], "flags") == 0)
krh@247
   171
				relation = yum_to_razor_relation(atts[i + 1]);
krh@247
   172
			else if (strcmp(atts[i], "pre") == 0)
ali@418
   173
				pre = RAZOR_PROPERTY_PRE;
rhughes@241
   174
		}
rhughes@241
   175
rhughes@241
   176
		if (n == NULL) {
rhughes@241
   177
			fprintf(stderr, "invalid rpm:entry, "
rhughes@241
   178
				"missing name or version attributes\n");
rhughes@241
   179
			return;
rhughes@241
   180
		}
rhughes@241
   181
rhughes@241
   182
		razor_build_evr(buffer, sizeof buffer, epoch, version, release);
krh@247
   183
		flags = ctx->property_type | relation | pre;
krh@247
   184
		razor_importer_add_property(ctx->importer, n, flags, buffer);
rhughes@241
   185
	}
rhughes@241
   186
}
rhughes@241
   187
rhughes@241
   188
static void
rhughes@241
   189
yum_primary_end_element (void *data, const char *name)
rhughes@241
   190
{
rhughes@241
   191
	struct yum_context *ctx = data;
rhughes@241
   192
rhughes@241
   193
	switch (ctx->state) {
rhughes@241
   194
	case YUM_STATE_PACKAGE_NAME:
rhughes@241
   195
	case YUM_STATE_PACKAGE_ARCH:
jbowes@258
   196
	case YUM_STATE_SUMMARY:
jbowes@258
   197
	case YUM_STATE_DESCRIPTION:
jbowes@258
   198
	case YUM_STATE_URL:
jbowes@258
   199
	case YUM_STATE_LICENSE:
rhughes@241
   200
	case YUM_STATE_CHECKSUM:
rhughes@241
   201
	case YUM_STATE_FILE:
rhughes@241
   202
		ctx->state = YUM_STATE_BEGIN;
rhughes@241
   203
		break;
rhughes@241
   204
	}
rhughes@241
   205
rhughes@241
   206
	if (strcmp(name, "package") == 0) {
jbowes@258
   207
		razor_importer_add_details(ctx->importer, ctx->summary,
jbowes@258
   208
					   ctx->description, ctx->url,
jbowes@258
   209
					   ctx->license);
jbowes@258
   210
rhughes@241
   211
		XML_StopParser(ctx->current_parser, XML_TRUE);
rhughes@241
   212
		ctx->current_parser = ctx->filelists_parser;
jbowes@263
   213
jbowes@263
   214
		printf("\rimporting %d/%d", ++ctx->current, ctx->total);
jbowes@263
   215
		fflush(stdout);
rhughes@241
   216
	}
rhughes@241
   217
}
rhughes@241
   218
rhughes@241
   219
static void
rhughes@241
   220
yum_character_data (void *data, const XML_Char *s, int len)
rhughes@241
   221
{
rhughes@241
   222
	struct yum_context *ctx = data;
rhughes@241
   223
rhughes@241
   224
	switch (ctx->state) {
rhughes@241
   225
	case YUM_STATE_PACKAGE_NAME:
rhughes@241
   226
	case YUM_STATE_PACKAGE_ARCH:
jbowes@258
   227
	case YUM_STATE_SUMMARY:
jbowes@258
   228
	case YUM_STATE_DESCRIPTION:
jbowes@258
   229
	case YUM_STATE_URL:
jbowes@258
   230
	case YUM_STATE_LICENSE:
rhughes@241
   231
	case YUM_STATE_CHECKSUM:
rhughes@241
   232
	case YUM_STATE_FILE:
rhughes@241
   233
		memcpy(ctx->p, s, len);
rhughes@241
   234
		ctx->p += len;
rhughes@241
   235
		*ctx->p = '\0';
rhughes@241
   236
		break;
rhughes@241
   237
	}
rhughes@241
   238
}
rhughes@241
   239
rhughes@241
   240
static void
rhughes@241
   241
yum_filelists_start_element(void *data, const char *name, const char **atts)
rhughes@241
   242
{
rhughes@241
   243
	struct yum_context *ctx = data;
rhughes@241
   244
	const char *pkg, *pkgid;
rhughes@241
   245
	int i;
rhughes@241
   246
rhughes@241
   247
	if (strcmp(name, "package") == 0) {
rhughes@241
   248
		pkg = NULL;
rhughes@241
   249
		pkgid = NULL;
rhughes@241
   250
		for (i = 0; atts[i]; i += 2) {
rhughes@241
   251
			if (strcmp(atts[i], "name") == 0)
rhughes@241
   252
				pkg = atts[i + 1];
rhughes@241
   253
			else if (strcmp(atts[i], "pkgid") == 0)
rhughes@241
   254
				pkgid = atts[i + 1];
rhughes@241
   255
		}
rhughes@241
   256
		if (strcmp(pkgid, ctx->pkgid) != 0)
rhughes@241
   257
			fprintf(stderr, "primary.xml and filelists.xml "
rhughes@241
   258
				"mismatch for %s: %s vs %s",
rhughes@241
   259
				pkg, pkgid, ctx->pkgid);
rhughes@241
   260
	} else if (strcmp(name, "file") == 0) {
rhughes@241
   261
		ctx->state = YUM_STATE_FILE;
rhughes@241
   262
		ctx->p = ctx->buffer;
rhughes@241
   263
	}
rhughes@241
   264
}
rhughes@241
   265
rhughes@241
   266
rhughes@241
   267
static void
rhughes@241
   268
yum_filelists_end_element (void *data, const char *name)
rhughes@241
   269
{
rhughes@241
   270
	struct yum_context *ctx = data;
rhughes@241
   271
rhughes@241
   272
	ctx->state = YUM_STATE_BEGIN;
rhughes@241
   273
	if (strcmp(name, "package") == 0) {
rhughes@241
   274
		XML_StopParser(ctx->current_parser, XML_TRUE);
rhughes@241
   275
		ctx->current_parser = ctx->primary_parser;
rhughes@241
   276
		razor_importer_finish_package(ctx->importer);
rhughes@241
   277
	} else if (strcmp(name, "file") == 0)
rhughes@241
   278
		razor_importer_add_file(ctx->importer, ctx->buffer);
rhughes@241
   279
rhughes@241
   280
}
rhughes@241
   281
rhughes@241
   282
#define XML_BUFFER_SIZE 4096
rhughes@241
   283
rhughes@241
   284
struct razor_set *
rhughes@241
   285
razor_set_create_from_yum(void)
rhughes@241
   286
{
ali@394
   287
	struct yum_context ctx={0};
rhughes@241
   288
	void *buf;
rhughes@241
   289
	int len, ret;
rhughes@241
   290
	gzFile primary, filelists;
rhughes@241
   291
	XML_ParsingStatus status;
rhughes@241
   292
krh@249
   293
	ctx.importer = razor_importer_create();
rhughes@241
   294
	ctx.state = YUM_STATE_BEGIN;
rhughes@241
   295
rhughes@241
   296
	ctx.primary_parser = XML_ParserCreate(NULL);
rhughes@241
   297
	XML_SetUserData(ctx.primary_parser, &ctx);
rhughes@241
   298
	XML_SetElementHandler(ctx.primary_parser,
rhughes@241
   299
			      yum_primary_start_element,
rhughes@241
   300
			      yum_primary_end_element);
rhughes@241
   301
	XML_SetCharacterDataHandler(ctx.primary_parser,
rhughes@241
   302
				    yum_character_data);
rhughes@241
   303
rhughes@241
   304
	ctx.filelists_parser = XML_ParserCreate(NULL);
rhughes@241
   305
	XML_SetUserData(ctx.filelists_parser, &ctx);
rhughes@241
   306
	XML_SetElementHandler(ctx.filelists_parser,
rhughes@241
   307
			      yum_filelists_start_element,
rhughes@241
   308
			      yum_filelists_end_element);
rhughes@241
   309
	XML_SetCharacterDataHandler(ctx.filelists_parser,
rhughes@241
   310
				    yum_character_data);
rhughes@241
   311
rhughes@241
   312
	primary = gzopen("primary.xml.gz", "rb");
rhughes@241
   313
	if (primary == NULL)
rhughes@241
   314
		return NULL;
rhughes@241
   315
	filelists = gzopen("filelists.xml.gz", "rb");
rhughes@241
   316
	if (filelists == NULL)
rhughes@241
   317
		return NULL;
rhughes@241
   318
rhughes@241
   319
	ctx.current_parser = ctx.primary_parser;
rhughes@241
   320
jbowes@263
   321
	ctx.current = 0;
jbowes@263
   322
rhughes@241
   323
	do {
rhughes@241
   324
		XML_GetParsingStatus(ctx.current_parser, &status);
rhughes@241
   325
		switch (status.parsing) {
rhughes@241
   326
		case XML_SUSPENDED:
rhughes@241
   327
			ret = XML_ResumeParser(ctx.current_parser);
rhughes@241
   328
			break;
rhughes@241
   329
		case XML_PARSING:
rhughes@241
   330
		case XML_INITIALIZED:
rhughes@241
   331
			buf = XML_GetBuffer(ctx.current_parser,
rhughes@241
   332
					    XML_BUFFER_SIZE);
rhughes@241
   333
			if (ctx.current_parser == ctx.primary_parser)
rhughes@241
   334
				len = gzread(primary, buf, XML_BUFFER_SIZE);
rhughes@241
   335
			else
rhughes@241
   336
				len = gzread(filelists, buf, XML_BUFFER_SIZE);
rhughes@241
   337
			if (len < 0) {
rhughes@241
   338
				fprintf(stderr,
rhughes@241
   339
					"couldn't read input: %s\n",
rhughes@241
   340
					strerror(errno));
rhughes@241
   341
				return NULL;
rhughes@241
   342
			}
rhughes@241
   343
rhughes@241
   344
			XML_ParseBuffer(ctx.current_parser, len, len == 0);
rhughes@241
   345
			break;
rhughes@241
   346
		case XML_FINISHED:
rhughes@241
   347
			break;
rhughes@241
   348
		}
rhughes@241
   349
	} while (status.parsing != XML_FINISHED);
rhughes@241
   350
rhughes@241
   351
rhughes@241
   352
	XML_ParserFree(ctx.primary_parser);
rhughes@241
   353
	XML_ParserFree(ctx.filelists_parser);
rhughes@241
   354
rhughes@241
   355
	gzclose(primary);
rhughes@241
   356
	gzclose(filelists);
rhughes@241
   357
jbowes@263
   358
	printf ("\nsaving\n");
rhughes@241
   359
	return razor_importer_finish(ctx.importer);
rhughes@241
   360
}