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