richard@300: /* richard@300: * Copyright (C) 2008 Kristian Høgsberg richard@300: * Copyright (C) 2008 Red Hat, Inc ali@499: * Copyright (C) 2009, 2011, 2012, 2014, 2016, 2018 J. Ali Harlow richard@300: * richard@300: * This program is free software; you can redistribute it and/or modify richard@300: * it under the terms of the GNU General Public License as published by richard@300: * the Free Software Foundation; either version 2 of the License, or richard@300: * (at your option) any later version. richard@300: * richard@300: * This program is distributed in the hope that it will be useful, richard@300: * but WITHOUT ANY WARRANTY; without even the implied warranty of richard@300: * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the richard@300: * GNU General Public License for more details. richard@300: * richard@300: * You should have received a copy of the GNU General Public License along richard@300: * with this program; if not, write to the Free Software Foundation, Inc., richard@300: * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. richard@300: */ richard@300: ali@340: #include "config.h" ali@340: krh@248: #include krh@248: #include krh@248: #include krh@317: #include ali@447: #include krh@248: #include krh@248: #include krh@248: #include ali@325: #include richard@301: #include ali@340: #ifdef MSWIN_API ali@340: #include ali@340: #endif richard@301: krh@248: #include "razor.h" krh@248: #include "razor-internal.h" krh@248: ali@345: #ifndef O_BINARY ali@345: #define O_BINARY 0 ali@345: #endif ali@345: ali@445: #ifndef FALSE ali@445: #define FALSE 0 ali@445: #endif ali@445: ali@445: #ifndef TRUE ali@445: #define TRUE (!FALSE) ali@445: #endif ali@445: richard@310: static const char system_repo_filename[] = "system.rzdb"; ali@388: /* ali@388: * system_lock_filename is chosen to be the same as the pre v0.3 ali@388: * next_repo_filename. This means that once a system has been ali@388: * updated by a v0.3+ copy of razor all pre v0.3 versions of razor ali@388: * will see the system as permenantly locked. ali@388: */ ali@388: static const char system_lock_filename[] = "system-next.rzdb"; ali@340: #ifdef MSWIN_API ali@475: #define RAZOR_DATABASE_URI NULL ali@340: #else ali@475: /* ali@475: * The non-MSWIN default is a relative-ref and thus affected by the root ali@475: */ ali@475: #define RAZOR_DATABASE_URI "var/lib/razor" ali@340: #endif ali@475: static char *razor_database_uri = RAZOR_DATABASE_URI; ali@475: static int razor_database_uri_alloced = FALSE; ali@499: static int razor_database_uri_default = TRUE; krh@248: krh@248: struct razor_root { krh@248: struct razor_set *system; ali@475: char *uri; krh@248: }; krh@248: ali@340: static void ali@340: razor_root_init(void) ali@340: { ali@340: #ifdef MSWIN_API ali@475: /* ali@475: * The MSWIN default is an absolute-URI and thus unaffected by the root ali@475: */ ali@475: char database_path[MAX_PATH]; ali@475: if (!razor_database_uri) { ali@340: SHGetFolderPath(NULL, ali@340: CSIDL_COMMON_APPDATA | CSIDL_FLAG_DONT_VERIFY, NULL, 0, ali@445: database_path); ali@445: strcat(database_path, "\\Razor"); ali@475: razor_database_uri = razor_path_to_uri(database_path); ali@475: razor_database_uri_alloced = TRUE; ali@340: } ali@340: #endif ali@340: } ali@340: ali@475: RAZOR_EXPORT const char *razor_get_database_uri(void) ali@445: { ali@445: razor_root_init(); ali@475: return razor_database_uri; ali@445: } ali@445: ali@445: RAZOR_EXPORT void ali@475: razor_set_database_uri(const char *database_uri) ali@445: { ali@475: if (razor_database_uri_alloced) ali@475: free(razor_database_uri); ali@445: ali@475: if (database_uri) { ali@475: razor_database_uri = strdup(database_uri); ali@475: razor_database_uri_alloced = TRUE; ali@499: razor_database_uri_default = FALSE; ali@445: } else { ali@475: razor_database_uri = RAZOR_DATABASE_URI; ali@475: razor_database_uri_alloced = FALSE; ali@499: razor_database_uri_default = TRUE; ali@445: } ali@445: } ali@445: ali@475: char *razor_resolve_database_file(const char *root_uri, const char *filename, ali@475: struct razor_error **error) ali@475: { ali@475: char *s, *uri; ali@475: ali@475: razor_root_init(); ali@475: ali@475: s = razor_concat(razor_database_uri, "/", filename, NULL); ali@475: ali@475: uri = razor_resolve_uri_root(root_uri, s, -1, error); ali@475: ali@475: free(s); ali@475: ali@475: return uri; ali@475: } ali@475: krh@269: RAZOR_EXPORT int ali@475: razor_root_create(const char *root_uri, struct razor_error **error) krh@248: { ali@475: int retval, is_within_root, is_directory; krh@248: struct razor_set *set; ali@403: struct razor_atomic *atomic; ali@475: struct razor_error *tmp_err = NULL; ali@475: char *uri; krh@248: ali@475: uri = razor_resolve_database_file(root_uri, system_repo_filename, ali@475: error); richard@301: ali@475: if (!uri) ali@475: return -1; ali@475: ali@475: if (razor_uri_is_directory(uri, NULL) >= 0) { ali@475: razor_set_error(error, RAZOR_GENERAL_ERROR, ali@475: RAZOR_GENERAL_ERROR_DATABASE_EXISTS, NULL, ali@475: "A razor install root is already initialized"); ali@475: free(uri); ali@475: return -1; ali@475: } ali@475: ali@475: is_within_root = root_uri && strchr(root_uri, '/') && ali@475: str_has_prefix(uri, root_uri); ali@475: ali@475: atomic = razor_atomic_open("Create initial package set"); ali@475: ali@475: if (is_within_root) { ali@475: is_directory = razor_uri_is_directory(root_uri, NULL); ali@475: ali@475: if (!is_directory) { ali@475: razor_set_error(error, RAZOR_POSIX_ERROR, ENOTDIR, ali@475: root_uri, "Not a directory"); ali@475: return -1; ali@475: } else if (is_directory < 0 && ali@475: razor_uri_mkdir(root_uri, 0777, &tmp_err) < 0) { ali@475: razor_set_error(error, ali@475: razor_error_get_domain(tmp_err), ali@475: razor_error_get_code(tmp_err), ali@475: root_uri, ali@425: "Could not create install root"); krh@248: return -1; krh@248: } krh@248: ali@475: razor_atomic_make_dirs(atomic, root_uri, ali@475: uri + strlen(root_uri)); ali@475: } else ali@475: razor_atomic_make_dirs(atomic, "", uri); krh@248: krh@248: set = razor_set_create(); ali@475: razor_set_write(set, atomic, uri, RAZOR_SECTION_ALL); ali@475: free(uri); ali@403: retval = razor_atomic_commit(atomic); ali@403: if (retval) ali@439: razor_propagate_error(error, ali@439: razor_atomic_get_error(atomic), ali@439: "Could not write initial package set"); ali@403: razor_set_unref(set); ali@403: razor_atomic_destroy(atomic); krh@248: ali@403: return retval; krh@248: } krh@248: krh@269: RAZOR_EXPORT struct razor_root * ali@475: razor_root_open(const char *root_uri, struct razor_error **error) krh@248: { krh@248: struct razor_root *image; ali@475: char *lock_uri; ali@403: int r; krh@248: ali@475: lock_uri = razor_resolve_database_file(root_uri, system_lock_filename, ali@475: error); richard@301: ali@475: if (!lock_uri) ali@475: return NULL; ali@475: krh@248: image = malloc(sizeof *image); ali@403: if (image == NULL) { ali@475: free(lock_uri); ali@447: razor_set_error(error, RAZOR_POSIX_ERROR, ENOMEM, NULL, ali@447: "Not enough memory"); krh@248: return NULL; ali@403: } ali@403: ali@388: image->system = razor_set_create_without_root(); ali@388: if (image->system == NULL) { ali@388: free(image); ali@475: free(lock_uri); ali@447: razor_set_error(error, RAZOR_POSIX_ERROR, ENOMEM, NULL, ali@447: "Not enough memory"); ali@388: return NULL; ali@388: } ali@388: ali@499: r = razor_set_acquire_lock(image->system, lock_uri, 1, error); ali@388: ali@475: free(lock_uri); ali@403: ali@403: if (r < 0) { ali@499: if (error && razor_database_uri_default) ali@499: razor_error_set_object(*error, root_uri); ali@403: razor_set_unref(image->system); krh@248: free(image); krh@248: return NULL; krh@248: } krh@248: ali@475: image->uri = razor_resolve_database_file(root_uri, system_repo_filename, ali@475: error); krh@317: ali@475: if (!image->uri) { ali@475: razor_set_unref(image->system); ali@475: free(image); ali@475: return NULL; ali@475: } ali@475: ali@475: if (razor_set_bind_sections(image->system, image->uri, ali@424: RAZOR_SET_PRIVATE, error)) { ali@475: free(image->uri); ali@403: razor_set_unref(image->system); krh@248: free(image); krh@248: return NULL; krh@248: } krh@248: krh@248: return image; krh@248: } krh@248: krh@269: RAZOR_EXPORT struct razor_set * ali@475: razor_root_open_read_only(const char *root_uri, struct razor_error **error) krh@248: { ali@475: int r; ali@475: char *uri; ali@388: struct razor_set *set; krh@248: ali@475: uri = razor_resolve_database_file(root_uri, system_lock_filename, ali@475: error); richard@301: ali@475: if (!uri) ali@475: return NULL; ali@475: ali@388: set = razor_set_create_without_root(); ali@403: if (set == NULL) { ali@475: free(uri); ali@447: razor_set_error(error, RAZOR_POSIX_ERROR, ENOMEM, NULL, ali@447: "Not enough memory"); ali@388: return NULL; ali@388: } ali@388: ali@499: r = razor_set_acquire_lock(set, uri, 0, error); ali@441: ali@475: free(uri); ali@475: ali@475: if (r < 0) { ali@499: if (error && razor_database_uri_default) ali@499: razor_error_set_object(*error, root_uri); ali@403: razor_set_unref(set); ali@388: return NULL; ali@388: } ali@388: ali@475: uri = razor_resolve_database_file(root_uri, system_repo_filename, ali@475: error); ali@441: ali@475: if (!uri || razor_set_bind_sections(set, uri, 0, error)) { ali@403: razor_set_unref(set); ali@403: set = NULL; ali@403: } ali@403: ali@475: free(uri); ali@403: ali@388: return set; krh@248: } krh@248: krh@269: RAZOR_EXPORT struct razor_set * krh@250: razor_root_get_system_set(struct razor_root *root) krh@248: { richard@301: assert (root != NULL); richard@301: krh@250: return root->system; krh@248: } krh@248: krh@269: RAZOR_EXPORT int krh@250: razor_root_close(struct razor_root *root) krh@248: { richard@301: assert (root != NULL); richard@301: ali@403: razor_set_unref(root->system); ali@475: free(root->uri); krh@250: free(root); krh@248: krh@248: return 0; krh@248: } krh@248: ali@424: RAZOR_EXPORT int ali@424: razor_root_update(struct razor_root *root, struct razor_set *next, ali@424: struct razor_atomic *atomic) krh@248: { ali@424: int handle, retval; ali@424: richard@301: assert (root != NULL); richard@301: assert (next != NULL); richard@301: ali@475: handle = razor_atomic_create_file(atomic, root->uri, ali@424: S_IRWXU | S_IRWXG | S_IRWXO); ali@424: if (handle < 0) ali@424: return handle; krh@248: ali@424: razor_set_write_to_handle(next, atomic, handle, RAZOR_SECTION_ALL); krh@248: ali@424: retval = razor_atomic_close(atomic, handle); richard@301: ali@424: if (!retval) { ali@424: razor_set_unref(root->system); ali@424: root->system = razor_set_ref(next); ali@424: } krh@248: ali@346: return retval; krh@248: }