import.c
author Kristian H?gsberg <krh@redhat.com>
Wed Sep 19 14:09:03 2007 -0400 (2007-09-19)
changeset 28 c8958f67afd8
parent 27 5dbd81809d26
child 30 702c01e59497
permissions -rw-r--r--
Add importer for system rpm database.
krh@27
     1
#define _GNU_SOURCE
krh@27
     2
krh@27
     3
#include <string.h>
krh@27
     4
#include <stdio.h>
krh@27
     5
#include <sys/stat.h>
krh@27
     6
#include <sys/mman.h>
krh@27
     7
#include <unistd.h>
krh@27
     8
#include <fcntl.h>
krh@27
     9
#include <errno.h>
krh@27
    10
krh@27
    11
#include <expat.h>
krh@28
    12
#include <rpm/rpmlib.h>
krh@28
    13
#include <rpm/rpmdb.h>
krh@27
    14
#include "sha1.h"
krh@27
    15
#include "razor.h"
krh@27
    16
krh@27
    17
static void
krh@27
    18
parse_package(struct import_context *ctx, const char **atts, void *data)
krh@27
    19
{
krh@27
    20
	const char *name = NULL, *version = NULL;
krh@27
    21
	int i;
krh@27
    22
krh@27
    23
	for (i = 0; atts[i]; i += 2) {
krh@27
    24
		if (strcmp(atts[i], "name") == 0)
krh@27
    25
			name = atts[i + 1];
krh@27
    26
		else if (strcmp(atts[i], "version") == 0)
krh@27
    27
			version = atts[i + 1];
krh@27
    28
	}
krh@27
    29
krh@27
    30
	if (name == NULL || version == NULL) {
krh@27
    31
		fprintf(stderr, "invalid package tag, "
krh@27
    32
			"missing name or version attributes\n");
krh@27
    33
		return;
krh@27
    34
	}
krh@27
    35
krh@27
    36
	import_context_add_package(ctx, name, version);
krh@27
    37
}
krh@27
    38
krh@27
    39
static void
krh@27
    40
parse_property(struct import_context *ctx, const char **atts, void *data)
krh@27
    41
{
krh@27
    42
	const char *name = NULL, *version = NULL;
krh@27
    43
	int i;
krh@27
    44
krh@27
    45
	for (i = 0; atts[i]; i += 2) {
krh@27
    46
		if (strcmp(atts[i], "name") == 0)
krh@27
    47
			name = atts[i + 1];
krh@27
    48
		if (strcmp(atts[i], "version") == 0)
krh@27
    49
			version = atts[i + 1];
krh@27
    50
	}
krh@27
    51
	
krh@27
    52
	if (name == NULL) {
krh@27
    53
		fprintf(stderr, "invalid tag, missing name attribute\n");
krh@27
    54
		return;
krh@27
    55
	}
krh@27
    56
krh@27
    57
	import_context_add_property(ctx, data, name, version);
krh@27
    58
}
krh@27
    59
krh@27
    60
static void
krh@27
    61
start_element(void *data, const char *name, const char **atts)
krh@27
    62
{
krh@27
    63
	struct import_context *ctx = data;
krh@27
    64
krh@27
    65
	if (strcmp(name, "package") == 0)
krh@27
    66
		parse_package(ctx, atts, NULL);
krh@27
    67
	else if (strcmp(name, "requires") == 0)
krh@27
    68
		parse_property(ctx, atts, &ctx->requires);
krh@27
    69
	else if (strcmp(name, "provides") == 0)
krh@27
    70
		parse_property(ctx, atts, &ctx->provides);
krh@27
    71
}
krh@27
    72
krh@27
    73
static void
krh@27
    74
end_element (void *data, const char *name)
krh@27
    75
{
krh@27
    76
	struct import_context *ctx = data;
krh@27
    77
krh@27
    78
	if (strcmp(name, "package") == 0)
krh@27
    79
		import_context_finish_package(ctx);
krh@27
    80
}
krh@27
    81
krh@27
    82
static int
krh@27
    83
import_rzr_file(struct import_context *ctx, const char *filename)
krh@27
    84
{
krh@27
    85
	SHA_CTX sha1;
krh@27
    86
	XML_Parser parser;
krh@27
    87
	int fd;
krh@27
    88
	void *p;
krh@27
    89
	struct stat stat;
krh@27
    90
	unsigned char hash[20];
krh@27
    91
krh@27
    92
	fd = open(filename, O_RDONLY);
krh@27
    93
	if (fstat(fd, &stat) < 0)
krh@27
    94
		return -1;
krh@27
    95
	p = mmap(NULL, stat.st_size, PROT_READ, MAP_PRIVATE, fd, 0);
krh@27
    96
	if (p == MAP_FAILED)
krh@27
    97
		return -1;
krh@27
    98
krh@27
    99
	parser = XML_ParserCreate(NULL);
krh@27
   100
	XML_SetUserData(parser, ctx);
krh@27
   101
	XML_SetElementHandler(parser, start_element, end_element);
krh@27
   102
	if (XML_Parse(parser, p, stat.st_size, 1) == XML_STATUS_ERROR) {
krh@27
   103
		fprintf(stderr,
krh@27
   104
			"%s at line %d, %s\n",
krh@27
   105
			XML_ErrorString(XML_GetErrorCode(parser)),
krh@27
   106
			XML_GetCurrentLineNumber(parser),
krh@27
   107
			filename);
krh@27
   108
		return 1;
krh@27
   109
	}
krh@27
   110
krh@27
   111
	XML_ParserFree(parser);
krh@27
   112
krh@27
   113
	SHA1_Init(&sha1);
krh@27
   114
	SHA1_Update(&sha1, p, stat.st_size);
krh@27
   115
	SHA1_Final(hash, &sha1);
krh@27
   116
krh@27
   117
	close(fd);
krh@27
   118
krh@27
   119
	munmap(p, stat.st_size);
krh@27
   120
krh@27
   121
	return 0;
krh@27
   122
}
krh@27
   123
krh@27
   124
struct razor_set *
krh@27
   125
razor_import_rzr_files(int count, const char *files[])
krh@27
   126
{
krh@27
   127
	struct import_context ctx;
krh@27
   128
	int i;
krh@27
   129
krh@27
   130
	razor_prepare_import(&ctx);
krh@27
   131
krh@27
   132
	for (i = 0; i < count; i++) {
krh@27
   133
		if (import_rzr_file(&ctx, files[i]) < 0) {
krh@27
   134
			fprintf(stderr, "failed to import %s\n", files[i]);
krh@27
   135
			exit(-1);
krh@27
   136
		}
krh@27
   137
	}
krh@27
   138
krh@27
   139
	return razor_finish_import(&ctx);
krh@27
   140
}
krh@27
   141
krh@27
   142
/* Import a yum filelist as a razor package set. */
krh@27
   143
krh@27
   144
enum {
krh@27
   145
	YUM_STATE_BEGIN,
krh@27
   146
	YUM_STATE_PACKAGE_NAME
krh@27
   147
};
krh@27
   148
krh@27
   149
struct yum_context {
krh@27
   150
	struct import_context ctx;
krh@27
   151
	struct import_property_context *current_property_context;
krh@27
   152
	char *name;
krh@27
   153
	int state;
krh@27
   154
};
krh@27
   155
krh@27
   156
static void
krh@27
   157
yum_start_element(void *data, const char *name, const char **atts)
krh@27
   158
{
krh@27
   159
	struct yum_context *ctx = data;
krh@27
   160
	const char *n, *version;
krh@27
   161
	int i;
krh@27
   162
krh@27
   163
	if (strcmp(name, "name") == 0) {
krh@27
   164
		ctx->state = YUM_STATE_PACKAGE_NAME;
krh@27
   165
	} else if (strcmp(name, "version") == 0) {
krh@27
   166
		version = NULL;
krh@27
   167
		for (i = 0; atts[i]; i += 2) {
krh@27
   168
			if (strcmp(atts[i], "ver") == 0)
krh@27
   169
				version = atts[i + 1];
krh@27
   170
		}
krh@27
   171
		import_context_add_package(&ctx->ctx, ctx->name, version);
krh@27
   172
	} else if (strcmp(name, "rpm:requires") == 0) {
krh@27
   173
		ctx->current_property_context = &ctx->ctx.requires;
krh@27
   174
	} else if (strcmp(name, "rpm:provides") == 0) {
krh@27
   175
		ctx->current_property_context = &ctx->ctx.provides;
krh@27
   176
	} else if (strcmp(name, "rpm:entry") == 0 &&
krh@27
   177
		   ctx->current_property_context != NULL) {
krh@27
   178
		n = NULL;
krh@27
   179
		version = NULL;
krh@27
   180
		for (i = 0; atts[i]; i += 2) {
krh@27
   181
			if (strcmp(atts[i], "name") == 0)
krh@27
   182
				n = atts[i + 1];
krh@27
   183
			else if (strcmp(atts[i], "ver") == 0)
krh@27
   184
				version = atts[i + 1];
krh@27
   185
		}
krh@27
   186
krh@27
   187
		if (n == NULL) {
krh@27
   188
			fprintf(stderr, "invalid rpm:entry, "
krh@27
   189
				"missing name or version attributes\n");
krh@27
   190
			return;
krh@27
   191
		}
krh@27
   192
krh@27
   193
		import_context_add_property(&ctx->ctx,
krh@27
   194
					    ctx->current_property_context,
krh@27
   195
					    n, version);
krh@27
   196
	}
krh@27
   197
}
krh@27
   198
krh@27
   199
static void
krh@27
   200
yum_end_element (void *data, const char *name)
krh@27
   201
{
krh@27
   202
	struct yum_context *ctx = data;
krh@27
   203
krh@27
   204
	if (strcmp(name, "package") == 0) {
krh@27
   205
		free(ctx->name);
krh@27
   206
		import_context_finish_package(&ctx->ctx);
krh@27
   207
	} else if (strcmp(name, "name") == 0) {
krh@27
   208
		ctx->state = 0;
krh@27
   209
	} else if (strcmp(name, "rpm:requires") == 0) {
krh@27
   210
		ctx->current_property_context = NULL;
krh@27
   211
	} else if (strcmp(name, "rpm:provides") == 0) {
krh@27
   212
		ctx->current_property_context = NULL;
krh@27
   213
	}
krh@27
   214
}
krh@27
   215
krh@27
   216
static void
krh@27
   217
yum_character_data (void *data, const XML_Char *s, int len)
krh@27
   218
{
krh@27
   219
	struct yum_context *ctx = data;
krh@27
   220
krh@27
   221
	if (ctx->state == YUM_STATE_PACKAGE_NAME)
krh@27
   222
		ctx->name = strndup(s, len);
krh@27
   223
}
krh@27
   224
krh@27
   225
struct razor_set *
krh@27
   226
razor_set_create_from_yum_filelist(int fd)
krh@27
   227
{
krh@27
   228
	struct yum_context ctx;
krh@27
   229
	XML_Parser parser;
krh@27
   230
	char buf[4096];
krh@27
   231
	int len;
krh@27
   232
krh@27
   233
	razor_prepare_import(&ctx.ctx);
krh@27
   234
krh@27
   235
	parser = XML_ParserCreate(NULL);
krh@27
   236
	XML_SetUserData(parser, &ctx);
krh@27
   237
	XML_SetElementHandler(parser, yum_start_element, yum_end_element);
krh@27
   238
	XML_SetCharacterDataHandler(parser, yum_character_data);
krh@27
   239
krh@27
   240
	while (1) {
krh@27
   241
		len = read(fd, buf, sizeof buf);
krh@27
   242
		if (len < 0) {
krh@27
   243
			fprintf(stderr,
krh@27
   244
				"couldn't read input: %s\n", strerror(errno));
krh@27
   245
			return NULL;
krh@27
   246
		} else if (len == 0)
krh@27
   247
			break;
krh@27
   248
krh@27
   249
		if (XML_Parse(parser, buf, len, 0) == XML_STATUS_ERROR) {
krh@27
   250
			fprintf(stderr,
krh@27
   251
				"%s at line %d\n",
krh@27
   252
				XML_ErrorString(XML_GetErrorCode(parser)),
krh@27
   253
				XML_GetCurrentLineNumber(parser));
krh@27
   254
			return NULL;
krh@27
   255
		}
krh@27
   256
	}
krh@27
   257
krh@27
   258
	XML_ParserFree(parser);
krh@27
   259
krh@27
   260
	return razor_finish_import(&ctx.ctx);
krh@27
   261
}
krh@28
   262
krh@28
   263
struct razor_set *
krh@28
   264
razor_set_create_from_rpmdb(void)
krh@28
   265
{
krh@28
   266
	struct import_context ctx;
krh@28
   267
	rpmdbMatchIterator iter;
krh@28
   268
	Header h;
krh@28
   269
	int_32 type, count, i;
krh@28
   270
	char *name, *version, *release;
krh@28
   271
	char **properties, **property_versions;
krh@28
   272
	rpmdb db;
krh@28
   273
krh@28
   274
	rpmReadConfigFiles(NULL, NULL);
krh@28
   275
krh@28
   276
	if (rpmdbOpen("", &db, O_RDONLY, 0644) != 0) {
krh@28
   277
		fprintf(stderr, "cannot open rpm database\n");
krh@28
   278
		exit(1);
krh@28
   279
	}
krh@28
   280
krh@28
   281
	razor_prepare_import(&ctx);
krh@28
   282
krh@28
   283
	iter = rpmdbInitIterator(db, 0, NULL, 0);
krh@28
   284
	while (h = rpmdbNextIterator(iter), h != NULL) {
krh@28
   285
		headerGetEntry(h, RPMTAG_NAME, &type,
krh@28
   286
			       (void **) &name, &count);
krh@28
   287
		headerGetEntry(h, RPMTAG_VERSION, &type,
krh@28
   288
			       (void **) &version, &count);
krh@28
   289
		headerGetEntry(h, RPMTAG_RELEASE, &type,
krh@28
   290
			       (void **) &release, &count);
krh@28
   291
		import_context_add_package(&ctx, name, version);
krh@28
   292
krh@28
   293
krh@28
   294
		headerGetEntry(h, RPMTAG_REQUIRES, &type,
krh@28
   295
			       (void **) &properties, &count);
krh@28
   296
		headerGetEntry(h, RPMTAG_REQUIREVERSION, &type,
krh@28
   297
			       (void **) &property_versions, &count);
krh@28
   298
		for (i = 0; i < count; i++)
krh@28
   299
			import_context_add_property(&ctx,
krh@28
   300
						    &ctx.requires,
krh@28
   301
						    properties[i],
krh@28
   302
						    property_versions[i]);
krh@28
   303
krh@28
   304
		headerGetEntry(h, RPMTAG_PROVIDES, &type,
krh@28
   305
			       (void **) &properties, &count);
krh@28
   306
		headerGetEntry(h, RPMTAG_PROVIDEVERSION, &type,
krh@28
   307
			       (void **) &property_versions, &count);
krh@28
   308
		for (i = 0; i < count; i++)
krh@28
   309
			import_context_add_property(&ctx,
krh@28
   310
						    &ctx.provides,
krh@28
   311
						    properties[i],
krh@28
   312
						    property_versions[i]);
krh@28
   313
krh@28
   314
		import_context_finish_package(&ctx);
krh@28
   315
	}
krh@28
   316
krh@28
   317
	rpmdbClose(db);
krh@28
   318
krh@28
   319
	return razor_finish_import(&ctx);
krh@28
   320
}