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