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
476 * Removes an installed package.
479 razor_package_remove(struct razor_set *set, struct razor_package *package,
482 struct razor_file_iterator *fi;
483 struct razor_package_iterator *pi;
484 struct razor_package *p;
485 char buffer[PATH_MAX];
486 const char *name, *program, *script;
487 int retval = 0, i, count;
488 struct environment env;
492 environment_init(&env);
493 link = list_first(&package->install_prefixes, &set->prefix_pool);
494 for (i = 0; link; i++) {
495 prefix = (const char *)set->string_pool.data + link->data;
496 sprintf(buffer, "RPM_INSTALL_PREFIX%d", i);
497 environment_add_variable(&env, buffer, prefix);
498 link = list_next(link);
501 razor_package_get_details(set, package,
502 RAZOR_DETAIL_PREUNPROG, &program,
503 RAZOR_DETAIL_PREUN, &script,
506 environment_set(&env);
507 retval = razor_run_script(root, RAZOR_PROPERTY_PREUN, program, script);
508 environment_unset(&env);
511 environment_release(&env);
515 fi = razor_file_iterator_create(set, package);
517 while (!retval && razor_file_iterator_next(fi, &name)) {
518 pi = razor_package_iterator_create_for_file(set, name);
520 while (razor_package_iterator_next(pi, &p, RAZOR_DETAIL_LAST))
522 razor_package_iterator_destroy(pi);
524 snprintf(buffer, sizeof buffer, "%s%s", root, name);
525 retval = remove(buffer);
529 razor_file_iterator_destroy(fi);
532 environment_release(&env);
536 razor_package_get_details(set, package,
537 RAZOR_DETAIL_POSTUNPROG, &program,
538 RAZOR_DETAIL_POSTUN, &script,
541 environment_set(&env);
542 retval = razor_run_script(root, RAZOR_PROPERTY_POSTUN, program, script);
543 environment_unset(&env);
545 environment_release(&env);
550 RAZOR_EXPORT const char *
551 razor_property_relation_to_string(struct razor_property *p)
555 switch (p->flags & RAZOR_PROPERTY_RELATION_MASK) {
556 case RAZOR_PROPERTY_LESS:
559 case RAZOR_PROPERTY_LESS | RAZOR_PROPERTY_EQUAL:
562 case RAZOR_PROPERTY_EQUAL:
565 case RAZOR_PROPERTY_GREATER | RAZOR_PROPERTY_EQUAL:
568 case RAZOR_PROPERTY_GREATER:
576 RAZOR_EXPORT const char *
577 razor_property_type_to_string(struct razor_property *p)
581 switch (p->flags & RAZOR_PROPERTY_TYPE_MASK) {
582 case RAZOR_PROPERTY_REQUIRES:
584 case RAZOR_PROPERTY_PROVIDES:
586 case RAZOR_PROPERTY_CONFLICTS:
588 case RAZOR_PROPERTY_OBSOLETES:
595 RAZOR_EXPORT struct razor_entry *
596 razor_set_find_entry(struct razor_set *set,
597 struct razor_entry *dir, const char *pattern)
599 struct razor_entry *e, *subdir;
600 const char *n, *pool = set->file_string_pool.data;
603 assert (set != NULL);
604 assert (dir != NULL);
605 assert (pattern != NULL);
610 if (strcmp(pattern, n) == 0)
613 if (e->start != 0 && strncmp(pattern, n, len) == 0 &&
614 pattern[len] == '/') {
615 subdir = (struct razor_entry *) set->files.data +
617 return razor_set_find_entry(set, subdir,
620 } while (!((e++)->flags & RAZOR_ENTRY_LAST));
626 list_dir(struct razor_set *set, struct razor_entry *dir,
627 char *prefix, const char *pattern)
629 struct razor_entry *e, *subdir;
630 const char *n, *pool = set->file_string_pool.data;
635 if (pattern && pattern[0] && fnmatch(pattern, n, 0) != 0)
637 printf("%s/%s\n", prefix, n);
639 char *sub = prefix + strlen (prefix);
642 subdir = (struct razor_entry *) set->files.data +
644 list_dir(set, subdir, prefix, pattern);
647 } while (!((e++)->flags & RAZOR_ENTRY_LAST));
651 razor_set_list_files(struct razor_set *set, const char *pattern)
653 struct razor_entry *root, *e;
654 char buffer[512], *p, *base;
656 assert (set != NULL);
658 root = (struct razor_entry *) set->files.data;
660 if (pattern == NULL) {
661 p = set->file_string_pool.data;
665 strcpy(buffer, p + e->name);
666 list_dir(set, root + e->start, buffer, NULL);
668 } while (!((e++)->flags & RAZOR_ENTRY_LAST));
672 strcpy(buffer, pattern);
673 e = razor_set_find_entry(set, root, buffer);
677 p = strrchr(buffer, '/');
685 e = razor_set_find_entry(set, root, buffer);
687 list_dir(set, root + e->start, buffer, base);
691 razor_set_list_package_files(struct razor_set *set,
692 struct razor_package *package)
694 struct razor_file_iterator *fi;
697 assert (set != NULL);
698 assert (package != NULL);
700 fi = razor_file_iterator_create(set, package);
702 while (razor_file_iterator_next(fi, &name))
703 printf("%s\n", name);
705 razor_file_iterator_destroy(fi);
709 razor_set_diff(struct razor_set *set, struct razor_set *upstream,
710 razor_diff_callback_t callback, void *data)
712 struct razor_package_iterator *pi1, *pi2;
713 struct razor_package *p1, *p2;
714 const char *name1, *name2, *version1, *version2, *arch1, *arch2;
717 assert (set != NULL);
718 assert (upstream != NULL);
720 pi1 = razor_package_iterator_create(set);
721 pi2 = razor_package_iterator_create(upstream);
723 razor_package_iterator_next(pi1, &p1,
724 RAZOR_DETAIL_NAME, &name1,
725 RAZOR_DETAIL_VERSION, &version1,
726 RAZOR_DETAIL_ARCH, &arch1,
728 razor_package_iterator_next(pi2, &p2,
729 RAZOR_DETAIL_NAME, &name2,
730 RAZOR_DETAIL_VERSION, &version2,
731 RAZOR_DETAIL_ARCH, &arch2,
736 res = strcmp(name1, name2);
738 res = razor_versioncmp(version1, version2);
743 if (p2 == NULL || res < 0)
744 callback(RAZOR_DIFF_ACTION_REMOVE,
745 p1, name1, version1, arch1, data);
746 else if (p1 == NULL || res > 0)
747 callback(RAZOR_DIFF_ACTION_ADD,
748 p2, name2, version2, arch2, data);
750 if (p1 != NULL && res <= 0)
751 razor_package_iterator_next(pi1, &p1,
752 RAZOR_DETAIL_NAME, &name1,
753 RAZOR_DETAIL_VERSION, &version1,
754 RAZOR_DETAIL_ARCH, &arch1,
756 if (p2 != NULL && res >= 0)
757 razor_package_iterator_next(pi2, &p2,
758 RAZOR_DETAIL_NAME, &name2,
759 RAZOR_DETAIL_VERSION, &version2,
760 RAZOR_DETAIL_ARCH, &arch2,
764 razor_package_iterator_destroy(pi1);
765 razor_package_iterator_destroy(pi2);
768 struct install_action {
769 enum razor_install_action action;
770 struct razor_package *package;
773 struct razor_install_iterator {
774 struct razor_set *set;
775 struct razor_set *next;
776 struct array actions;
781 add_action(enum razor_diff_action action,
782 struct razor_package *package,
788 struct razor_install_iterator *ii = data;
789 struct install_action *a;
791 a = array_add(&ii->actions, sizeof *a);
792 a->package = package;
795 case RAZOR_DIFF_ACTION_ADD:
796 a->action = RAZOR_INSTALL_ACTION_ADD;
798 case RAZOR_DIFF_ACTION_REMOVE:
799 a->action = RAZOR_INSTALL_ACTION_REMOVE;
804 RAZOR_EXPORT struct razor_install_iterator *
805 razor_set_create_install_iterator(struct razor_set *set,
806 struct razor_set *next)
808 struct razor_install_iterator *ii;
809 struct razor_property *prop;
810 /* A graph of the actions to be perfomed where
811 * A->B means action A should follow action B.
813 struct graph follows;
814 struct install_action *actions, *ai, *aj;
815 int i, j, count, vertex_added;
817 struct razor_set *rs;
819 assert (set != NULL);
820 assert (next != NULL);
822 ii = zalloc(sizeof *ii);
826 razor_set_diff(set, next, add_action, ii);
828 actions = ii->actions.data;
829 count = ii->actions.size / sizeof (struct install_action);
831 graph_init(&follows);
833 for(i = 0; i < count; i++) {
835 rs = ai->action == RAZOR_INSTALL_ACTION_ADD ? next : set;
837 link = list_first(&ai->package->properties, &rs->property_pool);
838 for(; link; link = list_next(link)) {
839 prop = rs->properties.data;
841 switch(prop->flags & RAZOR_PROPERTY_TYPE_MASK) {
842 case RAZOR_PROPERTY_REQUIRES:
843 case RAZOR_PROPERTY_CONFLICTS:
844 for(j = 0; j < count; j++) {
848 if (aj->package->name == prop->name) {
850 RAZOR_INSTALL_ACTION_ADD)
851 graph_add_edge(&follows,
854 graph_add_edge(&follows,
862 if (ai->action == RAZOR_INSTALL_ACTION_ADD) {
863 for(j = 0; j < count; j++) {
867 if (aj->package == ai->package &&
868 aj->action == RAZOR_INSTALL_ACTION_REMOVE) {
869 graph_add_edge(&follows, i, j);
875 graph_add_edge(&follows, i, i);
878 ii->order = graph_sort(&follows);
879 graph_release(&follows);
885 razor_install_iterator_next(struct razor_install_iterator *ii,
886 struct razor_set **set,
887 struct razor_package **package,
888 enum razor_install_action *action,
891 struct install_action *a;
892 if (deque_empty(ii->order))
895 a = (struct install_action *)ii->actions.data + deque_pop(ii->order);
897 case RAZOR_INSTALL_ACTION_ADD:
900 case RAZOR_INSTALL_ACTION_REMOVE:
905 *package = a->package;
913 razor_install_iterator_destroy(struct razor_install_iterator *ii)
915 array_release(&ii->actions);
916 deque_free(ii->order);