rhughes@241: /* rhughes@241: * Copyright (C) 2008 Kristian Høgsberg rhughes@241: * Copyright (C) 2008 Red Hat, Inc ali@475: * Copyright (C) 2009-2012, 2016 J. Ali Harlow rhughes@241: * rhughes@241: * This program is free software; you can redistribute it and/or modify rhughes@241: * it under the terms of the GNU General Public License as published by rhughes@241: * the Free Software Foundation; either version 2 of the License, or rhughes@241: * (at your option) any later version. rhughes@241: * rhughes@241: * This program is distributed in the hope that it will be useful, rhughes@241: * but WITHOUT ANY WARRANTY; without even the implied warranty of rhughes@241: * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the rhughes@241: * GNU General Public License for more details. rhughes@241: * rhughes@241: * You should have received a copy of the GNU General Public License along rhughes@241: * with this program; if not, write to the Free Software Foundation, Inc., rhughes@241: * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. rhughes@241: */ rhughes@241: rhughes@241: #define _GNU_SOURCE rhughes@241: ali@334: #include "config.h" ali@334: rhughes@241: #include rhughes@241: #include rhughes@241: #include rhughes@241: #include richard@302: #include rhughes@241: #include ali@475: #include rhughes@241: #include rhughes@241: #include rhughes@241: #include rhughes@241: #include ali@369: #include richard@301: #include ali@388: #ifdef MSWIN_API ali@388: #include ali@388: #endif rhughes@241: krh@253: #include "razor-internal.h" rhughes@241: #include "razor.h" rhughes@241: ali@345: #ifndef O_BINARY ali@345: #define O_BINARY 0 ali@345: #endif ali@345: jbowes@318: struct razor_set_section_index { jbowes@318: const char *name; jbowes@318: uint32_t offset; krh@373: uint32_t flags; jbowes@318: }; jbowes@318: krh@373: #define MAIN(type, field) \ krh@373: { type, offsetof(struct razor_set, field), RAZOR_SECTION_MAIN } krh@373: #define FILES(type, field) \ krh@373: { type, offsetof(struct razor_set, field), RAZOR_SECTION_FILES } krh@373: #define DETAILS(type, field) \ krh@373: { type, offsetof(struct razor_set, field), RAZOR_SECTION_DETAILS } krh@373: jbowes@318: struct razor_set_section_index razor_sections[] = { krh@373: MAIN(RAZOR_STRING_POOL, string_pool), krh@373: MAIN(RAZOR_PACKAGES, packages), krh@373: MAIN(RAZOR_PROPERTIES, properties), krh@373: MAIN(RAZOR_PACKAGE_POOL, package_pool), krh@373: MAIN(RAZOR_PROPERTY_POOL, property_pool), krh@373: MAIN(RAZOR_PREFIX_POOL, prefix_pool), krh@373: FILES(RAZOR_FILES, files), krh@373: FILES(RAZOR_FILE_POOL, file_pool), krh@373: FILES(RAZOR_FILE_STRING_POOL, file_string_pool), krh@373: DETAILS(RAZOR_DETAILS_STRING_POOL, details_string_pool) jbowes@258: }; krh@262: krh@269: RAZOR_EXPORT struct razor_set * ali@363: razor_set_create_without_root(void) ali@363: { ali@363: struct razor_set *set; ali@363: char *empty; ali@363: ali@363: set = zalloc(sizeof *set); ali@363: ali@403: if (set) { ali@403: empty = array_add(&set->string_pool, 1); ali@403: *empty = '\0'; ali@363: ali@403: set->lock_fd = -1; ali@403: ali@403: set->ref_count = 1; ali@403: ali@403: set->header_version = RAZOR_HEADER_VERSION; ali@424: ali@424: set->flags = RAZOR_SET_PRIVATE; ali@403: } ali@388: ali@363: return set; ali@363: } ali@363: ali@363: RAZOR_EXPORT struct razor_set * rhughes@241: razor_set_create(void) rhughes@241: { rhughes@241: struct razor_set *set; rhughes@241: struct razor_entry *e; rhughes@241: ali@363: set = razor_set_create_without_root(); rhughes@241: rhughes@241: e = array_add(&set->files, sizeof *e); rhughes@241: e->name = 0; rhughes@241: e->flags = RAZOR_ENTRY_LAST; rhughes@241: e->start = 0; rhughes@241: list_set_empty(&e->packages); rhughes@241: rhughes@241: return set; rhughes@241: } rhughes@241: ali@403: RAZOR_EXPORT uint32_t ali@403: razor_set_get_header_version(struct razor_set *set) ali@403: { ali@403: return set->header_version; ali@403: } ali@403: ali@403: RAZOR_EXPORT int ali@403: razor_set_set_header_version(struct razor_set *set, uint32_t header_version) ali@403: { ali@403: if (header_versionRAZOR_HEADER_VERSION) ali@403: return -1; ali@403: else { ali@403: set->header_version = header_version; ali@403: return 0; ali@403: } ali@403: } ali@403: krh@373: struct razor_mapped_file { krh@373: struct razor_set_header *header; krh@373: size_t size; krh@373: struct razor_mapped_file *next; krh@373: }; krh@373: krh@373: RAZOR_EXPORT int ali@475: razor_set_bind_sections(struct razor_set *set, const char *uri, ali@424: enum razor_set_flags flags, struct razor_error **error) rhughes@241: { jbowes@318: struct razor_set_section *s, *sections; krh@373: struct razor_mapped_file *file; ali@403: const char *pool, *reason; rhughes@241: struct array *array; ali@447: int i, j, code; richard@301: krh@373: file = zalloc(sizeof *file); ali@403: if (file == NULL) { ali@447: razor_set_error(error, RAZOR_POSIX_ERROR, ENOMEM, NULL, ali@447: "Not enough memory"); jbowes@288: return -1; ali@403: } jbowes@258: ali@475: file->header = razor_uri_get_contents(uri, &file->size, ali@475: flags & RAZOR_SET_PRIVATE, ali@475: error); krh@373: if (!file->header) { krh@373: free(file); krh@373: return -1; krh@373: } jbowes@318: ali@447: if (file->size < sizeof *file->header) { ali@447: code = RAZOR_GENERAL_ERROR_DATABASE_CORRUPTED; ali@403: reason = "Premature EOF"; ali@447: } else if (file->header->magic != RAZOR_MAGIC) { ali@447: code = RAZOR_GENERAL_ERROR_DATABASE_CORRUPTED; ali@403: reason = "Bad magic number"; ali@447: } else if (file->header->version < RAZOR_HEADER_VERSION_MIN || ali@447: file->header->version > RAZOR_HEADER_VERSION) { ali@447: code = RAZOR_GENERAL_ERROR_DATABASE_INCOMPATIBLE; ali@403: reason = "Incompatible file version"; ali@447: } else ali@403: reason = NULL; ali@403: ali@403: if (reason) { ali@475: razor_set_error(error, RAZOR_GENERAL_ERROR, code, uri, reason); ali@475: razor_uri_free_contents(file->header, file->size); ali@390: free(file); ali@390: return -1; ali@390: } ali@390: ali@424: set->flags = flags & RAZOR_SET_PRIVATE; ali@424: ali@403: set->header_version = file->header->version; ali@403: ali@388: if (set->mapped_files == NULL) { ali@388: for (i = 0; i < ARRAY_SIZE(razor_sections); i++) { ali@388: array = (void *) set + razor_sections[i].offset; ali@388: array_release(array); ali@388: } ali@388: } ali@388: krh@373: file->next = set->mapped_files; krh@373: set->mapped_files = file; krh@373: krh@373: sections = (void *) file->header + sizeof *file->header; krh@373: pool = (void *) sections + krh@373: file->header->num_sections * sizeof *sections; krh@373: krh@373: for (i = 0; i < file->header->num_sections; i++) { jbowes@318: s = sections + i; krh@373: for (j = 0; j < ARRAY_SIZE(razor_sections); j++) krh@373: if (!strcmp(razor_sections[j].name, &pool[s->name])) jbowes@318: break; krh@373: if (j == ARRAY_SIZE(razor_sections)) jbowes@258: continue; krh@373: array = (void *) set + razor_sections[j].offset; krh@373: array->data = (void *) file->header + s->offset; jbowes@258: array->size = s->size; jbowes@258: array->alloc = s->size; jbowes@258: } jbowes@288: jbowes@288: return 0; jbowes@258: } jbowes@258: jbowes@318: RAZOR_EXPORT struct razor_set * ali@475: razor_set_open(const char *uri, enum razor_set_flags flags, ali@424: struct razor_error **error) jbowes@318: { jbowes@318: struct razor_set *set; jbowes@318: jbowes@318: set = zalloc(sizeof *set); ali@403: if (!set) { ali@447: razor_set_error(error, RAZOR_POSIX_ERROR, ENOMEM, NULL, ali@447: "Not enough memory"); ali@403: return NULL; ali@403: } ali@403: ali@388: set->lock_fd = -1; ali@406: set->ref_count = 1; ali@475: if (razor_set_bind_sections(set, uri, flags, error)) { jbowes@318: free(set); jbowes@318: return NULL; jbowes@318: } jbowes@318: return set; jbowes@318: } jbowes@318: ali@388: int ali@475: razor_set_acquire_lock(struct razor_set *set, const char *uri, int exclusive) ali@388: { ali@388: int fd; ali@388: assert(set != NULL); ali@388: ali@475: if (uri) { ali@475: fd = razor_uri_open(uri, O_CREAT | O_RDWR | O_TRUNC | O_BINARY, ali@475: 0666, NULL); ali@388: if (fd < 0) ali@388: return -1; ali@475: } else ali@388: fd = -1; ali@388: ali@388: #ifdef MSWIN_API ali@388: DWORD flags = LOCKFILE_FAIL_IMMEDIATELY; ali@388: OVERLAPPED lock = {0}; ali@388: ali@388: if (exclusive) ali@388: flags |= LOCKFILE_EXCLUSIVE_LOCK; ali@403: if (fd >= 0 && !LockFileEx((HANDLE)_get_osfhandle(fd), flags, 0, 1, 0, ali@403: &lock)) { ali@388: close(fd); ali@388: return -1; ali@388: } ali@388: if (set->lock_fd >= 0) ali@403: (void)UnlockFile((HANDLE)_get_osfhandle(set->lock_fd), 0, 0, 1, ali@403: 0); ali@388: #else ali@388: struct flock lock = {0}; ali@388: ali@388: lock.l_type = exclusive ? F_WRLCK : F_RDLCK; ali@388: lock.l_whence = SEEK_SET; ali@388: lock.l_start = 0; ali@388: lock.l_len = 0; ali@388: if (fd >= 0 && fcntl(fd, F_SETLK, &lock) < 0) { ali@388: close(fd); ali@388: return -1; ali@388: } ali@388: if (set->lock_fd >= 0) { ali@388: lock.l_type = F_UNLCK; ali@388: (void)fcntl(set->lock_fd, F_SETLK, &lock); ali@388: } ali@388: #endif ali@388: ali@388: if (set->lock_fd >= 0) ali@388: close(set->lock_fd); ali@388: set->lock_fd = fd; ali@388: ali@388: return 0; ali@388: } ali@388: ali@403: static void rhughes@241: razor_set_destroy(struct razor_set *set) rhughes@241: { krh@373: struct razor_mapped_file *file, *next; krh@373: struct array *array; rhughes@241: int i; rhughes@241: richard@301: assert (set != NULL); richard@301: krh@373: if (set->mapped_files == NULL) { krh@373: for (i = 0; i < ARRAY_SIZE(razor_sections); i++) { krh@373: array = (void *) set + razor_sections[i].offset; krh@373: array_release(array); krh@373: } rhughes@241: } else { krh@373: for (file = set->mapped_files; file != NULL; file = next) { krh@373: next = file->next; ali@475: razor_uri_free_contents(file->header, file->size); krh@373: free(file); jbowes@258: } jbowes@258: } jbowes@258: ali@475: razor_set_acquire_lock(set, NULL, 0); rhughes@241: free(set); rhughes@241: } rhughes@241: ali@403: RAZOR_EXPORT void ali@403: razor_set_unref(struct razor_set *set) ali@403: { ali@403: if (set && !--set->ref_count) ali@403: razor_set_destroy(set); ali@403: } ali@403: ali@403: RAZOR_EXPORT struct razor_set * ali@403: razor_set_ref(struct razor_set *set) ali@403: { ali@403: if (set) ali@403: set->ref_count++; ali@403: return set; ali@403: } ali@403: ali@403: RAZOR_EXPORT void ali@403: razor_set_write_to_handle(struct razor_set *set, struct razor_atomic *atomic, ali@403: int handle, uint32_t section_mask) rhughes@241: { jbowes@318: struct razor_set_header header; krh@373: struct razor_set_section sections[ARRAY_SIZE(razor_sections)]; jbowes@318: struct hashtable table; krh@373: struct array pool, *arrays[ARRAY_SIZE(razor_sections)]; rhughes@241: uint32_t offset; krh@373: int count, i, j; krh@373: static const char padding[4]; jbowes@318: jbowes@318: array_init(&pool); jbowes@318: hashtable_init(&table, &pool); jbowes@318: krh@373: j = 0; krh@373: for (i = 0; i < ARRAY_SIZE(razor_sections); i++) { krh@373: if ((razor_sections[i].flags & section_mask) == 0) krh@373: continue; jbowes@318: krh@373: arrays[j] = (void *) set + razor_sections[i].offset; krh@373: sections[j].name = krh@373: hashtable_tokenize(&table, razor_sections[i].name); krh@373: j++; krh@373: } rhughes@241: krh@373: count = j; krh@373: header.magic = RAZOR_MAGIC; ali@403: header.version = set->header_version; krh@373: header.num_sections = count; krh@373: offset = sizeof header + count * sizeof *sections + ALIGN(pool.size, 4); krh@373: krh@373: for (i = 0; i < count; i++) { krh@373: sections[i].offset = offset; krh@373: sections[i].size = arrays[i]->size; krh@373: offset += ALIGN(arrays[i]->size, 4); rhughes@241: } rhughes@241: ali@403: razor_atomic_write(atomic, handle, &header, sizeof header); ali@403: razor_atomic_write(atomic, handle, sections, count * sizeof *sections); ali@403: razor_atomic_write(atomic, handle, pool.data, pool.size); ali@403: razor_atomic_write(atomic, handle, padding, PADDING(pool.size, 4)); rhughes@241: krh@373: for (i = 0; i < count; i++) { ali@403: razor_atomic_write(atomic, handle, arrays[i]->data, ali@403: arrays[i]->size); ali@403: razor_atomic_write(atomic, handle, padding, ali@403: PADDING(arrays[i]->size, 4)); rhughes@241: } rhughes@241: krh@373: array_release(&pool); krh@373: hashtable_release(&table); rhughes@241: } rhughes@241: krh@269: RAZOR_EXPORT int ali@403: razor_set_write(struct razor_set *set, struct razor_atomic *atomic, ali@475: const char *uri, uint32_t sections) rhughes@241: { ali@403: int h; rhughes@241: ali@475: h = razor_atomic_create_file(atomic, uri, ali@403: S_IRWXU | S_IRWXG | S_IRWXO); ali@403: if (h < 0) rhughes@241: return -1; rhughes@241: ali@403: razor_set_write_to_handle(set, atomic, h, sections); rhughes@241: ali@403: return razor_atomic_close(atomic, h); rhughes@241: } krh@269: krh@269: RAZOR_EXPORT void rhughes@241: razor_build_evr(char *evr_buf, int size, const char *epoch, rhughes@241: const char *version, const char *release) rhughes@241: { rhughes@241: int len; rhughes@241: rhughes@241: if (!version || !*version) { rhughes@241: *evr_buf = '\0'; rhughes@241: return; rhughes@241: } rhughes@241: rhughes@241: if (epoch && *epoch && strcmp(epoch, "0") != 0) { rhughes@241: len = snprintf(evr_buf, size, "%s:", epoch); rhughes@241: evr_buf += len; rhughes@241: size -= len; rhughes@241: } rhughes@241: len = snprintf(evr_buf, size, "%s", version); rhughes@241: evr_buf += len; rhughes@241: size -= len; rhughes@241: if (release && *release) rhughes@241: snprintf(evr_buf, size, "-%s", release); rhughes@241: } rhughes@241: krh@269: RAZOR_EXPORT int krh@248: razor_versioncmp(const char *s1, const char *s2) rhughes@241: { rhughes@241: const char *p1, *p2; rhughes@241: long n1, n2; rhughes@241: int res; rhughes@241: richard@301: assert (s1 != NULL); richard@301: assert (s2 != NULL); richard@301: rhughes@241: n1 = strtol(s1, (char **) &p1, 10); rhughes@241: n2 = strtol(s2, (char **) &p2, 10); rhughes@241: rhughes@241: /* Epoch; if one but not the other has an epoch set, default rhughes@241: * the epoch-less version to 0. */ rhughes@241: res = (*p1 == ':') - (*p2 == ':'); rhughes@241: if (res < 0) { rhughes@241: n1 = 0; rhughes@241: p1 = s1; rhughes@241: p2++; rhughes@241: } else if (res > 0) { rhughes@241: p1++; rhughes@241: n2 = 0; rhughes@241: p2 = s2; rhughes@241: } rhughes@241: rhughes@241: if (n1 != n2) rhughes@241: return n1 - n2; rhughes@241: while (*p1 && *p2) { rhughes@241: if (*p1 != *p2) rhughes@241: return *p1 - *p2; rhughes@241: p1++; rhughes@241: p2++; rhughes@241: if (isdigit(*p1) && isdigit(*p2)) krh@248: return razor_versioncmp(p1, p2); rhughes@241: } rhughes@241: rhughes@241: return *p1 - *p2; rhughes@241: } rhughes@241: richard@302: static const char * ali@372: razor_package_get_details_string(struct razor_set *set, ali@372: struct razor_package *package, ali@372: enum razor_detail_type type) richard@302: { richard@302: const char *pool; richard@302: richard@302: switch (type) { richard@302: case RAZOR_DETAIL_NAME: richard@302: pool = set->string_pool.data; richard@302: return &pool[package->name]; richard@302: richard@302: case RAZOR_DETAIL_VERSION: richard@302: pool = set->string_pool.data; richard@302: return &pool[package->version]; richard@302: richard@302: case RAZOR_DETAIL_ARCH: richard@302: pool = set->string_pool.data; richard@302: return &pool[package->arch]; richard@302: richard@302: case RAZOR_DETAIL_SUMMARY: ali@395: if (!set->details_string_pool.size) ali@395: return ""; richard@302: pool = set->details_string_pool.data; richard@302: return &pool[package->summary]; richard@302: richard@302: case RAZOR_DETAIL_DESCRIPTION: ali@395: if (!set->details_string_pool.size) ali@395: return ""; richard@302: pool = set->details_string_pool.data; richard@302: return &pool[package->description]; richard@302: richard@302: case RAZOR_DETAIL_URL: ali@395: if (!set->details_string_pool.size) ali@395: return ""; richard@302: pool = set->details_string_pool.data; richard@302: return &pool[package->url]; richard@302: richard@302: case RAZOR_DETAIL_LICENSE: ali@395: if (!set->details_string_pool.size) ali@395: return ""; richard@302: pool = set->details_string_pool.data; richard@302: return &pool[package->license]; richard@302: ali@369: case RAZOR_DETAIL_PREUNPROG: ali@369: pool = set->string_pool.data; ali@369: return &pool[package->preun.program]; ali@369: ali@369: case RAZOR_DETAIL_PREUN: ali@369: pool = set->string_pool.data; ali@369: return &pool[package->preun.body]; ali@369: ali@369: case RAZOR_DETAIL_POSTUNPROG: ali@369: pool = set->string_pool.data; ali@369: return &pool[package->postun.program]; ali@369: ali@369: case RAZOR_DETAIL_POSTUN: ali@369: pool = set->string_pool.data; ali@369: return &pool[package->postun.body]; ali@369: richard@302: default: richard@302: fprintf(stderr, "type %u not found\n", type); richard@302: return NULL; richard@302: } richard@302: } richard@302: ali@372: static const char *const * ali@372: razor_package_get_details_array(struct razor_set *set, ali@372: struct razor_package *package, ali@372: enum razor_detail_type type) ali@372: { ali@372: switch (type) { ali@372: case RAZOR_DETAIL_PREFIXES: ali@462: /* We don't track prefixes in packages. Install ali@462: * prefixes are tracked, and made available via ali@462: * razor_install_prefix_iterator_create(). ali@372: */ ali@372: return NULL; ali@372: ali@372: default: ali@372: fprintf(stderr, "type %u not found\n", type); ali@372: return NULL; ali@372: } ali@372: } ali@372: richard@302: /** richard@302: * razor_package_get_details_varg: richard@302: * @set: a %razor_set richard@302: * @package: a %razor_package richard@302: * @args: a va_list of arguments to set richard@302: **/ richard@302: void richard@302: razor_package_get_details_varg(struct razor_set *set, richard@302: struct razor_package *package, richard@302: va_list args) richard@302: { richard@302: int i; richard@302: enum razor_detail_type type; ali@372: const char **string; ali@372: const char *const **array; richard@302: richard@302: for (i = 0;; i += 2) { richard@302: type = va_arg(args, enum razor_detail_type); richard@307: if (type == RAZOR_DETAIL_LAST) richard@302: break; ali@372: if (type == RAZOR_DETAIL_PREFIXES) { ali@372: array = va_arg(args, const char *const **); ali@372: *array = razor_package_get_details_array(set, package, ali@372: type); ali@372: } else { ali@372: string = va_arg(args, const char **); ali@372: *string = razor_package_get_details_string(set, package, ali@372: type); ali@372: } richard@302: } richard@302: richard@302: } richard@302: richard@302: /** richard@302: * razor_package_get_details: richard@302: * @set: a %razor_set richard@302: * @package: a %razor_package richard@302: * richard@302: * Gets details about a package using a varg interface krh@308: * The vararg must be terminated with %RAZOR_DETAIL_LAST. richard@302: * richard@307: * Example: razor_package_get_details (set, package, richard@307: * RAZOR_DETAIL_URL, &url, richard@307: * RAZOR_DETAIL_LAST); richard@302: **/ krh@269: RAZOR_EXPORT void richard@302: razor_package_get_details(struct razor_set *set, struct razor_package *package, ...) jbowes@258: { richard@302: va_list args; jbowes@258: richard@301: assert (set != NULL); richard@301: assert (package != NULL); richard@301: richard@302: va_start(args, NULL); richard@302: razor_package_get_details_varg (set, package, args); richard@302: va_end (args); jbowes@258: } jbowes@258: ali@369: /** ali@369: * razor_package_remove: ali@382: * @prev: The %razor_set before the current transaction ali@382: * @next: The %razor_set after the current transaction is applied ali@369: * @package: a %razor_package ali@369: * @root: the root into which the package is currently installed ali@376: * @install_count: the value to pass to uninstall scripts ali@403: * @stage: Limit the removal to just the scripts or the files ali@369: * ali@369: * Removes an installed package. ali@369: **/ ali@369: RAZOR_EXPORT int ali@382: razor_package_remove(struct razor_set *prev, struct razor_set *next, ali@403: struct razor_atomic *atomic, struct razor_package *package, ali@479: const char *root_uri, int install_count, ali@403: enum razor_stage_type stage) ali@369: { ali@369: struct razor_file_iterator *fi; ali@369: struct razor_package_iterator *pi; ali@369: struct razor_package *p; ali@479: char *uri, *relative, *buffer, buf[32]; ali@369: const char *name, *program, *script; ali@422: int i, count, retval = 0; ali@372: struct environment env; ali@372: struct list *link; ali@372: const char *prefix; ali@475: struct razor_error *tmp_error = NULL; ali@369: ali@403: if (stage & RAZOR_STAGE_SCRIPTS) { ali@403: environment_init(&env); ali@403: link = list_first(&package->install_prefixes, ali@403: &prev->prefix_pool); ali@403: for (i = 0; link; i++) { ali@403: prefix = (const char *)prev->string_pool.data + ali@403: link->data; ali@411: sprintf(buf, "RPM_INSTALL_PREFIX%d", i); ali@411: environment_add_variable(&env, buf, prefix); ali@403: link = list_next(link); ali@403: } ali@403: environment_set(&env); ali@375: } ali@375: ali@403: if (stage & RAZOR_STAGE_SCRIPTS_PRE) { ali@403: razor_package_get_details(prev, package, ali@403: RAZOR_DETAIL_PREUNPROG, &program, ali@403: RAZOR_DETAIL_PREUN, &script, ali@403: RAZOR_DETAIL_LAST); ali@369: ali@479: retval = razor_run_script(root_uri, RAZOR_PROPERTY_PREUN, ali@479: program, script, install_count, ali@479: &tmp_error); ali@475: ali@475: if (retval < 0) { ali@475: razor_atomic_propagate_error(atomic, tmp_error, NULL); ali@475: tmp_error = NULL; ali@475: } ali@403: } ali@375: ali@422: if (!retval && (stage & RAZOR_STAGE_FILES)) { ali@403: fi = razor_file_iterator_create(prev, package, 1); ali@369: ali@403: while (razor_file_iterator_next(fi, &name)) { ali@403: pi = razor_package_iterator_create_for_file(next, name); ali@403: count = 0; ali@403: while (razor_package_iterator_next(pi, &p, ali@403: RAZOR_DETAIL_LAST)) ali@403: count++; ali@403: razor_package_iterator_destroy(pi); ali@403: if (count <= 0) { ali@479: uri = razor_path_to_uri(name); ali@479: ali@479: if (str_has_prefix(uri, "file:///")) ali@479: relative = uri + 8; ali@479: else if (str_has_prefix(uri, "file:/")) ali@479: relative = uri + 6; ali@479: else if (str_has_prefix(uri, "file:")) ali@479: relative = uri + 5; ali@479: else if (str_has_prefix(uri, "/")) ali@479: relative = uri + 1; ali@479: else ali@479: relative = uri; ali@479: ali@479: buffer = razor_resolve_uri_root(root_uri, ali@479: relative, 1, ali@479: &tmp_error); ali@479: free(uri); ali@479: ali@479: if (buffer) { ali@479: razor_atomic_remove(atomic, buffer); ali@479: free(buffer); ali@479: } else { ali@479: razor_atomic_propagate_error(atomic, ali@479: tmp_error, ali@479: NULL); ali@479: tmp_error = NULL; ali@479: break; ali@479: } ali@377: } ali@369: } ali@403: ali@403: razor_file_iterator_destroy(fi); ali@422: ali@422: retval = razor_atomic_in_error_state(atomic); ali@369: } ali@369: ali@422: if (!retval && (stage & RAZOR_STAGE_SCRIPTS_POST)) { ali@403: razor_package_get_details(prev, package, ali@403: RAZOR_DETAIL_POSTUNPROG, &program, ali@403: RAZOR_DETAIL_POSTUN, &script, ali@403: RAZOR_DETAIL_LAST); ali@369: ali@479: retval |= razor_run_script(root_uri, RAZOR_PROPERTY_POSTUN, ali@479: program, script, install_count, ali@479: &tmp_error); ali@475: ali@475: if (retval < 0) { ali@475: razor_atomic_propagate_error(atomic, tmp_error, NULL); ali@475: tmp_error = NULL; ali@475: } ali@403: } ali@369: ali@403: if (stage & RAZOR_STAGE_SCRIPTS) { ali@403: environment_unset(&env); ali@403: environment_release(&env); ali@403: } ali@377: ali@422: return retval; ali@369: } ali@369: krh@270: RAZOR_EXPORT const char * krh@270: razor_property_relation_to_string(struct razor_property *p) krh@270: { richard@301: assert (p != NULL); richard@301: krh@270: switch (p->flags & RAZOR_PROPERTY_RELATION_MASK) { krh@270: case RAZOR_PROPERTY_LESS: krh@270: return "<"; krh@270: krh@270: case RAZOR_PROPERTY_LESS | RAZOR_PROPERTY_EQUAL: krh@270: return "<="; krh@270: krh@270: case RAZOR_PROPERTY_EQUAL: krh@270: return "="; krh@270: krh@270: case RAZOR_PROPERTY_GREATER | RAZOR_PROPERTY_EQUAL: krh@270: return ">="; krh@270: krh@270: case RAZOR_PROPERTY_GREATER: krh@270: return ">"; krh@270: krh@270: default: krh@270: return "?"; krh@270: } krh@270: } krh@270: krh@270: RAZOR_EXPORT const char * krh@270: razor_property_type_to_string(struct razor_property *p) krh@270: { richard@301: assert (p != NULL); richard@301: krh@270: switch (p->flags & RAZOR_PROPERTY_TYPE_MASK) { krh@270: case RAZOR_PROPERTY_REQUIRES: krh@270: return "requires"; krh@270: case RAZOR_PROPERTY_PROVIDES: krh@270: return "provides"; krh@270: case RAZOR_PROPERTY_CONFLICTS: krh@270: return "conflicts"; krh@270: case RAZOR_PROPERTY_OBSOLETES: krh@270: return "obsoletes"; krh@270: default: krh@270: return NULL; krh@270: } krh@270: } krh@270: krh@269: RAZOR_EXPORT struct razor_entry * krh@248: razor_set_find_entry(struct razor_set *set, krh@248: struct razor_entry *dir, const char *pattern) rhughes@241: { ali@359: struct razor_entry *e, *subdir; jbowes@264: const char *n, *pool = set->file_string_pool.data; rhughes@241: int len; rhughes@241: richard@301: assert (set != NULL); richard@301: assert (pattern != NULL); richard@301: ali@383: if (dir == NULL) ali@383: return NULL; ali@383: ali@359: e = dir; rhughes@241: do { rhughes@241: n = pool + e->name; ali@359: if (strcmp(pattern, n) == 0) rhughes@241: return e; rhughes@241: len = strlen(n); ali@359: if (e->start != 0 && strncmp(pattern, n, len) == 0 && ali@359: pattern[len] == '/') { ali@359: subdir = (struct razor_entry *) set->files.data + ali@359: e->start; ali@359: return razor_set_find_entry(set, subdir, ali@359: pattern + len + 1); rhughes@241: } rhughes@241: } while (!((e++)->flags & RAZOR_ENTRY_LAST)); rhughes@241: rhughes@241: return NULL; rhughes@241: } rhughes@241: rhughes@241: static void rhughes@241: list_dir(struct razor_set *set, struct razor_entry *dir, rhughes@241: char *prefix, const char *pattern) rhughes@241: { ali@359: struct razor_entry *e, *subdir; jbowes@274: const char *n, *pool = set->file_string_pool.data; rhughes@241: ali@359: e = dir; rhughes@241: do { rhughes@241: n = pool + e->name; rhughes@241: if (pattern && pattern[0] && fnmatch(pattern, n, 0) != 0) rhughes@241: continue; rhughes@241: printf("%s/%s\n", prefix, n); rhughes@241: if (e->start) { rhughes@241: char *sub = prefix + strlen (prefix); rhughes@241: *sub = '/'; rhughes@241: strcpy (sub + 1, n); ali@359: subdir = (struct razor_entry *) set->files.data + ali@359: e->start; ali@359: list_dir(set, subdir, prefix, pattern); rhughes@241: *sub = '\0'; rhughes@241: } rhughes@241: } while (!((e++)->flags & RAZOR_ENTRY_LAST)); rhughes@241: } rhughes@241: krh@269: RAZOR_EXPORT void rhughes@241: razor_set_list_files(struct razor_set *set, const char *pattern) rhughes@241: { ali@359: struct razor_entry *root, *e; rhughes@241: char buffer[512], *p, *base; rhughes@241: richard@301: assert (set != NULL); richard@301: ali@359: root = (struct razor_entry *) set->files.data; ali@359: ali@359: if (pattern == NULL) { ali@359: p = set->file_string_pool.data; ali@359: e = root; ali@359: do { ali@359: if (e->start) { ali@359: strcpy(buffer, p + e->name); ali@359: list_dir(set, root + e->start, buffer, NULL); ali@359: } ali@359: } while (!((e++)->flags & RAZOR_ENTRY_LAST)); rhughes@241: return; rhughes@241: } rhughes@241: rhughes@241: strcpy(buffer, pattern); ali@359: e = razor_set_find_entry(set, root, buffer); ali@359: if (e && e->start) { rhughes@241: base = NULL; rhughes@241: } else { rhughes@241: p = strrchr(buffer, '/'); rhughes@241: if (p) { rhughes@241: *p = '\0'; rhughes@241: base = p + 1; rhughes@241: } else { rhughes@241: base = NULL; rhughes@241: } rhughes@241: } ali@359: e = razor_set_find_entry(set, root, buffer); ali@359: if (e && e->start) ali@359: list_dir(set, root + e->start, buffer, base); rhughes@241: } rhughes@241: krh@269: RAZOR_EXPORT void krh@306: razor_set_list_package_files(struct razor_set *set, krh@306: struct razor_package *package) rhughes@241: { ali@351: struct razor_file_iterator *fi; ali@351: const char *name; rhughes@241: richard@301: assert (set != NULL); krh@306: assert (package != NULL); rhughes@241: ali@377: fi = razor_file_iterator_create(set, package, 0); ali@351: ali@351: while (razor_file_iterator_next(fi, &name)) ali@351: printf("%s\n", name); ali@351: ali@351: razor_file_iterator_destroy(fi); rhughes@241: } rhughes@241: ali@387: /* ali@387: * Package data can potentially come from two places. The so-called ali@387: * metadata (eg., from comps.xml) and from an RPM file. We consider ali@387: * a package which has additional data from an RPM file as "fixed". ali@387: * If a package needs fixing, then razor_transaction_fixup_package() ali@387: * will do so. When considering what packages to add and to remove ali@387: * we need to take this into account since we always want to add ali@387: * unfixed packages (otherwise we have a potential conflict between ali@387: * the existing package data and that present in the RPM). ali@387: */ ali@387: static int ali@387: razor_package_is_fixed(struct razor_set *set, struct razor_package *p) ali@387: { ali@387: const char *preunprog, *preun, *postunprog, *postun; ali@387: ali@387: if (!p) ali@387: return 0; ali@387: razor_package_get_details(set, p, ali@387: RAZOR_DETAIL_PREUNPROG, &preunprog, ali@387: RAZOR_DETAIL_PREUN, &preun, ali@387: RAZOR_DETAIL_POSTUNPROG, &postunprog, ali@387: RAZOR_DETAIL_POSTUN, &postun, ali@387: RAZOR_DETAIL_LAST); ali@387: return *preunprog || *preun || *postunprog || *postun; ali@387: } ali@387: krh@269: RAZOR_EXPORT void rhughes@241: razor_set_diff(struct razor_set *set, struct razor_set *upstream, krh@253: razor_diff_callback_t callback, void *data) rhughes@241: { rhughes@241: struct razor_package_iterator *pi1, *pi2; rhughes@241: struct razor_package *p1, *p2; rhughes@241: const char *name1, *name2, *version1, *version2, *arch1, *arch2; ali@387: int res, is_fixed1, is_fixed2; rhughes@241: richard@301: assert (set != NULL); richard@301: assert (upstream != NULL); richard@301: rhughes@241: pi1 = razor_package_iterator_create(set); rhughes@241: pi2 = razor_package_iterator_create(upstream); rhughes@241: richard@302: razor_package_iterator_next(pi1, &p1, richard@302: RAZOR_DETAIL_NAME, &name1, richard@302: RAZOR_DETAIL_VERSION, &version1, richard@302: RAZOR_DETAIL_ARCH, &arch1, richard@307: RAZOR_DETAIL_LAST); ali@387: is_fixed1 = razor_package_is_fixed(set, p1); richard@302: razor_package_iterator_next(pi2, &p2, richard@302: RAZOR_DETAIL_NAME, &name2, richard@302: RAZOR_DETAIL_VERSION, &version2, richard@302: RAZOR_DETAIL_ARCH, &arch2, richard@307: RAZOR_DETAIL_LAST); ali@387: is_fixed2 = razor_package_is_fixed(upstream, p2); rhughes@241: rhughes@241: while (p1 || p2) { rhughes@241: if (p1 && p2) { rhughes@241: res = strcmp(name1, name2); rhughes@241: if (res == 0) krh@248: res = razor_versioncmp(version1, version2); ali@387: if (res == 0) ali@387: res = is_fixed1 - is_fixed2; rhughes@241: } else { rhughes@241: res = 0; rhughes@241: } rhughes@241: rhughes@241: if (p2 == NULL || res < 0) krh@253: callback(RAZOR_DIFF_ACTION_REMOVE, krh@253: p1, name1, version1, arch1, data); rhughes@241: else if (p1 == NULL || res > 0) krh@253: callback(RAZOR_DIFF_ACTION_ADD, krh@253: p2, name2, version2, arch2, data); rhughes@241: ali@387: if (p1 != NULL && res <= 0) { rhughes@241: razor_package_iterator_next(pi1, &p1, richard@302: RAZOR_DETAIL_NAME, &name1, richard@302: RAZOR_DETAIL_VERSION, &version1, richard@302: RAZOR_DETAIL_ARCH, &arch1, richard@307: RAZOR_DETAIL_LAST); ali@387: is_fixed1 = razor_package_is_fixed(set, p1); ali@387: } ali@387: if (p2 != NULL && res >= 0) { rhughes@241: razor_package_iterator_next(pi2, &p2, richard@302: RAZOR_DETAIL_NAME, &name2, richard@302: RAZOR_DETAIL_VERSION, &version2, richard@302: RAZOR_DETAIL_ARCH, &arch2, richard@307: RAZOR_DETAIL_LAST); ali@387: is_fixed2 = razor_package_is_fixed(upstream, p2); ali@387: } rhughes@241: } rhughes@241: rhughes@241: razor_package_iterator_destroy(pi1); rhughes@241: razor_package_iterator_destroy(pi2); rhughes@241: } krh@254: krh@316: struct install_action { krh@316: enum razor_install_action action; krh@316: struct razor_package *package; krh@316: }; krh@316: krh@316: struct razor_install_iterator { krh@316: struct razor_set *set; krh@316: struct razor_set *next; krh@316: struct array actions; ali@403: struct deque *order, *left; krh@316: }; krh@316: krh@254: static void krh@316: add_action(enum razor_diff_action action, krh@316: struct razor_package *package, krh@316: const char *name, krh@316: const char *version, krh@316: const char *arch, krh@316: void *data) krh@254: { krh@316: struct razor_install_iterator *ii = data; krh@316: struct install_action *a; krh@316: krh@316: a = array_add(&ii->actions, sizeof *a); krh@316: a->package = package; krh@316: krh@316: switch (action) { krh@316: case RAZOR_DIFF_ACTION_ADD: krh@316: a->action = RAZOR_INSTALL_ACTION_ADD; krh@316: break; krh@316: case RAZOR_DIFF_ACTION_REMOVE: krh@316: a->action = RAZOR_INSTALL_ACTION_REMOVE; krh@316: break; krh@316: } krh@254: } krh@254: ali@418: /* ali@418: * Does have a requirement for