2 * Copyright (C) 2008 Kristian Høgsberg <krh@redhat.com>
3 * Copyright (C) 2008 Red Hat, Inc
4 * Copyright (C) 2009 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.
31 #include <sys/types.h>
41 #include "razor-internal.h"
59 struct razor_set_section_index {
65 #define MAIN(type, field) \
66 { type, offsetof(struct razor_set, field), RAZOR_SECTION_MAIN }
67 #define FILES(type, field) \
68 { type, offsetof(struct razor_set, field), RAZOR_SECTION_FILES }
69 #define DETAILS(type, field) \
70 { type, offsetof(struct razor_set, field), RAZOR_SECTION_DETAILS }
72 struct razor_set_section_index razor_sections[] = {
73 MAIN(RAZOR_STRING_POOL, string_pool),
74 MAIN(RAZOR_PACKAGES, packages),
75 MAIN(RAZOR_PROPERTIES, properties),
76 MAIN(RAZOR_PACKAGE_POOL, package_pool),
77 MAIN(RAZOR_PROPERTY_POOL, property_pool),
78 MAIN(RAZOR_PREFIX_POOL, prefix_pool),
79 FILES(RAZOR_FILES, files),
80 FILES(RAZOR_FILE_POOL, file_pool),
81 FILES(RAZOR_FILE_STRING_POOL, file_string_pool),
82 DETAILS(RAZOR_DETAILS_STRING_POOL, details_string_pool)
85 RAZOR_EXPORT struct razor_set *
86 razor_set_create_without_root(void)
88 struct razor_set *set;
91 set = zalloc(sizeof *set);
93 empty = array_add(&set->string_pool, 1);
99 RAZOR_EXPORT struct razor_set *
100 razor_set_create(void)
102 struct razor_set *set;
103 struct razor_entry *e;
105 set = razor_set_create_without_root();
107 e = array_add(&set->files, sizeof *e);
109 e->flags = RAZOR_ENTRY_LAST;
111 list_set_empty(&e->packages);
116 struct razor_mapped_file {
117 struct razor_set_header *header;
119 struct razor_mapped_file *next;
123 razor_set_bind_sections(struct razor_set *set, const char *filename)
125 struct razor_set_section *s, *sections;
126 struct razor_mapped_file *file;
131 file = zalloc(sizeof *file);
135 file->header = razor_file_get_contents(filename, &file->size);
141 file->next = set->mapped_files;
142 set->mapped_files = file;
144 sections = (void *) file->header + sizeof *file->header;
145 pool = (void *) sections +
146 file->header->num_sections * sizeof *sections;
148 for (i = 0; i < file->header->num_sections; i++) {
150 for (j = 0; j < ARRAY_SIZE(razor_sections); j++)
151 if (!strcmp(razor_sections[j].name, &pool[s->name]))
153 if (j == ARRAY_SIZE(razor_sections))
155 array = (void *) set + razor_sections[j].offset;
156 array->data = (void *) file->header + s->offset;
157 array->size = s->size;
158 array->alloc = s->size;
164 RAZOR_EXPORT struct razor_set *
165 razor_set_open(const char *filename)
167 struct razor_set *set;
169 set = zalloc(sizeof *set);
170 if (razor_set_bind_sections(set, filename)){
178 razor_set_destroy(struct razor_set *set)
180 struct razor_mapped_file *file, *next;
184 assert (set != NULL);
186 if (set->mapped_files == NULL) {
187 for (i = 0; i < ARRAY_SIZE(razor_sections); i++) {
188 array = (void *) set + razor_sections[i].offset;
189 array_release(array);
192 for (file = set->mapped_files; file != NULL; file = next) {
194 razor_file_free_contents(file->header, file->size);
203 razor_set_write_to_fd(struct razor_set *set, int fd, uint32_t section_mask)
205 struct razor_set_header header;
206 struct razor_set_section sections[ARRAY_SIZE(razor_sections)];
207 struct hashtable table;
208 struct array pool, *arrays[ARRAY_SIZE(razor_sections)];
211 static const char padding[4];
214 hashtable_init(&table, &pool);
217 for (i = 0; i < ARRAY_SIZE(razor_sections); i++) {
218 if ((razor_sections[i].flags & section_mask) == 0)
221 arrays[j] = (void *) set + razor_sections[i].offset;
223 hashtable_tokenize(&table, razor_sections[i].name);
228 header.magic = RAZOR_MAGIC;
229 header.version = RAZOR_VERSION;
230 header.num_sections = count;
231 offset = sizeof header + count * sizeof *sections + ALIGN(pool.size, 4);
233 for (i = 0; i < count; i++) {
234 sections[i].offset = offset;
235 sections[i].size = arrays[i]->size;
236 offset += ALIGN(arrays[i]->size, 4);
239 razor_write(fd, &header, sizeof header);
240 razor_write(fd, sections, count * sizeof *sections);
241 razor_write(fd, pool.data, pool.size);
242 razor_write(fd, padding, PADDING(pool.size, 4));
244 for (i = 0; i < count; i++) {
245 razor_write(fd, arrays[i]->data, arrays[i]->size);
246 razor_write(fd, padding, PADDING(arrays[i]->size, 4));
249 array_release(&pool);
250 hashtable_release(&table);
256 razor_set_write(struct razor_set *set, const char *filename, uint32_t sections)
260 fd = open(filename, O_CREAT | O_WRONLY | O_TRUNC | O_BINARY, 0666);
264 status = razor_set_write_to_fd(set, fd, sections);
274 razor_build_evr(char *evr_buf, int size, const char *epoch,
275 const char *version, const char *release)
279 if (!version || !*version) {
284 if (epoch && *epoch && strcmp(epoch, "0") != 0) {
285 len = snprintf(evr_buf, size, "%s:", epoch);
289 len = snprintf(evr_buf, size, "%s", version);
292 if (release && *release)
293 snprintf(evr_buf, size, "-%s", release);
297 razor_versioncmp(const char *s1, const char *s2)
306 n1 = strtol(s1, (char **) &p1, 10);
307 n2 = strtol(s2, (char **) &p2, 10);
309 /* Epoch; if one but not the other has an epoch set, default
310 * the epoch-less version to 0. */
311 res = (*p1 == ':') - (*p2 == ':');
316 } else if (res > 0) {
329 if (isdigit(*p1) && isdigit(*p2))
330 return razor_versioncmp(p1, p2);
337 razor_package_get_details_string(struct razor_set *set,
338 struct razor_package *package,
339 enum razor_detail_type type)
344 case RAZOR_DETAIL_NAME:
345 pool = set->string_pool.data;
346 return &pool[package->name];
348 case RAZOR_DETAIL_VERSION:
349 pool = set->string_pool.data;
350 return &pool[package->version];
352 case RAZOR_DETAIL_ARCH:
353 pool = set->string_pool.data;
354 return &pool[package->arch];
356 case RAZOR_DETAIL_SUMMARY:
357 pool = set->details_string_pool.data;
358 return &pool[package->summary];
360 case RAZOR_DETAIL_DESCRIPTION:
361 pool = set->details_string_pool.data;
362 return &pool[package->description];
364 case RAZOR_DETAIL_URL:
365 pool = set->details_string_pool.data;
366 return &pool[package->url];
368 case RAZOR_DETAIL_LICENSE:
369 pool = set->details_string_pool.data;
370 return &pool[package->license];
372 case RAZOR_DETAIL_PREUNPROG:
373 pool = set->string_pool.data;
374 return &pool[package->preun.program];
376 case RAZOR_DETAIL_PREUN:
377 pool = set->string_pool.data;
378 return &pool[package->preun.body];
380 case RAZOR_DETAIL_POSTUNPROG:
381 pool = set->string_pool.data;
382 return &pool[package->postun.program];
384 case RAZOR_DETAIL_POSTUN:
385 pool = set->string_pool.data;
386 return &pool[package->postun.body];
389 fprintf(stderr, "type %u not found\n", type);
394 static const char *const *
395 razor_package_get_details_array(struct razor_set *set,
396 struct razor_package *package,
397 enum razor_detail_type type)
400 case RAZOR_DETAIL_PREFIXES:
401 /* We don't track prefixes in packages. Install prefixes
402 * are tracked, but we don't provide an API to get them.
407 fprintf(stderr, "type %u not found\n", type);
413 * razor_package_get_details_varg:
415 * @package: a %razor_package
416 * @args: a va_list of arguments to set
419 razor_package_get_details_varg(struct razor_set *set,
420 struct razor_package *package,
424 enum razor_detail_type type;
426 const char *const **array;
428 for (i = 0;; i += 2) {
429 type = va_arg(args, enum razor_detail_type);
430 if (type == RAZOR_DETAIL_LAST)
432 if (type == RAZOR_DETAIL_PREFIXES) {
433 array = va_arg(args, const char *const **);
434 *array = razor_package_get_details_array(set, package,
437 string = va_arg(args, const char **);
438 *string = razor_package_get_details_string(set, package,
446 * razor_package_get_details:
448 * @package: a %razor_package
450 * Gets details about a package using a varg interface
451 * The vararg must be terminated with %RAZOR_DETAIL_LAST.
453 * Example: razor_package_get_details (set, package,
454 * RAZOR_DETAIL_URL, &url,
455 * RAZOR_DETAIL_LAST);
458 razor_package_get_details(struct razor_set *set, struct razor_package *package, ...)
462 assert (set != NULL);
463 assert (package != NULL);
465 va_start(args, NULL);
466 razor_package_get_details_varg (set, package, args);
471 * razor_package_remove:
472 * @prev: The %razor_set before the current transaction
473 * @next: The %razor_set after the current transaction is applied
474 * @package: a %razor_package
475 * @root: the root into which the package is currently installed
476 * @install_count: the value to pass to uninstall scripts
478 * Removes an installed package.
481 razor_package_remove(struct razor_set *prev, struct razor_set *next,
482 struct razor_package *package, const char *root,
485 struct razor_file_iterator *fi;
486 struct razor_package_iterator *pi;
487 struct razor_package *p;
488 char buffer[PATH_MAX];
489 const char *name, *program, *script;
490 int retval = 0, i, count;
491 struct environment env;
495 environment_init(&env);
496 link = list_first(&package->install_prefixes, &prev->prefix_pool);
497 for (i = 0; link; i++) {
498 prefix = (const char *)prev->string_pool.data + link->data;
499 sprintf(buffer, "RPM_INSTALL_PREFIX%d", i);
500 environment_add_variable(&env, buffer, prefix);
501 link = list_next(link);
503 environment_set(&env);
505 razor_package_get_details(prev, package,
506 RAZOR_DETAIL_PREUNPROG, &program,
507 RAZOR_DETAIL_PREUN, &script,
510 retval = razor_run_script(root, RAZOR_PROPERTY_PREUN, program, script,
513 fi = razor_file_iterator_create(prev, package, 1);
515 while (razor_file_iterator_next(fi, &name)) {
516 pi = razor_package_iterator_create_for_file(next, name);
518 while (razor_package_iterator_next(pi, &p, RAZOR_DETAIL_LAST))
520 razor_package_iterator_destroy(pi);
522 snprintf(buffer, sizeof buffer, "%s%s", root, name);
523 if (razor_remove(buffer) && errno != ENOENT) {
530 razor_file_iterator_destroy(fi);
532 razor_package_get_details(prev, package,
533 RAZOR_DETAIL_POSTUNPROG, &program,
534 RAZOR_DETAIL_POSTUN, &script,
537 if (razor_run_script(root, RAZOR_PROPERTY_POSTUN, program, script,
541 environment_unset(&env);
542 environment_release(&env);
547 RAZOR_EXPORT const char *
548 razor_property_relation_to_string(struct razor_property *p)
552 switch (p->flags & RAZOR_PROPERTY_RELATION_MASK) {
553 case RAZOR_PROPERTY_LESS:
556 case RAZOR_PROPERTY_LESS | RAZOR_PROPERTY_EQUAL:
559 case RAZOR_PROPERTY_EQUAL:
562 case RAZOR_PROPERTY_GREATER | RAZOR_PROPERTY_EQUAL:
565 case RAZOR_PROPERTY_GREATER:
573 RAZOR_EXPORT const char *
574 razor_property_type_to_string(struct razor_property *p)
578 switch (p->flags & RAZOR_PROPERTY_TYPE_MASK) {
579 case RAZOR_PROPERTY_REQUIRES:
581 case RAZOR_PROPERTY_PROVIDES:
583 case RAZOR_PROPERTY_CONFLICTS:
585 case RAZOR_PROPERTY_OBSOLETES:
592 RAZOR_EXPORT struct razor_entry *
593 razor_set_find_entry(struct razor_set *set,
594 struct razor_entry *dir, const char *pattern)
596 struct razor_entry *e, *subdir;
597 const char *n, *pool = set->file_string_pool.data;
600 assert (set != NULL);
601 assert (pattern != NULL);
609 if (strcmp(pattern, n) == 0)
612 if (e->start != 0 && strncmp(pattern, n, len) == 0 &&
613 pattern[len] == '/') {
614 subdir = (struct razor_entry *) set->files.data +
616 return razor_set_find_entry(set, subdir,
619 } while (!((e++)->flags & RAZOR_ENTRY_LAST));
625 list_dir(struct razor_set *set, struct razor_entry *dir,
626 char *prefix, const char *pattern)
628 struct razor_entry *e, *subdir;
629 const char *n, *pool = set->file_string_pool.data;
634 if (pattern && pattern[0] && fnmatch(pattern, n, 0) != 0)
636 printf("%s/%s\n", prefix, n);
638 char *sub = prefix + strlen (prefix);
641 subdir = (struct razor_entry *) set->files.data +
643 list_dir(set, subdir, prefix, pattern);
646 } while (!((e++)->flags & RAZOR_ENTRY_LAST));
650 razor_set_list_files(struct razor_set *set, const char *pattern)
652 struct razor_entry *root, *e;
653 char buffer[512], *p, *base;
655 assert (set != NULL);
657 root = (struct razor_entry *) set->files.data;
659 if (pattern == NULL) {
660 p = set->file_string_pool.data;
664 strcpy(buffer, p + e->name);
665 list_dir(set, root + e->start, buffer, NULL);
667 } while (!((e++)->flags & RAZOR_ENTRY_LAST));
671 strcpy(buffer, pattern);
672 e = razor_set_find_entry(set, root, buffer);
676 p = strrchr(buffer, '/');
684 e = razor_set_find_entry(set, root, buffer);
686 list_dir(set, root + e->start, buffer, base);
690 razor_set_list_package_files(struct razor_set *set,
691 struct razor_package *package)
693 struct razor_file_iterator *fi;
696 assert (set != NULL);
697 assert (package != NULL);
699 fi = razor_file_iterator_create(set, package, 0);
701 while (razor_file_iterator_next(fi, &name))
702 printf("%s\n", name);
704 razor_file_iterator_destroy(fi);
708 * Package data can potentially come from two places. The so-called
709 * metadata (eg., from comps.xml) and from an RPM file. We consider
710 * a package which has additional data from an RPM file as "fixed".
711 * If a package needs fixing, then razor_transaction_fixup_package()
712 * will do so. When considering what packages to add and to remove
713 * we need to take this into account since we always want to add
714 * unfixed packages (otherwise we have a potential conflict between
715 * the existing package data and that present in the RPM).
718 razor_package_is_fixed(struct razor_set *set, struct razor_package *p)
720 const char *preunprog, *preun, *postunprog, *postun;
724 razor_package_get_details(set, p,
725 RAZOR_DETAIL_PREUNPROG, &preunprog,
726 RAZOR_DETAIL_PREUN, &preun,
727 RAZOR_DETAIL_POSTUNPROG, &postunprog,
728 RAZOR_DETAIL_POSTUN, &postun,
730 return *preunprog || *preun || *postunprog || *postun;
734 razor_set_diff(struct razor_set *set, struct razor_set *upstream,
735 razor_diff_callback_t callback, void *data)
737 struct razor_package_iterator *pi1, *pi2;
738 struct razor_package *p1, *p2;
739 const char *name1, *name2, *version1, *version2, *arch1, *arch2;
740 int res, is_fixed1, is_fixed2;
742 assert (set != NULL);
743 assert (upstream != NULL);
745 pi1 = razor_package_iterator_create(set);
746 pi2 = razor_package_iterator_create(upstream);
748 razor_package_iterator_next(pi1, &p1,
749 RAZOR_DETAIL_NAME, &name1,
750 RAZOR_DETAIL_VERSION, &version1,
751 RAZOR_DETAIL_ARCH, &arch1,
753 is_fixed1 = razor_package_is_fixed(set, p1);
754 razor_package_iterator_next(pi2, &p2,
755 RAZOR_DETAIL_NAME, &name2,
756 RAZOR_DETAIL_VERSION, &version2,
757 RAZOR_DETAIL_ARCH, &arch2,
759 is_fixed2 = razor_package_is_fixed(upstream, p2);
763 res = strcmp(name1, name2);
765 res = razor_versioncmp(version1, version2);
767 res = is_fixed1 - is_fixed2;
772 if (p2 == NULL || res < 0)
773 callback(RAZOR_DIFF_ACTION_REMOVE,
774 p1, name1, version1, arch1, data);
775 else if (p1 == NULL || res > 0)
776 callback(RAZOR_DIFF_ACTION_ADD,
777 p2, name2, version2, arch2, data);
779 if (p1 != NULL && res <= 0) {
780 razor_package_iterator_next(pi1, &p1,
781 RAZOR_DETAIL_NAME, &name1,
782 RAZOR_DETAIL_VERSION, &version1,
783 RAZOR_DETAIL_ARCH, &arch1,
785 is_fixed1 = razor_package_is_fixed(set, p1);
787 if (p2 != NULL && res >= 0) {
788 razor_package_iterator_next(pi2, &p2,
789 RAZOR_DETAIL_NAME, &name2,
790 RAZOR_DETAIL_VERSION, &version2,
791 RAZOR_DETAIL_ARCH, &arch2,
793 is_fixed2 = razor_package_is_fixed(upstream, p2);
797 razor_package_iterator_destroy(pi1);
798 razor_package_iterator_destroy(pi2);
801 struct install_action {
802 enum razor_install_action action;
803 struct razor_package *package;
806 struct razor_install_iterator {
807 struct razor_set *set;
808 struct razor_set *next;
809 struct array actions;
814 add_action(enum razor_diff_action action,
815 struct razor_package *package,
821 struct razor_install_iterator *ii = data;
822 struct install_action *a;
824 a = array_add(&ii->actions, sizeof *a);
825 a->package = package;
828 case RAZOR_DIFF_ACTION_ADD:
829 a->action = RAZOR_INSTALL_ACTION_ADD;
831 case RAZOR_DIFF_ACTION_REMOVE:
832 a->action = RAZOR_INSTALL_ACTION_REMOVE;
837 RAZOR_EXPORT struct razor_install_iterator *
838 razor_set_create_install_iterator(struct razor_set *set,
839 struct razor_set *next)
841 struct razor_install_iterator *ii;
842 struct razor_property *prop;
843 /* A graph of the actions to be perfomed where
844 * A->B means action A should follow action B.
846 struct graph follows;
847 struct install_action *actions, *ai, *aj;
848 int i, j, count, vertex_added;
850 struct razor_set *rs;
852 assert (set != NULL);
853 assert (next != NULL);
855 ii = zalloc(sizeof *ii);
859 razor_set_diff(set, next, add_action, ii);
861 actions = ii->actions.data;
862 count = ii->actions.size / sizeof (struct install_action);
864 graph_init(&follows);
866 for(i = 0; i < count; i++) {
868 rs = ai->action == RAZOR_INSTALL_ACTION_ADD ? next : set;
870 link = list_first(&ai->package->properties, &rs->property_pool);
871 for(; link; link = list_next(link)) {
872 prop = rs->properties.data;
874 switch(prop->flags & RAZOR_PROPERTY_TYPE_MASK) {
875 case RAZOR_PROPERTY_REQUIRES:
876 case RAZOR_PROPERTY_CONFLICTS:
877 for(j = 0; j < count; j++) {
881 if (aj->package->name == prop->name) {
883 RAZOR_INSTALL_ACTION_ADD)
884 graph_add_edge(&follows,
887 graph_add_edge(&follows,
895 if (ai->action == RAZOR_INSTALL_ACTION_ADD) {
896 for(j = 0; j < count; j++) {
900 if (aj->package == ai->package &&
901 aj->action == RAZOR_INSTALL_ACTION_REMOVE) {
902 graph_add_edge(&follows, i, j);
908 graph_add_edge(&follows, i, i);
911 ii->order = graph_sort(&follows);
912 graph_release(&follows);
918 razor_install_iterator_next(struct razor_install_iterator *ii,
919 struct razor_package **package,
920 enum razor_install_action *action,
923 struct install_action *a;
924 struct razor_package_iterator *pi;
925 struct razor_package *pkg;
926 const char *removing, *name;
928 if (deque_empty(ii->order))
931 a = (struct install_action *)ii->actions.data + deque_pop(ii->order);
932 *package = a->package;
936 if (a->action == RAZOR_INSTALL_ACTION_REMOVE) {
937 razor_package_get_details(ii->set, a->package,
938 RAZOR_DETAIL_NAME, &removing,
941 pi = razor_package_iterator_create(ii->next);
942 while (razor_package_iterator_next(pi, &pkg,
943 RAZOR_DETAIL_NAME, &name,
944 RAZOR_DETAIL_LAST)) {
945 if (!strcmp(name, removing))
948 razor_package_iterator_destroy(pi);
955 razor_install_iterator_destroy(struct razor_install_iterator *ii)
957 array_release(&ii->actions);
958 deque_free(ii->order);