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 {
64 struct razor_set_section_index razor_sections[] = {
65 { RAZOR_STRING_POOL, offsetof(struct razor_set, string_pool) },
66 { RAZOR_PACKAGES, offsetof(struct razor_set, packages) },
67 { RAZOR_PROPERTIES, offsetof(struct razor_set, properties) },
68 { RAZOR_PACKAGE_POOL, offsetof(struct razor_set, package_pool) },
69 { RAZOR_PROPERTY_POOL, offsetof(struct razor_set, property_pool) },
72 struct razor_set_section_index razor_files_sections[] = {
73 { RAZOR_FILES, offsetof(struct razor_set, files) },
74 { RAZOR_FILE_POOL, offsetof(struct razor_set, file_pool) },
75 { RAZOR_FILE_STRING_POOL, offsetof(struct razor_set, file_string_pool) },
78 struct razor_set_section_index razor_details_sections[] = {
79 { RAZOR_DETAILS_STRING_POOL, offsetof(struct razor_set, details_string_pool) },
82 RAZOR_EXPORT struct razor_set *
83 razor_set_create_without_root(void)
85 struct razor_set *set;
88 set = zalloc(sizeof *set);
90 empty = array_add(&set->string_pool, 1);
96 RAZOR_EXPORT struct razor_set *
97 razor_set_create(void)
99 struct razor_set *set;
100 struct razor_entry *e;
102 set = razor_set_create_without_root();
104 e = array_add(&set->files, sizeof *e);
106 e->flags = RAZOR_ENTRY_LAST;
108 list_set_empty(&e->packages);
114 razor_set_bind_sections(struct razor_set *set,
115 struct razor_set_header **header,
117 struct razor_set_section_index section_index[],
118 int section_index_size,
119 const char *filename)
121 struct razor_set_section *s, *sections;
126 *header = razor_file_get_contents(filename, header_size);
130 sections = (void *) *header + sizeof **header;
131 pool = (void *) sections + (*header)->num_sections * sizeof *sections;
133 for (i = 0; i < (*header)->num_sections; i++) {
136 for (j = 0; j < section_index_size; j++)
137 if (!strcmp(section_index[j].name,
140 if (j == section_index_size)
142 array = (void *) set + section_index[j].offset;
143 array->data = (void *) *header + s->offset;
144 array->size = s->size;
145 array->alloc = s->size;
151 RAZOR_EXPORT struct razor_set *
152 razor_set_open(const char *filename)
154 struct razor_set *set;
156 set = zalloc(sizeof *set);
157 if (razor_set_bind_sections(set, &set->header, &set->header_size,
158 razor_sections, ARRAY_SIZE(razor_sections),
167 razor_set_open_details(struct razor_set *set, const char *filename)
169 return razor_set_bind_sections(set, &set->details_header,
170 &set->details_header_size,
171 razor_details_sections,
172 ARRAY_SIZE(razor_details_sections),
177 razor_set_open_files(struct razor_set *set, const char *filename)
179 return razor_set_bind_sections(set, &set->files_header,
180 &set->files_header_size,
181 razor_files_sections,
182 ARRAY_SIZE(razor_files_sections),
187 razor_set_destroy(struct razor_set *set)
192 assert (set != NULL);
195 razor_file_free_contents(set->header, set->header_size);
197 for (i = 0; i < ARRAY_SIZE(razor_sections); i++) {
198 a = (void *) set + razor_sections[i].offset;
203 if (set->details_header) {
204 razor_file_free_contents(set->details_header,
205 set->details_header_size);
207 for (i = 0; i < ARRAY_SIZE(razor_details_sections); i++) {
208 a = (void *) set + razor_details_sections[i].offset;
213 if (set->files_header) {
214 razor_file_free_contents(set->files_header,
215 set->files_header_size);
217 for (i = 0; i < ARRAY_SIZE(razor_files_sections); i++) {
218 a = (void *) set + razor_files_sections[i].offset;
227 razor_set_write_sections_to_fd(struct razor_set *set, int fd,
228 struct razor_set_section_index *sections,
231 struct razor_set_header header;
232 struct razor_set_section *out_sections =
233 malloc(array_size * sizeof *out_sections);
234 struct hashtable table;
235 struct array *a, pool;
239 header.magic = RAZOR_MAGIC;
240 header.version = RAZOR_VERSION;
241 header.num_sections = array_size;
242 offset = sizeof header + array_size * sizeof *out_sections;
245 hashtable_init(&table, &pool);
247 for (i = 0; i < array_size; i++)
248 out_sections[i].name =
249 hashtable_tokenize(&table, sections[i].name);
253 for (i = 0; i < array_size; i++) {
254 a = (void *) set + sections[i].offset;
255 out_sections[i].offset = offset;
256 out_sections[i].size = a->size;
260 razor_write(fd, &header, sizeof header);
261 razor_write(fd, out_sections, array_size * sizeof *out_sections);
262 razor_write(fd, pool.data, pool.size);
264 for (i = 0; i < array_size; i++) {
265 a = (void *) set + sections[i].offset;
266 razor_write(fd, a->data, a->size);
275 razor_set_write_to_fd(struct razor_set *set, int fd,
276 enum razor_repo_file_type type)
279 case RAZOR_REPO_FILE_MAIN:
280 return razor_set_write_sections_to_fd(set, fd,
282 ARRAY_SIZE(razor_sections));
284 case RAZOR_REPO_FILE_DETAILS:
285 return razor_set_write_sections_to_fd(set, fd,
286 razor_details_sections,
287 ARRAY_SIZE(razor_details_sections));
288 case RAZOR_REPO_FILE_FILES:
289 return razor_set_write_sections_to_fd(set, fd,
290 razor_files_sections,
291 ARRAY_SIZE(razor_files_sections));
298 razor_set_write(struct razor_set *set, const char *filename,
299 enum razor_repo_file_type type)
303 fd = open(filename, O_CREAT | O_WRONLY | O_TRUNC | O_BINARY, 0666);
307 status = razor_set_write_to_fd(set, fd, type);
317 razor_build_evr(char *evr_buf, int size, const char *epoch,
318 const char *version, const char *release)
322 if (!version || !*version) {
327 if (epoch && *epoch && strcmp(epoch, "0") != 0) {
328 len = snprintf(evr_buf, size, "%s:", epoch);
332 len = snprintf(evr_buf, size, "%s", version);
335 if (release && *release)
336 snprintf(evr_buf, size, "-%s", release);
340 razor_versioncmp(const char *s1, const char *s2)
349 n1 = strtol(s1, (char **) &p1, 10);
350 n2 = strtol(s2, (char **) &p2, 10);
352 /* Epoch; if one but not the other has an epoch set, default
353 * the epoch-less version to 0. */
354 res = (*p1 == ':') - (*p2 == ':');
359 } else if (res > 0) {
372 if (isdigit(*p1) && isdigit(*p2))
373 return razor_versioncmp(p1, p2);
380 razor_package_get_details_type(struct razor_set *set,
381 struct razor_package *package,
382 enum razor_detail_type type)
387 case RAZOR_DETAIL_NAME:
388 pool = set->string_pool.data;
389 return &pool[package->name];
391 case RAZOR_DETAIL_VERSION:
392 pool = set->string_pool.data;
393 return &pool[package->version];
395 case RAZOR_DETAIL_ARCH:
396 pool = set->string_pool.data;
397 return &pool[package->arch];
399 case RAZOR_DETAIL_SUMMARY:
400 pool = set->details_string_pool.data;
401 return &pool[package->summary];
403 case RAZOR_DETAIL_DESCRIPTION:
404 pool = set->details_string_pool.data;
405 return &pool[package->description];
407 case RAZOR_DETAIL_URL:
408 pool = set->details_string_pool.data;
409 return &pool[package->url];
411 case RAZOR_DETAIL_LICENSE:
412 pool = set->details_string_pool.data;
413 return &pool[package->license];
415 case RAZOR_DETAIL_PREUNPROG:
416 pool = set->string_pool.data;
417 return &pool[package->preun.program];
419 case RAZOR_DETAIL_PREUN:
420 pool = set->string_pool.data;
421 return &pool[package->preun.body];
423 case RAZOR_DETAIL_POSTUNPROG:
424 pool = set->string_pool.data;
425 return &pool[package->postun.program];
427 case RAZOR_DETAIL_POSTUN:
428 pool = set->string_pool.data;
429 return &pool[package->postun.body];
432 fprintf(stderr, "type %u not found\n", type);
438 * razor_package_get_details_varg:
440 * @package: a %razor_package
441 * @args: a va_list of arguments to set
444 razor_package_get_details_varg(struct razor_set *set,
445 struct razor_package *package,
449 enum razor_detail_type type;
452 for (i = 0;; i += 2) {
453 type = va_arg(args, enum razor_detail_type);
454 if (type == RAZOR_DETAIL_LAST)
456 data = va_arg(args, const char **);
457 *data = razor_package_get_details_type(set, package, type);
463 * razor_package_get_details:
465 * @package: a %razor_package
467 * Gets details about a package using a varg interface
468 * The vararg must be terminated with %RAZOR_DETAIL_LAST.
470 * Example: razor_package_get_details (set, package,
471 * RAZOR_DETAIL_URL, &url,
472 * RAZOR_DETAIL_LAST);
475 razor_package_get_details(struct razor_set *set, struct razor_package *package, ...)
479 assert (set != NULL);
480 assert (package != NULL);
482 va_start(args, NULL);
483 razor_package_get_details_varg (set, package, args);
488 * razor_package_remove:
490 * @package: a %razor_package
491 * @root: the root into which the package is currently installed
493 * Removes an installed package.
496 razor_package_remove(struct razor_set *set, struct razor_package *package,
499 struct razor_file_iterator *fi;
500 struct razor_package_iterator *pi;
501 struct razor_package *p;
502 char buffer[PATH_MAX];
503 const char *name, *program, *script;
504 int retval = 0, count;
506 razor_package_get_details(set, package,
507 RAZOR_DETAIL_PREUNPROG, &program,
508 RAZOR_DETAIL_PREUN, &script,
511 if (razor_run_script(root, RAZOR_PROPERTY_PREUN, program, script))
514 fi = razor_file_iterator_create(set, package);
516 while (!retval && razor_file_iterator_next(fi, &name)) {
517 pi = razor_package_iterator_create_for_file(set, name);
519 while (razor_package_iterator_next(pi, &p, RAZOR_DETAIL_LAST))
521 razor_package_iterator_destroy(pi);
523 snprintf(buffer, sizeof buffer, "%s%s", root, name);
524 retval = remove(buffer);
528 razor_file_iterator_destroy(fi);
533 razor_package_get_details(set, package,
534 RAZOR_DETAIL_POSTUNPROG, &program,
535 RAZOR_DETAIL_POSTUN, &script,
538 return razor_run_script(root, RAZOR_PROPERTY_POSTUN, program, script);
541 RAZOR_EXPORT const char *
542 razor_property_relation_to_string(struct razor_property *p)
546 switch (p->flags & RAZOR_PROPERTY_RELATION_MASK) {
547 case RAZOR_PROPERTY_LESS:
550 case RAZOR_PROPERTY_LESS | RAZOR_PROPERTY_EQUAL:
553 case RAZOR_PROPERTY_EQUAL:
556 case RAZOR_PROPERTY_GREATER | RAZOR_PROPERTY_EQUAL:
559 case RAZOR_PROPERTY_GREATER:
567 RAZOR_EXPORT const char *
568 razor_property_type_to_string(struct razor_property *p)
572 switch (p->flags & RAZOR_PROPERTY_TYPE_MASK) {
573 case RAZOR_PROPERTY_REQUIRES:
575 case RAZOR_PROPERTY_PROVIDES:
577 case RAZOR_PROPERTY_CONFLICTS:
579 case RAZOR_PROPERTY_OBSOLETES:
586 RAZOR_EXPORT struct razor_entry *
587 razor_set_find_entry(struct razor_set *set,
588 struct razor_entry *dir, const char *pattern)
590 struct razor_entry *e, *subdir;
591 const char *n, *pool = set->file_string_pool.data;
594 assert (set != NULL);
595 assert (dir != NULL);
596 assert (pattern != NULL);
601 if (strcmp(pattern, n) == 0)
604 if (e->start != 0 && strncmp(pattern, n, len) == 0 &&
605 pattern[len] == '/') {
606 subdir = (struct razor_entry *) set->files.data +
608 return razor_set_find_entry(set, subdir,
611 } while (!((e++)->flags & RAZOR_ENTRY_LAST));
617 list_dir(struct razor_set *set, struct razor_entry *dir,
618 char *prefix, const char *pattern)
620 struct razor_entry *e, *subdir;
621 const char *n, *pool = set->file_string_pool.data;
626 if (pattern && pattern[0] && fnmatch(pattern, n, 0) != 0)
628 printf("%s/%s\n", prefix, n);
630 char *sub = prefix + strlen (prefix);
633 subdir = (struct razor_entry *) set->files.data +
635 list_dir(set, subdir, prefix, pattern);
638 } while (!((e++)->flags & RAZOR_ENTRY_LAST));
642 razor_set_list_files(struct razor_set *set, const char *pattern)
644 struct razor_entry *root, *e;
645 char buffer[512], *p, *base;
647 assert (set != NULL);
649 root = (struct razor_entry *) set->files.data;
651 if (pattern == NULL) {
652 p = set->file_string_pool.data;
656 strcpy(buffer, p + e->name);
657 list_dir(set, root + e->start, buffer, NULL);
659 } while (!((e++)->flags & RAZOR_ENTRY_LAST));
663 strcpy(buffer, pattern);
664 e = razor_set_find_entry(set, root, buffer);
668 p = strrchr(buffer, '/');
676 e = razor_set_find_entry(set, root, buffer);
678 list_dir(set, root + e->start, buffer, base);
682 razor_set_list_package_files(struct razor_set *set,
683 struct razor_package *package)
685 struct razor_file_iterator *fi;
688 assert (set != NULL);
689 assert (package != NULL);
691 fi = razor_file_iterator_create(set, package);
693 while (razor_file_iterator_next(fi, &name))
694 printf("%s\n", name);
696 razor_file_iterator_destroy(fi);
700 razor_set_diff(struct razor_set *set, struct razor_set *upstream,
701 razor_diff_callback_t callback, void *data)
703 struct razor_package_iterator *pi1, *pi2;
704 struct razor_package *p1, *p2;
705 const char *name1, *name2, *version1, *version2, *arch1, *arch2;
708 assert (set != NULL);
709 assert (upstream != NULL);
711 pi1 = razor_package_iterator_create(set);
712 pi2 = razor_package_iterator_create(upstream);
714 razor_package_iterator_next(pi1, &p1,
715 RAZOR_DETAIL_NAME, &name1,
716 RAZOR_DETAIL_VERSION, &version1,
717 RAZOR_DETAIL_ARCH, &arch1,
719 razor_package_iterator_next(pi2, &p2,
720 RAZOR_DETAIL_NAME, &name2,
721 RAZOR_DETAIL_VERSION, &version2,
722 RAZOR_DETAIL_ARCH, &arch2,
727 res = strcmp(name1, name2);
729 res = razor_versioncmp(version1, version2);
734 if (p2 == NULL || res < 0)
735 callback(RAZOR_DIFF_ACTION_REMOVE,
736 p1, name1, version1, arch1, data);
737 else if (p1 == NULL || res > 0)
738 callback(RAZOR_DIFF_ACTION_ADD,
739 p2, name2, version2, arch2, data);
741 if (p1 != NULL && res <= 0)
742 razor_package_iterator_next(pi1, &p1,
743 RAZOR_DETAIL_NAME, &name1,
744 RAZOR_DETAIL_VERSION, &version1,
745 RAZOR_DETAIL_ARCH, &arch1,
747 if (p2 != NULL && res >= 0)
748 razor_package_iterator_next(pi2, &p2,
749 RAZOR_DETAIL_NAME, &name2,
750 RAZOR_DETAIL_VERSION, &version2,
751 RAZOR_DETAIL_ARCH, &arch2,
755 razor_package_iterator_destroy(pi1);
756 razor_package_iterator_destroy(pi2);
759 struct install_action {
760 enum razor_install_action action;
761 struct razor_package *package;
764 struct razor_install_iterator {
765 struct razor_set *set;
766 struct razor_set *next;
767 struct array actions;
772 add_action(enum razor_diff_action action,
773 struct razor_package *package,
779 struct razor_install_iterator *ii = data;
780 struct install_action *a;
782 a = array_add(&ii->actions, sizeof *a);
783 a->package = package;
786 case RAZOR_DIFF_ACTION_ADD:
787 a->action = RAZOR_INSTALL_ACTION_ADD;
789 case RAZOR_DIFF_ACTION_REMOVE:
790 a->action = RAZOR_INSTALL_ACTION_REMOVE;
795 RAZOR_EXPORT struct razor_install_iterator *
796 razor_set_create_install_iterator(struct razor_set *set,
797 struct razor_set *next)
799 struct razor_install_iterator *ii;
800 struct razor_property *prop;
801 /* A graph of the actions to be perfomed where
802 * A->B means action A should follow action B.
804 struct graph follows;
805 struct install_action *actions, *ai, *aj;
806 int i, j, count, vertex_added;
808 struct razor_set *rs;
810 assert (set != NULL);
811 assert (next != NULL);
813 ii = zalloc(sizeof *ii);
817 razor_set_diff(set, next, add_action, ii);
819 actions = ii->actions.data;
820 count = ii->actions.size / sizeof (struct install_action);
822 graph_init(&follows);
824 for(i = 0; i < count; i++) {
826 rs = ai->action == RAZOR_INSTALL_ACTION_ADD ? next : set;
828 link = list_first(&ai->package->properties, &rs->property_pool);
829 for(; link; link = list_next(link)) {
830 prop = rs->properties.data;
832 switch(prop->flags & RAZOR_PROPERTY_TYPE_MASK) {
833 case RAZOR_PROPERTY_REQUIRES:
834 case RAZOR_PROPERTY_CONFLICTS:
835 for(j = 0; j < count; j++) {
839 if (aj->package->name == prop->name) {
841 RAZOR_INSTALL_ACTION_ADD)
842 graph_add_edge(&follows,
845 graph_add_edge(&follows,
853 if (ai->action == RAZOR_INSTALL_ACTION_ADD) {
854 for(j = 0; j < count; j++) {
858 if (aj->package == ai->package &&
859 aj->action == RAZOR_INSTALL_ACTION_REMOVE) {
860 graph_add_edge(&follows, i, j);
866 graph_add_edge(&follows, i, i);
869 ii->order = graph_sort(&follows);
870 graph_release(&follows);
876 razor_install_iterator_next(struct razor_install_iterator *ii,
877 struct razor_set **set,
878 struct razor_package **package,
879 enum razor_install_action *action,
882 struct install_action *a;
883 if (deque_empty(ii->order))
886 a = (struct install_action *)ii->actions.data + deque_pop(ii->order);
888 case RAZOR_INSTALL_ACTION_ADD:
891 case RAZOR_INSTALL_ACTION_REMOVE:
896 *package = a->package;
904 razor_install_iterator_destroy(struct razor_install_iterator *ii)
906 array_release(&ii->actions);
907 deque_free(ii->order);