danw@109: #define _GNU_SOURCE danw@109: danw@109: #include danw@109: #include danw@109: #include danw@109: #include danw@109: #include danw@109: #include danw@109: #include danw@109: danw@109: #include danw@109: #include danw@109: #include "razor.h" danw@109: danw@109: /* Import a yum filelist as a razor package set. */ danw@109: danw@109: enum { danw@109: YUM_STATE_BEGIN, danw@109: YUM_STATE_PACKAGE_NAME, danw@109: YUM_STATE_CHECKSUM, danw@109: YUM_STATE_REQUIRES, danw@109: YUM_STATE_PROVIDES, danw@109: YUM_STATE_OBSOLETES, danw@109: YUM_STATE_CONFLICTS, danw@109: YUM_STATE_FILE danw@109: }; danw@109: danw@109: struct yum_context { danw@109: XML_Parser primary_parser; danw@109: XML_Parser filelists_parser; danw@109: XML_Parser current_parser; danw@109: danw@109: struct razor_importer *importer; danw@109: struct import_property_context *current_property_context; danw@109: char name[256], buffer[512], *p; danw@109: char pkgid[128]; danw@109: int state; danw@109: }; danw@109: danw@109: static enum razor_version_relation danw@109: yum_to_razor_flags (const char *flags) danw@109: { danw@109: /* FIXME? */ danw@109: if (!flags) danw@109: return RAZOR_VERSION_EQUAL; danw@109: danw@109: if (flags[0] == 'L') { danw@109: if (flags[1] == 'T') danw@109: return RAZOR_VERSION_LESS; danw@109: else danw@109: return RAZOR_VERSION_LESS_OR_EQUAL; danw@109: } else if (flags[0] == 'G') { danw@109: if (flags[1] == 'T') danw@109: return RAZOR_VERSION_GREATER; danw@109: else danw@109: return RAZOR_VERSION_GREATER_OR_EQUAL; danw@109: } else danw@109: return RAZOR_VERSION_EQUAL; danw@109: } danw@109: danw@109: static void danw@109: yum_primary_start_element(void *data, const char *name, const char **atts) danw@109: { danw@109: struct yum_context *ctx = data; danw@143: const char *n, *epoch, *version, *release, *flags; danw@109: char buffer[128]; danw@109: int i; danw@109: danw@109: if (strcmp(name, "name") == 0) { danw@109: ctx->state = YUM_STATE_PACKAGE_NAME; danw@109: ctx->p = ctx->name; danw@109: } else if (strcmp(name, "version") == 0) { danw@143: epoch = NULL; danw@109: version = NULL; danw@109: release = NULL; danw@109: for (i = 0; atts[i]; i += 2) { danw@143: if (strcmp(atts[i], "epoch") == 0) danw@143: epoch = atts[i + 1]; danw@143: else if (strcmp(atts[i], "ver") == 0) danw@109: version = atts[i + 1]; danw@109: else if (strcmp(atts[i], "rel") == 0) danw@109: release = atts[i + 1]; danw@109: } danw@109: if (version == NULL || release == NULL) { danw@109: fprintf(stderr, "invalid version tag, " danw@109: "missing version or release attribute\n"); danw@109: return; danw@109: } danw@109: danw@143: razor_build_evr(buffer, sizeof buffer, epoch, version, release); danw@109: razor_importer_begin_package(ctx->importer, ctx->name, buffer); danw@109: } else if (strcmp(name, "checksum") == 0) { danw@109: ctx->p = ctx->pkgid; danw@109: ctx->state = YUM_STATE_CHECKSUM; danw@109: } else if (strcmp(name, "rpm:requires") == 0) { danw@109: ctx->state = YUM_STATE_REQUIRES; danw@109: } else if (strcmp(name, "rpm:provides") == 0) { danw@109: ctx->state = YUM_STATE_PROVIDES; danw@109: } else if (strcmp(name, "rpm:obsoletes") == 0) { danw@109: ctx->state = YUM_STATE_OBSOLETES; danw@109: } else if (strcmp(name, "rpm:conflicts") == 0) { danw@109: ctx->state = YUM_STATE_CONFLICTS; danw@109: } else if (strcmp(name, "rpm:entry") == 0 && danw@109: ctx->state != YUM_STATE_BEGIN) { danw@109: n = NULL; danw@143: epoch = NULL; danw@109: version = NULL; danw@109: release = NULL; danw@109: flags = NULL; danw@109: for (i = 0; atts[i]; i += 2) { danw@109: if (strcmp(atts[i], "name") == 0) danw@109: n = atts[i + 1]; danw@143: else if (strcmp(atts[i], "epoch") == 0) danw@143: epoch = atts[i + 1]; danw@109: else if (strcmp(atts[i], "ver") == 0) danw@109: version = atts[i + 1]; danw@109: else if (strcmp(atts[i], "rel") == 0) danw@109: release = atts[i + 1]; danw@109: else if (strcmp(atts[i], "flags") == 0) danw@109: flags = atts[i + 1]; danw@109: } danw@109: danw@109: if (n == NULL) { danw@109: fprintf(stderr, "invalid rpm:entry, " danw@109: "missing name or version attributes\n"); danw@109: return; danw@109: } danw@109: danw@143: razor_build_evr(buffer, sizeof buffer, epoch, version, release); danw@109: switch (ctx->state) { danw@109: case YUM_STATE_REQUIRES: danw@109: razor_importer_add_property(ctx->importer, n, danw@109: yum_to_razor_flags (flags), danw@109: buffer, danw@109: RAZOR_PROPERTY_REQUIRES); danw@109: break; danw@109: case YUM_STATE_PROVIDES: danw@109: razor_importer_add_property(ctx->importer, n, danw@109: yum_to_razor_flags (flags), danw@109: buffer, danw@109: RAZOR_PROPERTY_PROVIDES); danw@109: break; danw@109: case YUM_STATE_OBSOLETES: danw@109: razor_importer_add_property(ctx->importer, n, danw@109: yum_to_razor_flags (flags), danw@109: buffer, danw@109: RAZOR_PROPERTY_OBSOLETES); danw@109: break; danw@109: case YUM_STATE_CONFLICTS: danw@109: razor_importer_add_property(ctx->importer, n, danw@109: yum_to_razor_flags (flags), danw@109: buffer, danw@109: RAZOR_PROPERTY_CONFLICTS); danw@109: break; danw@109: } danw@109: } danw@109: } danw@109: danw@109: static void danw@109: yum_primary_end_element (void *data, const char *name) danw@109: { danw@109: struct yum_context *ctx = data; danw@109: danw@109: switch (ctx->state) { danw@109: case YUM_STATE_PACKAGE_NAME: danw@109: case YUM_STATE_CHECKSUM: danw@109: case YUM_STATE_FILE: danw@109: ctx->state = YUM_STATE_BEGIN; danw@109: break; danw@109: } danw@109: danw@109: if (strcmp(name, "package") == 0) { danw@109: XML_StopParser(ctx->current_parser, XML_TRUE); danw@109: ctx->current_parser = ctx->filelists_parser; danw@109: } danw@109: } danw@109: danw@109: static void danw@109: yum_character_data (void *data, const XML_Char *s, int len) danw@109: { danw@109: struct yum_context *ctx = data; danw@109: danw@109: switch (ctx->state) { danw@109: case YUM_STATE_PACKAGE_NAME: danw@109: case YUM_STATE_CHECKSUM: danw@109: case YUM_STATE_FILE: danw@109: memcpy(ctx->p, s, len); danw@109: ctx->p += len; danw@109: *ctx->p = '\0'; danw@109: break; danw@109: } danw@109: } danw@109: danw@109: static void danw@109: yum_filelists_start_element(void *data, const char *name, const char **atts) danw@109: { danw@109: struct yum_context *ctx = data; danw@109: const char *pkg, *pkgid; danw@109: int i; danw@109: danw@109: if (strcmp(name, "package") == 0) { danw@109: pkg = NULL; danw@109: pkgid = NULL; danw@109: for (i = 0; atts[i]; i += 2) { danw@109: if (strcmp(atts[i], "name") == 0) danw@109: pkg = atts[i + 1]; danw@109: else if (strcmp(atts[i], "pkgid") == 0) danw@109: pkgid = atts[i + 1]; danw@109: } danw@109: if (strcmp(pkgid, ctx->pkgid) != 0) danw@109: fprintf(stderr, "primary.xml and filelists.xml " danw@109: "mismatch for %s: %s vs %s", danw@109: pkg, pkgid, ctx->pkgid); danw@109: } else if (strcmp(name, "file") == 0) { danw@109: ctx->state = YUM_STATE_FILE; danw@109: ctx->p = ctx->buffer; danw@109: } danw@109: } danw@109: danw@109: danw@109: static void danw@109: yum_filelists_end_element (void *data, const char *name) danw@109: { danw@109: struct yum_context *ctx = data; danw@109: danw@109: ctx->state = YUM_STATE_BEGIN; danw@109: if (strcmp(name, "package") == 0) { danw@109: XML_StopParser(ctx->current_parser, XML_TRUE); danw@109: ctx->current_parser = ctx->primary_parser; danw@109: razor_importer_finish_package(ctx->importer); danw@109: } else if (strcmp(name, "file") == 0) danw@109: razor_importer_add_file(ctx->importer, ctx->buffer); danw@109: danw@109: } danw@109: danw@109: #define XML_BUFFER_SIZE 4096 danw@109: danw@109: struct razor_set * danw@109: razor_set_create_from_yum(void) danw@109: { danw@109: struct yum_context ctx; danw@109: void *buf; danw@109: int len, ret; danw@109: gzFile primary, filelists; danw@109: XML_ParsingStatus status; danw@109: danw@109: ctx.importer = razor_importer_new(); danw@109: ctx.state = YUM_STATE_BEGIN; danw@109: danw@109: ctx.primary_parser = XML_ParserCreate(NULL); danw@109: XML_SetUserData(ctx.primary_parser, &ctx); danw@109: XML_SetElementHandler(ctx.primary_parser, danw@109: yum_primary_start_element, danw@109: yum_primary_end_element); danw@109: XML_SetCharacterDataHandler(ctx.primary_parser, danw@109: yum_character_data); danw@109: danw@109: ctx.filelists_parser = XML_ParserCreate(NULL); danw@109: XML_SetUserData(ctx.filelists_parser, &ctx); danw@109: XML_SetElementHandler(ctx.filelists_parser, danw@109: yum_filelists_start_element, danw@109: yum_filelists_end_element); danw@109: XML_SetCharacterDataHandler(ctx.filelists_parser, danw@109: yum_character_data); danw@109: danw@109: primary = gzopen("primary.xml.gz", "rb"); danw@109: if (primary == NULL) danw@109: return NULL; danw@109: filelists = gzopen("filelists.xml.gz", "rb"); danw@109: if (filelists == NULL) danw@109: return NULL; danw@109: danw@109: ctx.current_parser = ctx.primary_parser; danw@109: danw@109: do { danw@109: XML_GetParsingStatus(ctx.current_parser, &status); danw@109: switch (status.parsing) { danw@109: case XML_SUSPENDED: danw@109: ret = XML_ResumeParser(ctx.current_parser); danw@109: break; danw@109: case XML_PARSING: danw@109: case XML_INITIALIZED: danw@109: buf = XML_GetBuffer(ctx.current_parser, danw@109: XML_BUFFER_SIZE); danw@109: if (ctx.current_parser == ctx.primary_parser) danw@109: len = gzread(primary, buf, XML_BUFFER_SIZE); danw@109: else danw@109: len = gzread(filelists, buf, XML_BUFFER_SIZE); danw@109: if (len < 0) { danw@109: fprintf(stderr, danw@109: "couldn't read input: %s\n", danw@109: strerror(errno)); danw@109: return NULL; danw@109: } danw@109: danw@109: XML_ParseBuffer(ctx.current_parser, len, len == 0); danw@109: break; danw@109: case XML_FINISHED: danw@109: break; danw@109: } danw@109: } while (status.parsing != XML_FINISHED); danw@109: danw@109: danw@109: XML_ParserFree(ctx.primary_parser); danw@109: XML_ParserFree(ctx.filelists_parser); danw@109: danw@109: gzclose(primary); danw@109: gzclose(filelists); danw@109: danw@109: return razor_importer_finish(ctx.importer); danw@109: }