richard@300: /* richard@300: * Copyright (C) 2008 Kristian Høgsberg richard@300: * Copyright (C) 2008 Red Hat, Inc ali@403: * Copyright (C) 2009, 2011 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 krh@248: #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: 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@388: static const char system_tmp_filename[] = "system.tmp"; ali@340: #ifdef MSWIN_API ali@340: #define RAZOR_ROOT_PATH NULL ali@340: #else ali@340: #define RAZOR_ROOT_PATH "/var/lib/razor" ali@340: #endif ali@340: static const char *razor_root_path = RAZOR_ROOT_PATH; krh@248: krh@248: struct razor_root { krh@248: struct razor_set *system; krh@248: struct razor_set *next; ali@403: struct razor_atomic *atomic; ali@403: int handle; ali@403: char *path, *new_path; krh@248: }; krh@248: ali@340: static void ali@340: razor_root_init(void) ali@340: { ali@340: #ifdef MSWIN_API ali@340: static char root_path[MAX_PATH]; ali@340: if (!razor_root_path) { ali@340: SHGetFolderPath(NULL, ali@340: CSIDL_COMMON_APPDATA | CSIDL_FLAG_DONT_VERIFY, NULL, 0, ali@340: root_path); ali@340: strcat(root_path, "\\Razor"); ali@340: razor_root_path = root_path; ali@340: } ali@340: #endif ali@340: } ali@340: krh@269: RAZOR_EXPORT int krh@248: razor_root_create(const char *root) krh@248: { ali@403: int retval; krh@248: struct stat buf; krh@248: struct razor_set *set; ali@403: struct razor_atomic *atomic; ali@406: char *file, *path; krh@248: richard@301: assert (root != NULL); richard@301: ali@340: razor_root_init(); krh@317: if (root[0] == '\0') { krh@317: /* root is file system root */ krh@317: } else if (stat(root, &buf) < 0) { krh@248: if (mkdir(root, 0777) < 0) { krh@248: fprintf(stderr, krh@248: "could not create install root \"%s\"\n", krh@248: root); krh@248: return -1; krh@248: } krh@248: fprintf(stderr, "created install root \"%s\"\n", root); krh@248: } else if (!S_ISDIR(buf.st_mode)) { krh@248: fprintf(stderr, krh@248: "install root \"%s\" exists, but is not a directory\n", krh@248: root); krh@248: return -1; krh@248: } krh@248: ali@406: file = razor_concat(razor_root_path, "/", system_repo_filename, NULL); ali@406: path = razor_concat(root, file, NULL); ali@403: retval = !stat(path, &buf); ali@403: if (retval) { ali@403: fprintf(stderr, ali@403: "a razor install root is already initialized\n"); ali@406: free(path); ali@406: free(file); ali@403: return retval; krh@248: } krh@248: ali@403: atomic = razor_atomic_open("Create initial package set"); ali@406: razor_atomic_make_dirs(atomic, root, file); krh@248: set = razor_set_create(); ali@403: razor_set_write(set, atomic, path, RAZOR_SECTION_ALL); ali@403: free(path); ali@406: free(file); ali@403: retval = razor_atomic_commit(atomic); ali@403: if (retval) krh@248: fprintf(stderr, "could not write initial package set\n"); 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@403: razor_root_open(const char *root, struct razor_atomic *atomic) krh@248: { krh@248: struct razor_root *image; ali@403: char *lock_path; ali@403: int r; krh@248: richard@301: assert (root != NULL); richard@301: ali@340: razor_root_init(); krh@248: image = malloc(sizeof *image); ali@403: if (image == NULL) { ali@403: razor_atomic_abort(atomic, "Not enough memory"); krh@248: return NULL; ali@403: } ali@403: ali@403: image->atomic = atomic; krh@248: ali@388: image->system = razor_set_create_without_root(); ali@388: if (image->system == NULL) { ali@388: free(image); ali@403: razor_atomic_abort(atomic, "Not enough memory"); ali@388: return NULL; ali@388: } ali@388: ali@403: lock_path = razor_concat(root, razor_root_path, "/", ali@403: system_lock_filename, NULL); ali@388: ali@403: r = razor_set_aquire_lock(image->system, lock_path, 1); ali@403: ali@403: free(lock_path); ali@403: ali@403: if (r < 0) { ali@403: razor_atomic_abort(atomic, ali@403: "Failed to aquire exclusive system lock"); ali@403: razor_set_unref(image->system); ali@388: free(image); ali@388: return NULL; ali@388: } ali@388: ali@403: image->new_path = razor_concat(root, razor_root_path, "/", ali@403: system_tmp_filename, NULL); ali@403: image->handle = razor_atomic_create_file(atomic, image->new_path, ali@403: S_IRWXU | S_IRWXG | S_IRWXO); ali@403: if (image->handle < 0) { ali@403: free(image->new_path); ali@403: razor_set_unref(image->system); krh@248: free(image); krh@248: return NULL; krh@248: } krh@248: ali@403: image->path = razor_concat(root, razor_root_path, "/", ali@403: system_repo_filename, NULL); krh@317: ali@403: if (razor_set_bind_sections(image->system, atomic, image->path)) { krh@248: unlink(image->new_path); ali@403: free(image->new_path); ali@403: free(image->path); 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@403: razor_root_open_read_only(const char *root, struct razor_atomic *atomic) krh@248: { ali@403: char *path; ali@388: struct razor_set *set; krh@248: richard@301: assert (root != NULL); richard@301: ali@340: razor_root_init(); ali@388: set = razor_set_create_without_root(); ali@403: if (set == NULL) { ali@403: razor_atomic_abort(atomic, "Not enough memory"); ali@388: return NULL; ali@388: } ali@388: ali@403: path = razor_concat(root, razor_root_path, "/", system_lock_filename, ali@403: NULL); ali@403: if (razor_set_aquire_lock(set, path, 0) < 0) { ali@403: razor_atomic_abort(atomic, "Failed to aquire non-exclusive " ali@403: "system lock"); ali@403: free(path); ali@403: razor_set_unref(set); ali@388: return NULL; ali@388: } ali@388: ali@403: free(path); ali@403: path = razor_concat(root, razor_root_path, "/", system_repo_filename, ali@403: NULL); ali@403: ali@403: if (razor_set_bind_sections(set, atomic, path)) { ali@403: razor_set_unref(set); ali@403: set = NULL; ali@403: } ali@403: ali@403: free(path); 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@403: razor_atomic_close(root->atomic, root->handle); ali@403: razor_atomic_remove(root->atomic, root->new_path); ali@403: free(root->path); ali@403: free(root->new_path); krh@250: free(root); krh@248: krh@248: return 0; krh@248: } krh@248: krh@269: RAZOR_EXPORT void krh@248: razor_root_update(struct razor_root *root, struct razor_set *next) krh@248: { richard@301: assert (root != NULL); richard@301: assert (next != NULL); richard@301: ali@340: razor_root_init(); ali@403: razor_set_write_to_handle(next, root->atomic, root->handle, ali@403: RAZOR_SECTION_ALL); krh@248: root->next = next; krh@248: krh@248: /* Sync the new repo file so the new package set is on disk krh@248: * before we start upgrading. */ ali@403: razor_atomic_sync(root->atomic, root->handle); krh@248: } krh@248: krh@269: RAZOR_EXPORT int krh@250: razor_root_commit(struct razor_root *root) krh@248: { ali@346: int retval; richard@301: assert (root != NULL); richard@301: ali@403: razor_atomic_close(root->atomic, root->handle); ali@403: retval = razor_atomic_rename_file(root->atomic, root->new_path, ali@403: root->path); ali@403: razor_set_unref(root->system); ali@403: free(root->path); ali@403: free(root->new_path); krh@250: free(root); krh@248: ali@346: return retval; krh@248: }