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