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 (dir != NULL);
602 assert (pattern != NULL);
607 if (strcmp(pattern, n) == 0)
610 if (e->start != 0 && strncmp(pattern, n, len) == 0 &&
611 pattern[len] == '/') {
612 subdir = (struct razor_entry *) set->files.data +
614 return razor_set_find_entry(set, subdir,
617 } while (!((e++)->flags & RAZOR_ENTRY_LAST));
623 list_dir(struct razor_set *set, struct razor_entry *dir,
624 char *prefix, const char *pattern)
626 struct razor_entry *e, *subdir;
627 const char *n, *pool = set->file_string_pool.data;
632 if (pattern && pattern[0] && fnmatch(pattern, n, 0) != 0)
634 printf("%s/%s\n", prefix, n);
636 char *sub = prefix + strlen (prefix);
639 subdir = (struct razor_entry *) set->files.data +
641 list_dir(set, subdir, prefix, pattern);
644 } while (!((e++)->flags & RAZOR_ENTRY_LAST));
648 razor_set_list_files(struct razor_set *set, const char *pattern)
650 struct razor_entry *root, *e;
651 char buffer[512], *p, *base;
653 assert (set != NULL);
655 root = (struct razor_entry *) set->files.data;
657 if (pattern == NULL) {
658 p = set->file_string_pool.data;
662 strcpy(buffer, p + e->name);
663 list_dir(set, root + e->start, buffer, NULL);
665 } while (!((e++)->flags & RAZOR_ENTRY_LAST));
669 strcpy(buffer, pattern);
670 e = razor_set_find_entry(set, root, buffer);
674 p = strrchr(buffer, '/');
682 e = razor_set_find_entry(set, root, buffer);
684 list_dir(set, root + e->start, buffer, base);
688 razor_set_list_package_files(struct razor_set *set,
689 struct razor_package *package)
691 struct razor_file_iterator *fi;
694 assert (set != NULL);
695 assert (package != NULL);
697 fi = razor_file_iterator_create(set, package, 0);
699 while (razor_file_iterator_next(fi, &name))
700 printf("%s\n", name);
702 razor_file_iterator_destroy(fi);
706 razor_set_diff(struct razor_set *set, struct razor_set *upstream,
707 razor_diff_callback_t callback, void *data)
709 struct razor_package_iterator *pi1, *pi2;
710 struct razor_package *p1, *p2;
711 const char *name1, *name2, *version1, *version2, *arch1, *arch2;
714 assert (set != NULL);
715 assert (upstream != NULL);
717 pi1 = razor_package_iterator_create(set);
718 pi2 = razor_package_iterator_create(upstream);
720 razor_package_iterator_next(pi1, &p1,
721 RAZOR_DETAIL_NAME, &name1,
722 RAZOR_DETAIL_VERSION, &version1,
723 RAZOR_DETAIL_ARCH, &arch1,
725 razor_package_iterator_next(pi2, &p2,
726 RAZOR_DETAIL_NAME, &name2,
727 RAZOR_DETAIL_VERSION, &version2,
728 RAZOR_DETAIL_ARCH, &arch2,
733 res = strcmp(name1, name2);
735 res = razor_versioncmp(version1, version2);
740 if (p2 == NULL || res < 0)
741 callback(RAZOR_DIFF_ACTION_REMOVE,
742 p1, name1, version1, arch1, data);
743 else if (p1 == NULL || res > 0)
744 callback(RAZOR_DIFF_ACTION_ADD,
745 p2, name2, version2, arch2, data);
747 if (p1 != NULL && res <= 0)
748 razor_package_iterator_next(pi1, &p1,
749 RAZOR_DETAIL_NAME, &name1,
750 RAZOR_DETAIL_VERSION, &version1,
751 RAZOR_DETAIL_ARCH, &arch1,
753 if (p2 != NULL && res >= 0)
754 razor_package_iterator_next(pi2, &p2,
755 RAZOR_DETAIL_NAME, &name2,
756 RAZOR_DETAIL_VERSION, &version2,
757 RAZOR_DETAIL_ARCH, &arch2,
761 razor_package_iterator_destroy(pi1);
762 razor_package_iterator_destroy(pi2);
765 struct install_action {
766 enum razor_install_action action;
767 struct razor_package *package;
770 struct razor_install_iterator {
771 struct razor_set *set;
772 struct razor_set *next;
773 struct array actions;
778 add_action(enum razor_diff_action action,
779 struct razor_package *package,
785 struct razor_install_iterator *ii = data;
786 struct install_action *a;
788 a = array_add(&ii->actions, sizeof *a);
789 a->package = package;
792 case RAZOR_DIFF_ACTION_ADD:
793 a->action = RAZOR_INSTALL_ACTION_ADD;
795 case RAZOR_DIFF_ACTION_REMOVE:
796 a->action = RAZOR_INSTALL_ACTION_REMOVE;
801 RAZOR_EXPORT struct razor_install_iterator *
802 razor_set_create_install_iterator(struct razor_set *set,
803 struct razor_set *next)
805 struct razor_install_iterator *ii;
806 struct razor_property *prop;
807 /* A graph of the actions to be perfomed where
808 * A->B means action A should follow action B.
810 struct graph follows;
811 struct install_action *actions, *ai, *aj;
812 int i, j, count, vertex_added;
814 struct razor_set *rs;
816 assert (set != NULL);
817 assert (next != NULL);
819 ii = zalloc(sizeof *ii);
823 razor_set_diff(set, next, add_action, ii);
825 actions = ii->actions.data;
826 count = ii->actions.size / sizeof (struct install_action);
828 graph_init(&follows);
830 for(i = 0; i < count; i++) {
832 rs = ai->action == RAZOR_INSTALL_ACTION_ADD ? next : set;
834 link = list_first(&ai->package->properties, &rs->property_pool);
835 for(; link; link = list_next(link)) {
836 prop = rs->properties.data;
838 switch(prop->flags & RAZOR_PROPERTY_TYPE_MASK) {
839 case RAZOR_PROPERTY_REQUIRES:
840 case RAZOR_PROPERTY_CONFLICTS:
841 for(j = 0; j < count; j++) {
845 if (aj->package->name == prop->name) {
847 RAZOR_INSTALL_ACTION_ADD)
848 graph_add_edge(&follows,
851 graph_add_edge(&follows,
859 if (ai->action == RAZOR_INSTALL_ACTION_ADD) {
860 for(j = 0; j < count; j++) {
864 if (aj->package == ai->package &&
865 aj->action == RAZOR_INSTALL_ACTION_REMOVE) {
866 graph_add_edge(&follows, i, j);
872 graph_add_edge(&follows, i, i);
875 ii->order = graph_sort(&follows);
876 graph_release(&follows);
882 razor_install_iterator_next(struct razor_install_iterator *ii,
883 struct razor_package **package,
884 enum razor_install_action *action,
887 struct install_action *a;
888 struct razor_package_iterator *pi;
889 struct razor_package *pkg;
890 const char *removing, *name;
892 if (deque_empty(ii->order))
895 a = (struct install_action *)ii->actions.data + deque_pop(ii->order);
896 *package = a->package;
900 if (a->action == RAZOR_INSTALL_ACTION_REMOVE) {
901 razor_package_get_details(ii->set, a->package,
902 RAZOR_DETAIL_NAME, &removing,
905 pi = razor_package_iterator_create(ii->next);
906 while (razor_package_iterator_next(pi, &pkg,
907 RAZOR_DETAIL_NAME, &name,
908 RAZOR_DETAIL_LAST)) {
909 if (!strcmp(name, removing))
912 razor_package_iterator_destroy(pi);
919 razor_install_iterator_destroy(struct razor_install_iterator *ii)
921 array_release(&ii->actions);
922 deque_free(ii->order);