Support parallel installations. The idea is that for CAD screener, we want
to be able to install this on the same machine as a standard AVOT setup
(most notably for John's laptop). To allow for the possibility of a second
application that might have the same requirements, we add the concept of
vendor-specific distributions. Thus we can have one distribution for CAD
screener and one for The Next Big Thing. It doesn't seem trivial to have
both CAD screener and AVOT under the same vendor tag so we'll have to have
AVOT under "City Occupational" and CAD screener under "City Occupational Ltd"
or some such kludge.
Most of this is done although we are very short of test cases (in particular
we don't test that it's actually possible to install CAD screener in parallel
with AVOT or to update either of them once installed, which is fundamental).
We also have a lot of baggage left over, including an intercept of razor_set.
The problem that this was introduced to debug has been fixed but it looks
like there are a number of memory leaks which it might be useful to help
track down so it has been left in place for now.
There is still a lot of confusion in plover between path-based and URI-based
API. We should review the API, decide what we want and have a general clear up.
There is also confusion as to the purpose of RAZOR_ROOT (and meaning; path or
URI). This is not used at all in librazor (although it is used in razor.exe).
Ideally we shouldn't use it in plover or plover-gtk either although again, we
might want to support it or an equivalent in (some of) the various executables.
Work that would still to nice to do for CAD screener:
- uninstall (ideally as an installed program that hooks into Add/Remove programs
but even re-running the installer would be acceptable).
- xz support (smaller packages).
- repomd.xml and xml:base (would be needed for an Internet installer).
- graphical installer.
2 * Copyright (C) 2008 Kristian Høgsberg <krh@redhat.com>
3 * Copyright (C) 2008 Red Hat, Inc
4 * Copyright (C) 2009, 2011, 2014, 2016 J. Ali Harlow <ali@juiblex.co.uk>
6 * This program is free software; you can redistribute it and/or modify
7 * it under the terms of the GNU General Public License as published by
8 * the Free Software Foundation; either version 2 of the License, or
9 * (at your option) any later version.
11 * This program is distributed in the hope that it will be useful,
12 * but WITHOUT ANY WARRANTY; without even the implied warranty of
13 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
14 * GNU General Public License for more details.
16 * You should have received a copy of the GNU General Public License along
17 * with this program; if not, write to the Free Software Foundation, Inc.,
18 * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
35 #include "plover/plover.h"
36 #include "plover/uri-handler.h"
37 #include "plover/inputstream.h"
39 /* Import a yum filelist as a razor package set. */
43 YUM_STATE_PACKAGE_NAME,
44 YUM_STATE_PACKAGE_ARCH,
46 YUM_STATE_DESCRIPTION,
54 YUM_STATE_SKIPPING_PACKAGE,
59 XML_Parser primary_parser;
60 XML_Parser filelists_parser;
61 XML_Parser current_parser;
63 struct razor_importer *importer;
64 struct import_property_context *current_property_context;
67 char name[256], arch[64], summary[512], description[4096];
68 char url[256], license[64], buffer[512], *p;
69 char pkgid[128], evr[128];
70 uint32_t property_type;
77 yum_to_razor_relation (const char *flags)
79 if (flags[0] == 'L') {
81 return RAZOR_PROPERTY_LESS;
83 return RAZOR_PROPERTY_LESS | RAZOR_PROPERTY_EQUAL;
84 } else if (flags[0] == 'G') {
86 return RAZOR_PROPERTY_GREATER;
88 return RAZOR_PROPERTY_GREATER | RAZOR_PROPERTY_EQUAL;
90 return RAZOR_PROPERTY_EQUAL;
94 yum_primary_start_element(void *data, const char *name, const char **atts)
96 struct yum_context *ctx = data;
97 const char *n, *epoch, *version, *release;
101 uint32_t pre, relation, flags;
104 if (ctx->state == YUM_STATE_SKIPPING_PACKAGE)
107 if (strcmp(name, "metadata") == 0) {
108 for (i = 0; atts[i]; i += 2) {
109 if (strcmp(atts[i], "packages") == 0)
110 ctx->total = atoi(atts[i + 1]);
112 } else if (strcmp(name, "package") == 0) {
113 *ctx->name=*ctx->arch=*ctx->summary=*ctx->description='\0';
114 *ctx->url=*ctx->license='\0';
115 } else if (strcmp(name, "name") == 0) {
116 ctx->state = YUM_STATE_PACKAGE_NAME;
118 } else if (strcmp(name, "arch") == 0) {
119 ctx->state = YUM_STATE_PACKAGE_ARCH;
121 } else if (strcmp(name, "version") == 0) {
125 for (i = 0; atts[i]; i += 2) {
126 if (strcmp(atts[i], "epoch") == 0)
128 else if (strcmp(atts[i], "ver") == 0)
129 version = atts[i + 1];
130 else if (strcmp(atts[i], "rel") == 0)
131 release = atts[i + 1];
133 if (version == NULL || release == NULL) {
134 fprintf(stderr, "invalid version tag, "
135 "missing version or release attribute\n");
139 razor_build_evr(ctx->evr, sizeof ctx->evr, epoch, version,
141 if (!strcmp(ctx->arch, "noarch") ||
142 !strcmp(ctx->arch, razor_system_arch())) {
143 razor_importer_begin_package(ctx->importer, ctx->name,
144 ctx->evr, ctx->arch);
146 ctx->state = YUM_STATE_SKIPPING_PACKAGE;
147 } else if (strcmp(name, "summary") == 0) {
148 ctx->p = ctx->summary;
149 ctx->state = YUM_STATE_SUMMARY;
150 } else if (strcmp(name, "description") == 0) {
151 ctx->p = ctx->description;
152 ctx->state = YUM_STATE_DESCRIPTION;
153 } else if (strcmp(name, "url") == 0) {
155 ctx->state = YUM_STATE_URL;
156 } else if (strcmp(name, "checksum") == 0) {
158 ctx->state = YUM_STATE_CHECKSUM;
159 } else if (strcmp(name, "location") == 0) {
160 if (ctx->state != YUM_STATE_SKIPPING_PACKAGE) {
161 for (i = 0; atts[i]; i += 2)
162 if (strcmp(atts[i], "href") == 0) {
163 nevra=g_strconcat(ctx->name,"-",ctx->evr,".",
165 s=razor_path_relative_to_uri(ctx->base_uri,
167 g_tree_insert(ctx->uris,nevra,g_strdup(s));
172 } else if (strcmp(name, "rpm:license") == 0) {
173 ctx->p = ctx->license;
174 ctx->state = YUM_STATE_LICENSE;
175 } else if (strcmp(name, "rpm:requires") == 0) {
176 ctx->state = YUM_STATE_REQUIRES;
177 ctx->property_type = RAZOR_PROPERTY_REQUIRES;
178 } else if (strcmp(name, "rpm:provides") == 0) {
179 ctx->state = YUM_STATE_PROVIDES;
180 ctx->property_type = RAZOR_PROPERTY_PROVIDES;
181 } else if (strcmp(name, "rpm:obsoletes") == 0) {
182 ctx->state = YUM_STATE_OBSOLETES;
183 ctx->property_type = RAZOR_PROPERTY_OBSOLETES;
184 } else if (strcmp(name, "rpm:conflicts") == 0) {
185 ctx->state = YUM_STATE_CONFLICTS;
186 ctx->property_type = RAZOR_PROPERTY_CONFLICTS;
187 } else if (strcmp(name, "rpm:entry") == 0 &&
188 ctx->state != YUM_STATE_BEGIN) {
193 relation = RAZOR_PROPERTY_EQUAL;
195 for (i = 0; atts[i]; i += 2) {
196 if (strcmp(atts[i], "name") == 0)
198 else if (strcmp(atts[i], "epoch") == 0)
200 else if (strcmp(atts[i], "ver") == 0)
201 version = atts[i + 1];
202 else if (strcmp(atts[i], "rel") == 0)
203 release = atts[i + 1];
204 else if (strcmp(atts[i], "flags") == 0)
205 relation = yum_to_razor_relation(atts[i + 1]);
206 else if (strcmp(atts[i], "pre") == 0)
207 pre = RAZOR_PROPERTY_PRE;
211 fprintf(stderr, "invalid rpm:entry, "
212 "missing name or version attributes\n");
216 razor_build_evr(buffer, sizeof buffer, epoch, version, release);
217 flags = ctx->property_type | relation | pre;
218 razor_importer_add_property(ctx->importer, n, flags, buffer);
223 yum_primary_end_element (void *data, const char *name)
225 struct yum_context *ctx = data;
227 switch (ctx->state) {
228 case YUM_STATE_PACKAGE_NAME:
229 case YUM_STATE_PACKAGE_ARCH:
230 case YUM_STATE_SUMMARY:
231 case YUM_STATE_DESCRIPTION:
233 case YUM_STATE_LICENSE:
234 case YUM_STATE_CHECKSUM:
236 ctx->state = YUM_STATE_BEGIN;
240 if (strcmp(name, "package") == 0) {
241 if (ctx->state != YUM_STATE_SKIPPING_PACKAGE)
242 razor_importer_add_details(ctx->importer, ctx->summary,
243 ctx->description, ctx->url,
246 XML_StopParser(ctx->current_parser, XML_TRUE);
247 ctx->current_parser = ctx->filelists_parser;
252 yum_character_data (void *data, const XML_Char *s, int len)
254 struct yum_context *ctx = data;
256 switch (ctx->state) {
257 case YUM_STATE_PACKAGE_NAME:
258 case YUM_STATE_PACKAGE_ARCH:
259 case YUM_STATE_SUMMARY:
260 case YUM_STATE_DESCRIPTION:
262 case YUM_STATE_LICENSE:
263 case YUM_STATE_CHECKSUM:
265 memcpy(ctx->p, s, len);
273 yum_filelists_start_element(void *data, const char *name, const char **atts)
275 struct yum_context *ctx = data;
276 const char *pkg, *pkgid;
279 if (strcmp(name, "package") == 0 &&
280 ctx->state != YUM_STATE_SKIPPING_PACKAGE) {
283 for (i = 0; atts[i]; i += 2) {
284 if (strcmp(atts[i], "name") == 0)
286 else if (strcmp(atts[i], "pkgid") == 0)
289 if (strcmp(pkgid, ctx->pkgid) != 0)
290 fprintf(stderr, "primary.xml and filelists.xml "
291 "mismatch for %s: %s vs %s",
292 pkg, pkgid, ctx->pkgid);
293 } else if (strcmp(name, "file") == 0) {
294 if (ctx->state != YUM_STATE_SKIPPING_PACKAGE)
295 ctx->state = YUM_STATE_FILE;
296 ctx->p = ctx->buffer;
301 yum_filelists_end_element (void *data, const char *name)
303 struct yum_context *ctx = data;
305 if (strcmp(name, "package") == 0) {
306 XML_StopParser(ctx->current_parser, XML_TRUE);
307 ctx->current_parser = ctx->primary_parser;
308 if (ctx->state != YUM_STATE_SKIPPING_PACKAGE)
309 razor_importer_finish_package(ctx->importer);
310 ctx->state = YUM_STATE_BEGIN;
311 } else if (strcmp(name, "file") == 0) {
312 if (ctx->state != YUM_STATE_SKIPPING_PACKAGE)
313 razor_importer_add_file(ctx->importer, ctx->buffer);
315 if (ctx->state != YUM_STATE_SKIPPING_PACKAGE)
316 ctx->state = YUM_STATE_BEGIN;
319 static int plover_system_arch_is_x86(void)
321 const char *arch=razor_system_arch();
322 if (!arch || arch[0]!='i' || arch[1]<'3' || arch[1]>'6')
325 return !strcmp(arch+2,"86");
328 #define XML_BUFFER_SIZE 4096
330 PloverRepository *plover_repository_new_from_yum_uri(const char *base_uri,
333 struct yum_context ctx;
337 const char *name,*version,*arch;
341 GInputStream *stream;
342 GInputStream *primary,*filelists;
343 GZlibDecompressor *decompressor;
344 XML_ParsingStatus status;
345 struct razor_set *razor;
346 struct razor_package_iterator *iter;
347 struct razor_package *pkg;
348 PloverPackageSet *set;
349 PloverRepository *repository;
350 plover__uri_handler_init();
351 ctx.importer=razor_importer_create();
352 ctx.state=YUM_STATE_BEGIN;
353 ctx.base_uri=base_uri;
354 ctx.primary_parser=XML_ParserCreate(NULL);
355 XML_SetUserData(ctx.primary_parser,&ctx);
356 XML_SetElementHandler(ctx.primary_parser,yum_primary_start_element,
357 yum_primary_end_element);
358 XML_SetCharacterDataHandler(ctx.primary_parser,yum_character_data);
359 ctx.filelists_parser=XML_ParserCreate(NULL);
360 XML_SetUserData(ctx.filelists_parser,&ctx);
361 XML_SetElementHandler(ctx.filelists_parser,yum_filelists_start_element,
362 yum_filelists_end_element);
363 XML_SetCharacterDataHandler(ctx.filelists_parser,yum_character_data);
364 uri=razor_path_relative_to_uri(base_uri,"repodata/primary.xml.gz",NULL);
365 stream=plover_razor_input_stream_new(uri,error);
368 XML_ParserFree(ctx.primary_parser);
369 XML_ParserFree(ctx.filelists_parser);
372 decompressor=g_zlib_decompressor_new(G_ZLIB_COMPRESSOR_FORMAT_GZIP);
373 primary=g_converter_input_stream_new(G_INPUT_STREAM(stream),
374 G_CONVERTER(decompressor));
375 g_object_unref(stream);
376 g_object_unref(decompressor);
377 uri=razor_path_relative_to_uri(base_uri,"repodata/filelists.xml.gz",NULL);
378 stream=plover_razor_input_stream_new(uri,error);
381 g_object_unref(primary);
382 XML_ParserFree(ctx.primary_parser);
383 XML_ParserFree(ctx.filelists_parser);
386 decompressor=g_zlib_decompressor_new(G_ZLIB_COMPRESSOR_FORMAT_GZIP);
387 filelists=g_converter_input_stream_new(G_INPUT_STREAM(stream),
388 G_CONVERTER(decompressor));
389 g_object_unref(stream);
390 g_object_unref(decompressor);
391 ctx.current_parser=ctx.primary_parser;
392 ctx.uris=g_tree_new_full((GCompareDataFunc)strcmp,NULL,g_free,NULL);
396 XML_GetParsingStatus(ctx.current_parser,&status);
397 switch (status.parsing)
400 XML_ResumeParser(ctx.current_parser);
403 case XML_INITIALIZED:
404 buf=XML_GetBuffer(ctx.current_parser,XML_BUFFER_SIZE);
405 if (ctx.current_parser==ctx.primary_parser)
406 len=g_input_stream_read(G_INPUT_STREAM(primary),buf,
407 XML_BUFFER_SIZE,NULL,error);
409 len=g_input_stream_read(G_INPUT_STREAM(filelists),buf,
410 XML_BUFFER_SIZE,NULL,error);
413 XML_ParseBuffer(ctx.current_parser,len,!len);
418 } while (status.parsing!=XML_FINISHED);
419 XML_ParserFree(ctx.primary_parser);
420 XML_ParserFree(ctx.filelists_parser);
421 g_object_unref(primary);
422 g_object_unref(filelists);
423 razor=razor_importer_finish(ctx.importer);
424 #if RAZOR_HEADER_VERSION_MIN<=1
426 * Header version 1 is supported by plover v0.3 and is used on
427 * 32-bit intel machines which allows the setup and update
428 * applications from v0.3 to work. On other machines, we don't
429 * want these old applications to work (since they would do
430 * the wrong thing) and so we use the current header version
431 * which they don't support.
433 if (plover_system_arch_is_x86())
434 razor_set_set_header_version(razor,1);
436 uris=g_ptr_array_new();
437 iter=razor_package_iterator_create(razor);
438 while(razor_package_iterator_next(iter,&pkg,RAZOR_DETAIL_NAME,&name,
439 RAZOR_DETAIL_VERSION,&version,RAZOR_DETAIL_ARCH,&arch,RAZOR_DETAIL_LAST))
441 s=g_strconcat(name,"-",version,".",arch,NULL);
442 g_ptr_array_add(uris,g_tree_lookup(ctx.uris,s));
445 razor_package_iterator_destroy(iter);
446 g_ptr_array_add(uris,NULL);
447 g_tree_unref(ctx.uris);
448 rpm_uris=(gchar **)g_ptr_array_free(uris,FALSE);
449 set=plover_package_set_new_from_razor(razor);
450 razor_set_unref(razor);
451 repository=plover_repository_new_from_package_set(set,
452 (const char **)rpm_uris);
454 g_strfreev(rpm_uris);
458 struct razor_set *plover_razor_set_create_from_yum_uri(const char *base_uri,
461 PloverRepository *repository;
462 PloverPackageSet *set;
463 struct razor_set *razor;
464 repository=plover_repository_new_from_yum_uri(base_uri,error);
467 set=plover_repository_get_package_set(repository);
468 razor=plover_package_set_get_razor(set);
469 razor_set_ref(razor);
470 g_object_unref(repository);
474 struct razor_set *plover_razor_set_create_from_yum(const char *base,
479 struct razor_set *set;
480 file=g_file_new_for_path(base);
481 base_uri=g_file_get_uri(file);
482 g_object_unref(file);
483 set=plover_razor_set_create_from_yum_uri(base_uri,error);