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:
473 * @package: a %razor_package
474 * @root: the root into which the package is currently installed
475 * @install_count: the value to pass to uninstall scripts
477 * Removes an installed package.
480 razor_package_remove(struct razor_set *set, struct razor_package *package,
481 const char *root, int install_count)
483 struct razor_file_iterator *fi;
484 struct razor_package_iterator *pi;
485 struct razor_package *p;
486 char buffer[PATH_MAX];
487 const char *name, *program, *script;
488 int retval = 0, i, count;
489 struct environment env;
493 environment_init(&env);
494 link = list_first(&package->install_prefixes, &set->prefix_pool);
495 for (i = 0; link; i++) {
496 prefix = (const char *)set->string_pool.data + link->data;
497 sprintf(buffer, "RPM_INSTALL_PREFIX%d", i);
498 environment_add_variable(&env, buffer, prefix);
499 link = list_next(link);
502 razor_package_get_details(set, package,
503 RAZOR_DETAIL_PREUNPROG, &program,
504 RAZOR_DETAIL_PREUN, &script,
507 environment_set(&env);
508 retval = razor_run_script(root, RAZOR_PROPERTY_PREUN, program, script,
510 environment_unset(&env);
513 environment_release(&env);
517 fi = razor_file_iterator_create(set, package);
519 while (!retval && razor_file_iterator_next(fi, &name)) {
520 pi = razor_package_iterator_create_for_file(set, name);
522 while (razor_package_iterator_next(pi, &p, RAZOR_DETAIL_LAST))
524 razor_package_iterator_destroy(pi);
526 snprintf(buffer, sizeof buffer, "%s%s", root, name);
527 retval = remove(buffer);
531 razor_file_iterator_destroy(fi);
534 environment_release(&env);
538 razor_package_get_details(set, package,
539 RAZOR_DETAIL_POSTUNPROG, &program,
540 RAZOR_DETAIL_POSTUN, &script,
543 environment_set(&env);
544 retval = razor_run_script(root, RAZOR_PROPERTY_POSTUN, program, script,
546 environment_unset(&env);
548 environment_release(&env);
553 RAZOR_EXPORT const char *
554 razor_property_relation_to_string(struct razor_property *p)
558 switch (p->flags & RAZOR_PROPERTY_RELATION_MASK) {
559 case RAZOR_PROPERTY_LESS:
562 case RAZOR_PROPERTY_LESS | RAZOR_PROPERTY_EQUAL:
565 case RAZOR_PROPERTY_EQUAL:
568 case RAZOR_PROPERTY_GREATER | RAZOR_PROPERTY_EQUAL:
571 case RAZOR_PROPERTY_GREATER:
579 RAZOR_EXPORT const char *
580 razor_property_type_to_string(struct razor_property *p)
584 switch (p->flags & RAZOR_PROPERTY_TYPE_MASK) {
585 case RAZOR_PROPERTY_REQUIRES:
587 case RAZOR_PROPERTY_PROVIDES:
589 case RAZOR_PROPERTY_CONFLICTS:
591 case RAZOR_PROPERTY_OBSOLETES:
598 RAZOR_EXPORT struct razor_entry *
599 razor_set_find_entry(struct razor_set *set,
600 struct razor_entry *dir, const char *pattern)
602 struct razor_entry *e, *subdir;
603 const char *n, *pool = set->file_string_pool.data;
606 assert (set != NULL);
607 assert (dir != NULL);
608 assert (pattern != NULL);
613 if (strcmp(pattern, n) == 0)
616 if (e->start != 0 && strncmp(pattern, n, len) == 0 &&
617 pattern[len] == '/') {
618 subdir = (struct razor_entry *) set->files.data +
620 return razor_set_find_entry(set, subdir,
623 } while (!((e++)->flags & RAZOR_ENTRY_LAST));
629 list_dir(struct razor_set *set, struct razor_entry *dir,
630 char *prefix, const char *pattern)
632 struct razor_entry *e, *subdir;
633 const char *n, *pool = set->file_string_pool.data;
638 if (pattern && pattern[0] && fnmatch(pattern, n, 0) != 0)
640 printf("%s/%s\n", prefix, n);
642 char *sub = prefix + strlen (prefix);
645 subdir = (struct razor_entry *) set->files.data +
647 list_dir(set, subdir, prefix, pattern);
650 } while (!((e++)->flags & RAZOR_ENTRY_LAST));
654 razor_set_list_files(struct razor_set *set, const char *pattern)
656 struct razor_entry *root, *e;
657 char buffer[512], *p, *base;
659 assert (set != NULL);
661 root = (struct razor_entry *) set->files.data;
663 if (pattern == NULL) {
664 p = set->file_string_pool.data;
668 strcpy(buffer, p + e->name);
669 list_dir(set, root + e->start, buffer, NULL);
671 } while (!((e++)->flags & RAZOR_ENTRY_LAST));
675 strcpy(buffer, pattern);
676 e = razor_set_find_entry(set, root, buffer);
680 p = strrchr(buffer, '/');
688 e = razor_set_find_entry(set, root, buffer);
690 list_dir(set, root + e->start, buffer, base);
694 razor_set_list_package_files(struct razor_set *set,
695 struct razor_package *package)
697 struct razor_file_iterator *fi;
700 assert (set != NULL);
701 assert (package != NULL);
703 fi = razor_file_iterator_create(set, package);
705 while (razor_file_iterator_next(fi, &name))
706 printf("%s\n", name);
708 razor_file_iterator_destroy(fi);
712 razor_set_diff(struct razor_set *set, struct razor_set *upstream,
713 razor_diff_callback_t callback, void *data)
715 struct razor_package_iterator *pi1, *pi2;
716 struct razor_package *p1, *p2;
717 const char *name1, *name2, *version1, *version2, *arch1, *arch2;
720 assert (set != NULL);
721 assert (upstream != NULL);
723 pi1 = razor_package_iterator_create(set);
724 pi2 = razor_package_iterator_create(upstream);
726 razor_package_iterator_next(pi1, &p1,
727 RAZOR_DETAIL_NAME, &name1,
728 RAZOR_DETAIL_VERSION, &version1,
729 RAZOR_DETAIL_ARCH, &arch1,
731 razor_package_iterator_next(pi2, &p2,
732 RAZOR_DETAIL_NAME, &name2,
733 RAZOR_DETAIL_VERSION, &version2,
734 RAZOR_DETAIL_ARCH, &arch2,
739 res = strcmp(name1, name2);
741 res = razor_versioncmp(version1, version2);
746 if (p2 == NULL || res < 0)
747 callback(RAZOR_DIFF_ACTION_REMOVE,
748 p1, name1, version1, arch1, data);
749 else if (p1 == NULL || res > 0)
750 callback(RAZOR_DIFF_ACTION_ADD,
751 p2, name2, version2, arch2, data);
753 if (p1 != NULL && res <= 0)
754 razor_package_iterator_next(pi1, &p1,
755 RAZOR_DETAIL_NAME, &name1,
756 RAZOR_DETAIL_VERSION, &version1,
757 RAZOR_DETAIL_ARCH, &arch1,
759 if (p2 != NULL && res >= 0)
760 razor_package_iterator_next(pi2, &p2,
761 RAZOR_DETAIL_NAME, &name2,
762 RAZOR_DETAIL_VERSION, &version2,
763 RAZOR_DETAIL_ARCH, &arch2,
767 razor_package_iterator_destroy(pi1);
768 razor_package_iterator_destroy(pi2);
771 struct install_action {
772 enum razor_install_action action;
773 struct razor_package *package;
776 struct razor_install_iterator {
777 struct razor_set *set;
778 struct razor_set *next;
779 struct array actions;
784 add_action(enum razor_diff_action action,
785 struct razor_package *package,
791 struct razor_install_iterator *ii = data;
792 struct install_action *a;
794 a = array_add(&ii->actions, sizeof *a);
795 a->package = package;
798 case RAZOR_DIFF_ACTION_ADD:
799 a->action = RAZOR_INSTALL_ACTION_ADD;
801 case RAZOR_DIFF_ACTION_REMOVE:
802 a->action = RAZOR_INSTALL_ACTION_REMOVE;
807 RAZOR_EXPORT struct razor_install_iterator *
808 razor_set_create_install_iterator(struct razor_set *set,
809 struct razor_set *next)
811 struct razor_install_iterator *ii;
812 struct razor_property *prop;
813 /* A graph of the actions to be perfomed where
814 * A->B means action A should follow action B.
816 struct graph follows;
817 struct install_action *actions, *ai, *aj;
818 int i, j, count, vertex_added;
820 struct razor_set *rs;
822 assert (set != NULL);
823 assert (next != NULL);
825 ii = zalloc(sizeof *ii);
829 razor_set_diff(set, next, add_action, ii);
831 actions = ii->actions.data;
832 count = ii->actions.size / sizeof (struct install_action);
834 graph_init(&follows);
836 for(i = 0; i < count; i++) {
838 rs = ai->action == RAZOR_INSTALL_ACTION_ADD ? next : set;
840 link = list_first(&ai->package->properties, &rs->property_pool);
841 for(; link; link = list_next(link)) {
842 prop = rs->properties.data;
844 switch(prop->flags & RAZOR_PROPERTY_TYPE_MASK) {
845 case RAZOR_PROPERTY_REQUIRES:
846 case RAZOR_PROPERTY_CONFLICTS:
847 for(j = 0; j < count; j++) {
851 if (aj->package->name == prop->name) {
853 RAZOR_INSTALL_ACTION_ADD)
854 graph_add_edge(&follows,
857 graph_add_edge(&follows,
865 if (ai->action == RAZOR_INSTALL_ACTION_ADD) {
866 for(j = 0; j < count; j++) {
870 if (aj->package == ai->package &&
871 aj->action == RAZOR_INSTALL_ACTION_REMOVE) {
872 graph_add_edge(&follows, i, j);
878 graph_add_edge(&follows, i, i);
881 ii->order = graph_sort(&follows);
882 graph_release(&follows);
888 razor_install_iterator_next(struct razor_install_iterator *ii,
889 struct razor_set **set,
890 struct razor_package **package,
891 enum razor_install_action *action,
894 struct install_action *a;
895 if (deque_empty(ii->order))
898 a = (struct install_action *)ii->actions.data + deque_pop(ii->order);
900 case RAZOR_INSTALL_ACTION_ADD:
903 case RAZOR_INSTALL_ACTION_REMOVE:
908 *package = a->package;
916 razor_install_iterator_destroy(struct razor_install_iterator *ii)
918 array_release(&ii->actions);
919 deque_free(ii->order);