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) },
70 { RAZOR_PREFIX_POOL, offsetof(struct razor_set, prefix_pool) },
73 struct razor_set_section_index razor_files_sections[] = {
74 { RAZOR_FILES, offsetof(struct razor_set, files) },
75 { RAZOR_FILE_POOL, offsetof(struct razor_set, file_pool) },
76 { RAZOR_FILE_STRING_POOL, offsetof(struct razor_set, file_string_pool) },
79 struct razor_set_section_index razor_details_sections[] = {
80 { RAZOR_DETAILS_STRING_POOL, offsetof(struct razor_set, details_string_pool) },
83 RAZOR_EXPORT struct razor_set *
84 razor_set_create_without_root(void)
86 struct razor_set *set;
89 set = zalloc(sizeof *set);
91 empty = array_add(&set->string_pool, 1);
97 RAZOR_EXPORT struct razor_set *
98 razor_set_create(void)
100 struct razor_set *set;
101 struct razor_entry *e;
103 set = razor_set_create_without_root();
105 e = array_add(&set->files, sizeof *e);
107 e->flags = RAZOR_ENTRY_LAST;
109 list_set_empty(&e->packages);
115 razor_set_bind_sections(struct razor_set *set,
116 struct razor_set_header **header,
118 struct razor_set_section_index section_index[],
119 int section_index_size,
120 const char *filename)
122 struct razor_set_section *s, *sections;
127 *header = razor_file_get_contents(filename, header_size);
131 sections = (void *) *header + sizeof **header;
132 pool = (void *) sections + (*header)->num_sections * sizeof *sections;
134 for (i = 0; i < (*header)->num_sections; i++) {
137 for (j = 0; j < section_index_size; j++)
138 if (!strcmp(section_index[j].name,
141 if (j == section_index_size)
143 array = (void *) set + section_index[j].offset;
144 array->data = (void *) *header + s->offset;
145 array->size = s->size;
146 array->alloc = s->size;
152 RAZOR_EXPORT struct razor_set *
153 razor_set_open(const char *filename)
155 struct razor_set *set;
157 set = zalloc(sizeof *set);
158 if (razor_set_bind_sections(set, &set->header, &set->header_size,
159 razor_sections, ARRAY_SIZE(razor_sections),
168 razor_set_open_details(struct razor_set *set, const char *filename)
170 return razor_set_bind_sections(set, &set->details_header,
171 &set->details_header_size,
172 razor_details_sections,
173 ARRAY_SIZE(razor_details_sections),
178 razor_set_open_files(struct razor_set *set, const char *filename)
180 return razor_set_bind_sections(set, &set->files_header,
181 &set->files_header_size,
182 razor_files_sections,
183 ARRAY_SIZE(razor_files_sections),
188 razor_set_destroy(struct razor_set *set)
193 assert (set != NULL);
196 razor_file_free_contents(set->header, set->header_size);
198 for (i = 0; i < ARRAY_SIZE(razor_sections); i++) {
199 a = (void *) set + razor_sections[i].offset;
204 if (set->details_header) {
205 razor_file_free_contents(set->details_header,
206 set->details_header_size);
208 for (i = 0; i < ARRAY_SIZE(razor_details_sections); i++) {
209 a = (void *) set + razor_details_sections[i].offset;
214 if (set->files_header) {
215 razor_file_free_contents(set->files_header,
216 set->files_header_size);
218 for (i = 0; i < ARRAY_SIZE(razor_files_sections); i++) {
219 a = (void *) set + razor_files_sections[i].offset;
228 razor_set_write_sections_to_fd(struct razor_set *set, int fd,
229 struct razor_set_section_index *sections,
232 struct razor_set_header header;
233 struct razor_set_section *out_sections =
234 malloc(array_size * sizeof *out_sections);
235 struct hashtable table;
236 struct array *a, pool;
240 header.magic = RAZOR_MAGIC;
241 header.version = RAZOR_VERSION;
242 header.num_sections = array_size;
243 offset = sizeof header + array_size * sizeof *out_sections;
246 hashtable_init(&table, &pool);
248 for (i = 0; i < array_size; i++)
249 out_sections[i].name =
250 hashtable_tokenize(&table, sections[i].name);
254 for (i = 0; i < array_size; i++) {
255 a = (void *) set + sections[i].offset;
256 out_sections[i].offset = offset;
257 out_sections[i].size = a->size;
261 razor_write(fd, &header, sizeof header);
262 razor_write(fd, out_sections, array_size * sizeof *out_sections);
263 razor_write(fd, pool.data, pool.size);
265 for (i = 0; i < array_size; i++) {
266 a = (void *) set + sections[i].offset;
267 razor_write(fd, a->data, a->size);
276 razor_set_write_to_fd(struct razor_set *set, int fd,
277 enum razor_repo_file_type type)
280 case RAZOR_REPO_FILE_MAIN:
281 return razor_set_write_sections_to_fd(set, fd,
283 ARRAY_SIZE(razor_sections));
285 case RAZOR_REPO_FILE_DETAILS:
286 return razor_set_write_sections_to_fd(set, fd,
287 razor_details_sections,
288 ARRAY_SIZE(razor_details_sections));
289 case RAZOR_REPO_FILE_FILES:
290 return razor_set_write_sections_to_fd(set, fd,
291 razor_files_sections,
292 ARRAY_SIZE(razor_files_sections));
299 razor_set_write(struct razor_set *set, const char *filename,
300 enum razor_repo_file_type type)
304 fd = open(filename, O_CREAT | O_WRONLY | O_TRUNC | O_BINARY, 0666);
308 status = razor_set_write_to_fd(set, fd, type);
318 razor_build_evr(char *evr_buf, int size, const char *epoch,
319 const char *version, const char *release)
323 if (!version || !*version) {
328 if (epoch && *epoch && strcmp(epoch, "0") != 0) {
329 len = snprintf(evr_buf, size, "%s:", epoch);
333 len = snprintf(evr_buf, size, "%s", version);
336 if (release && *release)
337 snprintf(evr_buf, size, "-%s", release);
341 razor_versioncmp(const char *s1, const char *s2)
350 n1 = strtol(s1, (char **) &p1, 10);
351 n2 = strtol(s2, (char **) &p2, 10);
353 /* Epoch; if one but not the other has an epoch set, default
354 * the epoch-less version to 0. */
355 res = (*p1 == ':') - (*p2 == ':');
360 } else if (res > 0) {
373 if (isdigit(*p1) && isdigit(*p2))
374 return razor_versioncmp(p1, p2);
381 razor_package_get_details_string(struct razor_set *set,
382 struct razor_package *package,
383 enum razor_detail_type type)
388 case RAZOR_DETAIL_NAME:
389 pool = set->string_pool.data;
390 return &pool[package->name];
392 case RAZOR_DETAIL_VERSION:
393 pool = set->string_pool.data;
394 return &pool[package->version];
396 case RAZOR_DETAIL_ARCH:
397 pool = set->string_pool.data;
398 return &pool[package->arch];
400 case RAZOR_DETAIL_SUMMARY:
401 pool = set->details_string_pool.data;
402 return &pool[package->summary];
404 case RAZOR_DETAIL_DESCRIPTION:
405 pool = set->details_string_pool.data;
406 return &pool[package->description];
408 case RAZOR_DETAIL_URL:
409 pool = set->details_string_pool.data;
410 return &pool[package->url];
412 case RAZOR_DETAIL_LICENSE:
413 pool = set->details_string_pool.data;
414 return &pool[package->license];
416 case RAZOR_DETAIL_PREUNPROG:
417 pool = set->string_pool.data;
418 return &pool[package->preun.program];
420 case RAZOR_DETAIL_PREUN:
421 pool = set->string_pool.data;
422 return &pool[package->preun.body];
424 case RAZOR_DETAIL_POSTUNPROG:
425 pool = set->string_pool.data;
426 return &pool[package->postun.program];
428 case RAZOR_DETAIL_POSTUN:
429 pool = set->string_pool.data;
430 return &pool[package->postun.body];
433 fprintf(stderr, "type %u not found\n", type);
438 static const char *const *
439 razor_package_get_details_array(struct razor_set *set,
440 struct razor_package *package,
441 enum razor_detail_type type)
444 case RAZOR_DETAIL_PREFIXES:
445 /* We don't track prefixes in packages. Install prefixes
446 * are tracked, but we don't provide an API to get them.
451 fprintf(stderr, "type %u not found\n", type);
457 * razor_package_get_details_varg:
459 * @package: a %razor_package
460 * @args: a va_list of arguments to set
463 razor_package_get_details_varg(struct razor_set *set,
464 struct razor_package *package,
468 enum razor_detail_type type;
470 const char *const **array;
472 for (i = 0;; i += 2) {
473 type = va_arg(args, enum razor_detail_type);
474 if (type == RAZOR_DETAIL_LAST)
476 if (type == RAZOR_DETAIL_PREFIXES) {
477 array = va_arg(args, const char *const **);
478 *array = razor_package_get_details_array(set, package,
481 string = va_arg(args, const char **);
482 *string = razor_package_get_details_string(set, package,
490 * razor_package_get_details:
492 * @package: a %razor_package
494 * Gets details about a package using a varg interface
495 * The vararg must be terminated with %RAZOR_DETAIL_LAST.
497 * Example: razor_package_get_details (set, package,
498 * RAZOR_DETAIL_URL, &url,
499 * RAZOR_DETAIL_LAST);
502 razor_package_get_details(struct razor_set *set, struct razor_package *package, ...)
506 assert (set != NULL);
507 assert (package != NULL);
509 va_start(args, NULL);
510 razor_package_get_details_varg (set, package, args);
515 * razor_package_remove:
517 * @package: a %razor_package
518 * @root: the root into which the package is currently installed
520 * Removes an installed package.
523 razor_package_remove(struct razor_set *set, struct razor_package *package,
526 struct razor_file_iterator *fi;
527 struct razor_package_iterator *pi;
528 struct razor_package *p;
529 char buffer[PATH_MAX];
530 const char *name, *program, *script;
531 int retval = 0, i, count;
532 struct environment env;
536 razor_package_get_details(set, package,
537 RAZOR_DETAIL_PREUNPROG, &program,
538 RAZOR_DETAIL_PREUN, &script,
541 if (razor_run_script(root, RAZOR_PROPERTY_PREUN, program, script))
544 fi = razor_file_iterator_create(set, package);
546 while (!retval && razor_file_iterator_next(fi, &name)) {
547 pi = razor_package_iterator_create_for_file(set, name);
549 while (razor_package_iterator_next(pi, &p, RAZOR_DETAIL_LAST))
551 razor_package_iterator_destroy(pi);
553 snprintf(buffer, sizeof buffer, "%s%s", root, name);
554 retval = remove(buffer);
558 razor_file_iterator_destroy(fi);
563 razor_package_get_details(set, package,
564 RAZOR_DETAIL_POSTUNPROG, &program,
565 RAZOR_DETAIL_POSTUN, &script,
568 environment_init(&env);
569 link = list_first(&package->install_prefixes, &set->prefix_pool);
570 for (i = 0; link; i++) {
571 prefix = (const char *)set->string_pool.data + link->data;
572 sprintf(buffer, "RPM_INSTALL_PREFIX%d", i);
573 environment_add_variable(&env, buffer, prefix);
574 link = list_next(link);
576 environment_set(&env);
578 retval = razor_run_script(root, RAZOR_PROPERTY_POSTUN, program, script);
580 environment_unset(&env);
581 environment_release(&env);
586 RAZOR_EXPORT const char *
587 razor_property_relation_to_string(struct razor_property *p)
591 switch (p->flags & RAZOR_PROPERTY_RELATION_MASK) {
592 case RAZOR_PROPERTY_LESS:
595 case RAZOR_PROPERTY_LESS | RAZOR_PROPERTY_EQUAL:
598 case RAZOR_PROPERTY_EQUAL:
601 case RAZOR_PROPERTY_GREATER | RAZOR_PROPERTY_EQUAL:
604 case RAZOR_PROPERTY_GREATER:
612 RAZOR_EXPORT const char *
613 razor_property_type_to_string(struct razor_property *p)
617 switch (p->flags & RAZOR_PROPERTY_TYPE_MASK) {
618 case RAZOR_PROPERTY_REQUIRES:
620 case RAZOR_PROPERTY_PROVIDES:
622 case RAZOR_PROPERTY_CONFLICTS:
624 case RAZOR_PROPERTY_OBSOLETES:
631 RAZOR_EXPORT struct razor_entry *
632 razor_set_find_entry(struct razor_set *set,
633 struct razor_entry *dir, const char *pattern)
635 struct razor_entry *e, *subdir;
636 const char *n, *pool = set->file_string_pool.data;
639 assert (set != NULL);
640 assert (dir != NULL);
641 assert (pattern != NULL);
646 if (strcmp(pattern, n) == 0)
649 if (e->start != 0 && strncmp(pattern, n, len) == 0 &&
650 pattern[len] == '/') {
651 subdir = (struct razor_entry *) set->files.data +
653 return razor_set_find_entry(set, subdir,
656 } while (!((e++)->flags & RAZOR_ENTRY_LAST));
662 list_dir(struct razor_set *set, struct razor_entry *dir,
663 char *prefix, const char *pattern)
665 struct razor_entry *e, *subdir;
666 const char *n, *pool = set->file_string_pool.data;
671 if (pattern && pattern[0] && fnmatch(pattern, n, 0) != 0)
673 printf("%s/%s\n", prefix, n);
675 char *sub = prefix + strlen (prefix);
678 subdir = (struct razor_entry *) set->files.data +
680 list_dir(set, subdir, prefix, pattern);
683 } while (!((e++)->flags & RAZOR_ENTRY_LAST));
687 razor_set_list_files(struct razor_set *set, const char *pattern)
689 struct razor_entry *root, *e;
690 char buffer[512], *p, *base;
692 assert (set != NULL);
694 root = (struct razor_entry *) set->files.data;
696 if (pattern == NULL) {
697 p = set->file_string_pool.data;
701 strcpy(buffer, p + e->name);
702 list_dir(set, root + e->start, buffer, NULL);
704 } while (!((e++)->flags & RAZOR_ENTRY_LAST));
708 strcpy(buffer, pattern);
709 e = razor_set_find_entry(set, root, buffer);
713 p = strrchr(buffer, '/');
721 e = razor_set_find_entry(set, root, buffer);
723 list_dir(set, root + e->start, buffer, base);
727 razor_set_list_package_files(struct razor_set *set,
728 struct razor_package *package)
730 struct razor_file_iterator *fi;
733 assert (set != NULL);
734 assert (package != NULL);
736 fi = razor_file_iterator_create(set, package);
738 while (razor_file_iterator_next(fi, &name))
739 printf("%s\n", name);
741 razor_file_iterator_destroy(fi);
745 razor_set_diff(struct razor_set *set, struct razor_set *upstream,
746 razor_diff_callback_t callback, void *data)
748 struct razor_package_iterator *pi1, *pi2;
749 struct razor_package *p1, *p2;
750 const char *name1, *name2, *version1, *version2, *arch1, *arch2;
753 assert (set != NULL);
754 assert (upstream != NULL);
756 pi1 = razor_package_iterator_create(set);
757 pi2 = razor_package_iterator_create(upstream);
759 razor_package_iterator_next(pi1, &p1,
760 RAZOR_DETAIL_NAME, &name1,
761 RAZOR_DETAIL_VERSION, &version1,
762 RAZOR_DETAIL_ARCH, &arch1,
764 razor_package_iterator_next(pi2, &p2,
765 RAZOR_DETAIL_NAME, &name2,
766 RAZOR_DETAIL_VERSION, &version2,
767 RAZOR_DETAIL_ARCH, &arch2,
772 res = strcmp(name1, name2);
774 res = razor_versioncmp(version1, version2);
779 if (p2 == NULL || res < 0)
780 callback(RAZOR_DIFF_ACTION_REMOVE,
781 p1, name1, version1, arch1, data);
782 else if (p1 == NULL || res > 0)
783 callback(RAZOR_DIFF_ACTION_ADD,
784 p2, name2, version2, arch2, data);
786 if (p1 != NULL && res <= 0)
787 razor_package_iterator_next(pi1, &p1,
788 RAZOR_DETAIL_NAME, &name1,
789 RAZOR_DETAIL_VERSION, &version1,
790 RAZOR_DETAIL_ARCH, &arch1,
792 if (p2 != NULL && res >= 0)
793 razor_package_iterator_next(pi2, &p2,
794 RAZOR_DETAIL_NAME, &name2,
795 RAZOR_DETAIL_VERSION, &version2,
796 RAZOR_DETAIL_ARCH, &arch2,
800 razor_package_iterator_destroy(pi1);
801 razor_package_iterator_destroy(pi2);
804 struct install_action {
805 enum razor_install_action action;
806 struct razor_package *package;
809 struct razor_install_iterator {
810 struct razor_set *set;
811 struct razor_set *next;
812 struct array actions;
817 add_action(enum razor_diff_action action,
818 struct razor_package *package,
824 struct razor_install_iterator *ii = data;
825 struct install_action *a;
827 a = array_add(&ii->actions, sizeof *a);
828 a->package = package;
831 case RAZOR_DIFF_ACTION_ADD:
832 a->action = RAZOR_INSTALL_ACTION_ADD;
834 case RAZOR_DIFF_ACTION_REMOVE:
835 a->action = RAZOR_INSTALL_ACTION_REMOVE;
840 RAZOR_EXPORT struct razor_install_iterator *
841 razor_set_create_install_iterator(struct razor_set *set,
842 struct razor_set *next)
844 struct razor_install_iterator *ii;
845 struct razor_property *prop;
846 /* A graph of the actions to be perfomed where
847 * A->B means action A should follow action B.
849 struct graph follows;
850 struct install_action *actions, *ai, *aj;
851 int i, j, count, vertex_added;
853 struct razor_set *rs;
855 assert (set != NULL);
856 assert (next != NULL);
858 ii = zalloc(sizeof *ii);
862 razor_set_diff(set, next, add_action, ii);
864 actions = ii->actions.data;
865 count = ii->actions.size / sizeof (struct install_action);
867 graph_init(&follows);
869 for(i = 0; i < count; i++) {
871 rs = ai->action == RAZOR_INSTALL_ACTION_ADD ? next : set;
873 link = list_first(&ai->package->properties, &rs->property_pool);
874 for(; link; link = list_next(link)) {
875 prop = rs->properties.data;
877 switch(prop->flags & RAZOR_PROPERTY_TYPE_MASK) {
878 case RAZOR_PROPERTY_REQUIRES:
879 case RAZOR_PROPERTY_CONFLICTS:
880 for(j = 0; j < count; j++) {
884 if (aj->package->name == prop->name) {
886 RAZOR_INSTALL_ACTION_ADD)
887 graph_add_edge(&follows,
890 graph_add_edge(&follows,
898 if (ai->action == RAZOR_INSTALL_ACTION_ADD) {
899 for(j = 0; j < count; j++) {
903 if (aj->package == ai->package &&
904 aj->action == RAZOR_INSTALL_ACTION_REMOVE) {
905 graph_add_edge(&follows, i, j);
911 graph_add_edge(&follows, i, i);
914 ii->order = graph_sort(&follows);
915 graph_release(&follows);
921 razor_install_iterator_next(struct razor_install_iterator *ii,
922 struct razor_set **set,
923 struct razor_package **package,
924 enum razor_install_action *action,
927 struct install_action *a;
928 if (deque_empty(ii->order))
931 a = (struct install_action *)ii->actions.data + deque_pop(ii->order);
933 case RAZOR_INSTALL_ACTION_ADD:
936 case RAZOR_INSTALL_ACTION_REMOVE:
941 *package = a->package;
949 razor_install_iterator_destroy(struct razor_install_iterator *ii)
951 array_release(&ii->actions);
952 deque_free(ii->order);