src/import-yum.c
author J. Ali Harlow <ali@juiblex.co.uk>
Sat Oct 04 18:12:58 2014 +0100 (2014-10-04)
changeset 454 56ff755c268c
parent 438 fab0b8a61dcb
child 455 df914f383f5c
permissions -rw-r--r--
Only export symbols starting with razor_ in dynamic library.

Apart from being good practice to avoid clashes with higher-level
libraries and the application, this also fixes an obscure bug: The
gnulib library is used both by librazor (the dynamic library) and
by razor (the executable). In doing so, we want to have two separate
copies of the library despite the code duplication this involves.
Without the explicit limit to export only razor_ symbols, the razor
executable under mingw64 was picking up the getopt_long function
from librazor and the optind variable from libgnu which meant that
it did not see optind changing. Hiding librazor's copy of getopt
causes the linker to find libgnu's copy and everything works.

Note that under mingw librazor-#.dll still contains undocumented
(private) razor_ symbols but these will do no harm as long as nobody
tries to use them.
     1 /*
     2  * Copyright (C) 2008  Kristian Høgsberg <krh@redhat.com>
     3  * Copyright (C) 2008  Red Hat, Inc
     4  *
     5  * This program is free software; you can redistribute it and/or modify
     6  * it under the terms of the GNU General Public License as published by
     7  * the Free Software Foundation; either version 2 of the License, or
     8  * (at your option) any later version.
     9  *
    10  * This program is distributed in the hope that it will be useful,
    11  * but WITHOUT ANY WARRANTY; without even the implied warranty of
    12  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
    13  * GNU General Public License for more details.
    14  *
    15  * You should have received a copy of the GNU General Public License along
    16  * with this program; if not, write to the Free Software Foundation, Inc.,
    17  * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
    18  */
    19 
    20 #define _GNU_SOURCE
    21 
    22 #include "config.h"
    23 #include <string.h>
    24 #include <stdio.h>
    25 #include <stdint.h>
    26 #include <sys/stat.h>
    27 #include <unistd.h>
    28 #include <fcntl.h>
    29 #include <errno.h>
    30 
    31 #include <expat.h>
    32 #include <zlib.h>
    33 #include "razor.h"
    34 
    35 /* Import a yum filelist as a razor package set. */
    36 
    37 enum {
    38 	YUM_STATE_BEGIN,
    39 	YUM_STATE_PACKAGE_NAME,
    40 	YUM_STATE_PACKAGE_ARCH,
    41 	YUM_STATE_SUMMARY,
    42 	YUM_STATE_DESCRIPTION,
    43 	YUM_STATE_URL,
    44 	YUM_STATE_LICENSE,
    45 	YUM_STATE_CHECKSUM,
    46 	YUM_STATE_REQUIRES,
    47 	YUM_STATE_PROVIDES,
    48 	YUM_STATE_OBSOLETES,
    49 	YUM_STATE_CONFLICTS,
    50 	YUM_STATE_FILE
    51 };
    52 
    53 struct yum_context {
    54 	XML_Parser primary_parser;
    55 	XML_Parser filelists_parser;
    56 	XML_Parser current_parser;
    57 
    58 	struct razor_importer *importer;
    59 	struct import_property_context *current_property_context;
    60 	char name[256], arch[64], summary[512], description[4096];
    61 	char url[256], license[64], buffer[512], *p;
    62 	char pkgid[128];
    63 	uint32_t property_type;
    64 	int state;
    65 
    66 	int total, current;
    67 };
    68 
    69 static uint32_t
    70 yum_to_razor_relation (const char *flags)
    71 {
    72 	if (flags[0] == 'L') {
    73 		if (flags[1] == 'T')
    74 			return RAZOR_PROPERTY_LESS;
    75 		else
    76 			return RAZOR_PROPERTY_LESS | RAZOR_PROPERTY_EQUAL;
    77 	} else if (flags[0] == 'G') {
    78 		if (flags[1] == 'T')
    79 			return RAZOR_PROPERTY_GREATER;
    80 		else
    81 			return RAZOR_PROPERTY_GREATER | RAZOR_PROPERTY_EQUAL;
    82 	} else
    83 		return RAZOR_PROPERTY_EQUAL;
    84 }
    85 
    86 static void
    87 yum_primary_start_element(void *data, const char *name, const char **atts)
    88 {
    89 	struct yum_context *ctx = data;
    90 	const char *n, *epoch, *version, *release;
    91 	char buffer[128];
    92 	uint32_t pre, relation, flags;
    93 	int i;
    94 
    95 	if (strcmp(name, "metadata") == 0) {
    96 		for (i = 0; atts[i]; i += 2) {
    97 			if (strcmp(atts[i], "packages") == 0)
    98 				ctx->total = atoi(atts[i + 1]);
    99 		}
   100 	} else if (strcmp(name, "name") == 0) {
   101 		ctx->state = YUM_STATE_PACKAGE_NAME;
   102 		ctx->p = ctx->name;
   103 	} else if (strcmp(name, "arch") == 0) {
   104 		ctx->state = YUM_STATE_PACKAGE_ARCH;
   105 		ctx->p = ctx->arch;
   106 	} else if (strcmp(name, "version") == 0) {
   107 		epoch = NULL;
   108 		version = NULL;
   109 		release = NULL;
   110 		for (i = 0; atts[i]; i += 2) {
   111 			if (strcmp(atts[i], "epoch") == 0)
   112 				epoch = atts[i + 1];
   113 			else if (strcmp(atts[i], "ver") == 0)
   114 				version = atts[i + 1];
   115 			else if (strcmp(atts[i], "rel") == 0)
   116 				release = atts[i + 1];
   117 		}
   118 		if (version == NULL || release == NULL) {
   119 			fprintf(stderr, "invalid version tag, "
   120 				"missing version or  release attribute\n");
   121 			return;
   122 		}
   123 
   124 		razor_build_evr(buffer, sizeof buffer, epoch, version, release);
   125 		razor_importer_begin_package(ctx->importer,
   126 					     ctx->name, buffer, ctx->arch);
   127 	} else if (strcmp(name, "summary") == 0) {
   128 		ctx->p = ctx->summary;
   129 		ctx->state = YUM_STATE_SUMMARY;
   130 	} else if (strcmp(name, "description") == 0) {
   131 		ctx->p = ctx->description;
   132 		ctx->state = YUM_STATE_DESCRIPTION;
   133 	} else if (strcmp(name, "url") == 0) {
   134 		ctx->p = ctx->url;
   135 		ctx->state = YUM_STATE_URL;
   136 	} else if (strcmp(name, "checksum") == 0) {
   137 		ctx->p = ctx->pkgid;
   138 		ctx->state = YUM_STATE_CHECKSUM;
   139 	} else if (strcmp(name, "rpm:license") == 0) {
   140 		ctx->p = ctx->license;
   141 		ctx->state = YUM_STATE_LICENSE;
   142 	} else if (strcmp(name, "rpm:requires") == 0) {
   143 		ctx->state = YUM_STATE_REQUIRES;
   144 		ctx->property_type = RAZOR_PROPERTY_REQUIRES;
   145 	} else if (strcmp(name, "rpm:provides") == 0) {
   146 		ctx->state = YUM_STATE_PROVIDES;
   147 		ctx->property_type = RAZOR_PROPERTY_PROVIDES;
   148 	} else if (strcmp(name, "rpm:obsoletes") == 0) {
   149 		ctx->state = YUM_STATE_OBSOLETES;
   150 		ctx->property_type = RAZOR_PROPERTY_OBSOLETES;
   151 	} else if (strcmp(name, "rpm:conflicts") == 0) {
   152 		ctx->state = YUM_STATE_CONFLICTS;
   153 		ctx->property_type = RAZOR_PROPERTY_CONFLICTS;
   154 	} else if (strcmp(name, "rpm:entry") == 0 &&
   155 		   ctx->state != YUM_STATE_BEGIN) {
   156 		n = NULL;
   157 		epoch = NULL;
   158 		version = NULL;
   159 		release = NULL;
   160 		relation = RAZOR_PROPERTY_EQUAL;
   161 		pre = 0;
   162 		for (i = 0; atts[i]; i += 2) {
   163 			if (strcmp(atts[i], "name") == 0)
   164 				n = atts[i + 1];
   165 			else if (strcmp(atts[i], "epoch") == 0)
   166 				epoch = atts[i + 1];
   167 			else if (strcmp(atts[i], "ver") == 0)
   168 				version = atts[i + 1];
   169 			else if (strcmp(atts[i], "rel") == 0)
   170 				release = atts[i + 1];
   171 			else if (strcmp(atts[i], "flags") == 0)
   172 				relation = yum_to_razor_relation(atts[i + 1]);
   173 			else if (strcmp(atts[i], "pre") == 0)
   174 				pre = RAZOR_PROPERTY_PRE;
   175 		}
   176 
   177 		if (n == NULL) {
   178 			fprintf(stderr, "invalid rpm:entry, "
   179 				"missing name or version attributes\n");
   180 			return;
   181 		}
   182 
   183 		razor_build_evr(buffer, sizeof buffer, epoch, version, release);
   184 		flags = ctx->property_type | relation | pre;
   185 		razor_importer_add_property(ctx->importer, n, flags, buffer);
   186 	}
   187 }
   188 
   189 static void
   190 yum_primary_end_element (void *data, const char *name)
   191 {
   192 	struct yum_context *ctx = data;
   193 
   194 	switch (ctx->state) {
   195 	case YUM_STATE_PACKAGE_NAME:
   196 	case YUM_STATE_PACKAGE_ARCH:
   197 	case YUM_STATE_SUMMARY:
   198 	case YUM_STATE_DESCRIPTION:
   199 	case YUM_STATE_URL:
   200 	case YUM_STATE_LICENSE:
   201 	case YUM_STATE_CHECKSUM:
   202 	case YUM_STATE_FILE:
   203 		ctx->state = YUM_STATE_BEGIN;
   204 		break;
   205 	}
   206 
   207 	if (strcmp(name, "package") == 0) {
   208 		razor_importer_add_details(ctx->importer, ctx->summary,
   209 					   ctx->description, ctx->url,
   210 					   ctx->license);
   211 
   212 		XML_StopParser(ctx->current_parser, XML_TRUE);
   213 		ctx->current_parser = ctx->filelists_parser;
   214 
   215 		printf("\rimporting %d/%d", ++ctx->current, ctx->total);
   216 		fflush(stdout);
   217 	}
   218 }
   219 
   220 static void
   221 yum_character_data (void *data, const XML_Char *s, int len)
   222 {
   223 	struct yum_context *ctx = data;
   224 
   225 	switch (ctx->state) {
   226 	case YUM_STATE_PACKAGE_NAME:
   227 	case YUM_STATE_PACKAGE_ARCH:
   228 	case YUM_STATE_SUMMARY:
   229 	case YUM_STATE_DESCRIPTION:
   230 	case YUM_STATE_URL:
   231 	case YUM_STATE_LICENSE:
   232 	case YUM_STATE_CHECKSUM:
   233 	case YUM_STATE_FILE:
   234 		memcpy(ctx->p, s, len);
   235 		ctx->p += len;
   236 		*ctx->p = '\0';
   237 		break;
   238 	}
   239 }
   240 
   241 static void
   242 yum_filelists_start_element(void *data, const char *name, const char **atts)
   243 {
   244 	struct yum_context *ctx = data;
   245 	const char *pkg, *pkgid;
   246 	int i;
   247 
   248 	if (strcmp(name, "package") == 0) {
   249 		pkg = NULL;
   250 		pkgid = NULL;
   251 		for (i = 0; atts[i]; i += 2) {
   252 			if (strcmp(atts[i], "name") == 0)
   253 				pkg = atts[i + 1];
   254 			else if (strcmp(atts[i], "pkgid") == 0)
   255 				pkgid = atts[i + 1];
   256 		}
   257 		if (strcmp(pkgid, ctx->pkgid) != 0)
   258 			fprintf(stderr, "primary.xml and filelists.xml "
   259 				"mismatch for %s: %s vs %s",
   260 				pkg, pkgid, ctx->pkgid);
   261 	} else if (strcmp(name, "file") == 0) {
   262 		ctx->state = YUM_STATE_FILE;
   263 		ctx->p = ctx->buffer;
   264 	}
   265 }
   266 
   267 
   268 static void
   269 yum_filelists_end_element (void *data, const char *name)
   270 {
   271 	struct yum_context *ctx = data;
   272 
   273 	ctx->state = YUM_STATE_BEGIN;
   274 	if (strcmp(name, "package") == 0) {
   275 		XML_StopParser(ctx->current_parser, XML_TRUE);
   276 		ctx->current_parser = ctx->primary_parser;
   277 		razor_importer_finish_package(ctx->importer);
   278 	} else if (strcmp(name, "file") == 0)
   279 		razor_importer_add_file(ctx->importer, ctx->buffer);
   280 
   281 }
   282 
   283 #define XML_BUFFER_SIZE 4096
   284 
   285 struct razor_set *
   286 razor_set_create_from_yum(void)
   287 {
   288 	struct yum_context ctx={0};
   289 	void *buf;
   290 	int len;
   291 	gzFile primary, filelists;
   292 	XML_ParsingStatus status;
   293 
   294 	ctx.importer = razor_importer_create();
   295 	ctx.state = YUM_STATE_BEGIN;
   296 
   297 	ctx.primary_parser = XML_ParserCreate(NULL);
   298 	XML_SetUserData(ctx.primary_parser, &ctx);
   299 	XML_SetElementHandler(ctx.primary_parser,
   300 			      yum_primary_start_element,
   301 			      yum_primary_end_element);
   302 	XML_SetCharacterDataHandler(ctx.primary_parser,
   303 				    yum_character_data);
   304 
   305 	ctx.filelists_parser = XML_ParserCreate(NULL);
   306 	XML_SetUserData(ctx.filelists_parser, &ctx);
   307 	XML_SetElementHandler(ctx.filelists_parser,
   308 			      yum_filelists_start_element,
   309 			      yum_filelists_end_element);
   310 	XML_SetCharacterDataHandler(ctx.filelists_parser,
   311 				    yum_character_data);
   312 
   313 	primary = gzopen("primary.xml.gz", "rb");
   314 	if (primary == NULL)
   315 		return NULL;
   316 	filelists = gzopen("filelists.xml.gz", "rb");
   317 	if (filelists == NULL)
   318 		return NULL;
   319 
   320 	ctx.current_parser = ctx.primary_parser;
   321 
   322 	ctx.current = 0;
   323 
   324 	do {
   325 		XML_GetParsingStatus(ctx.current_parser, &status);
   326 		switch (status.parsing) {
   327 		case XML_SUSPENDED:
   328 			XML_ResumeParser(ctx.current_parser);
   329 			break;
   330 		case XML_PARSING:
   331 		case XML_INITIALIZED:
   332 			buf = XML_GetBuffer(ctx.current_parser,
   333 					    XML_BUFFER_SIZE);
   334 			if (ctx.current_parser == ctx.primary_parser)
   335 				len = gzread(primary, buf, XML_BUFFER_SIZE);
   336 			else
   337 				len = gzread(filelists, buf, XML_BUFFER_SIZE);
   338 			if (len < 0) {
   339 				fprintf(stderr,
   340 					"couldn't read input: %s\n",
   341 					strerror(errno));
   342 				return NULL;
   343 			}
   344 
   345 			XML_ParseBuffer(ctx.current_parser, len, len == 0);
   346 			break;
   347 		case XML_FINISHED:
   348 			break;
   349 		}
   350 	} while (status.parsing != XML_FINISHED);
   351 
   352 
   353 	XML_ParserFree(ctx.primary_parser);
   354 	XML_ParserFree(ctx.filelists_parser);
   355 
   356 	gzclose(primary);
   357 	gzclose(filelists);
   358 
   359 	printf ("\nsaving\n");
   360 	return razor_importer_finish(ctx.importer);
   361 }