richard@300: /* richard@300: * Copyright (C) 2008 Kristian Høgsberg richard@300: * Copyright (C) 2008 Red Hat, Inc ali@340: * Copyright (C) 2009 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: richard@310: static const char system_repo_filename[] = "system.rzdb"; richard@310: static const char system_repo_details_filename[] = "system-details.rzdb"; richard@310: static const char system_repo_files_filename[] = "system-files.rzdb"; jbowes@273: richard@310: static const char next_repo_filename[] = "system-next.rzdb"; 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; krh@248: int fd; krh@317: char root[PATH_MAX]; krh@248: char path[PATH_MAX]; krh@248: char new_path[PATH_MAX]; 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: { krh@248: struct stat buf; krh@248: struct razor_set *set; jbowes@273: char path[PATH_MAX], details_path[PATH_MAX], files_path[PATH_MAX]; 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: krh@248: snprintf(path, sizeof path, "%s/%s", krh@248: razor_root_path, system_repo_filename); krh@248: if (razor_create_dir(root, path) < 0) { krh@248: fprintf(stderr, "could not create %s%s\n", krh@248: root, razor_root_path); krh@248: return -1; krh@248: } krh@248: krh@248: set = razor_set_create(); krh@248: snprintf(path, sizeof path, "%s%s/%s", krh@248: root, razor_root_path, system_repo_filename); jbowes@273: snprintf(details_path, sizeof details_path, "%s%s/%s", jbowes@273: root, razor_root_path, system_repo_details_filename); jbowes@273: snprintf(files_path, sizeof files_path, "%s%s/%s", jbowes@273: root, razor_root_path, system_repo_files_filename); krh@248: if (stat(path, &buf) == 0) { krh@248: fprintf(stderr, krh@248: "a razor install root is already initialized\n"); krh@248: return -1; krh@248: } jbowes@273: if (razor_set_write(set, path, RAZOR_REPO_FILE_MAIN) < 0 || jbowes@273: razor_set_write(set, details_path, RAZOR_REPO_FILE_DETAILS) < 0 || jbowes@273: razor_set_write(set, files_path, RAZOR_REPO_FILE_FILES) < 0 ) { krh@248: fprintf(stderr, "could not write initial package set\n"); krh@248: return -1; krh@248: } krh@248: razor_set_destroy(set); krh@248: krh@248: return 0; krh@248: } krh@248: krh@269: RAZOR_EXPORT struct razor_root * krh@250: razor_root_open(const char *root) krh@248: { krh@248: struct razor_root *image; krh@315: char details_path[PATH_MAX], files_path[PATH_MAX]; krh@248: richard@301: assert (root != NULL); richard@301: ali@340: razor_root_init(); krh@248: image = malloc(sizeof *image); krh@248: if (image == NULL) krh@248: return NULL; krh@248: krh@248: /* Create the new next repo file up front to ensure exclusive krh@248: * access. */ krh@248: snprintf(image->new_path, sizeof image->new_path, krh@248: "%s%s/%s", root, razor_root_path, next_repo_filename); krh@248: image->fd = open(image->new_path, krh@248: O_CREAT | O_WRONLY | O_TRUNC | O_EXCL, 0666); krh@248: if (image->fd < 0) { krh@248: fprintf(stderr, "failed to get lock file, " krh@248: "maybe previous operation crashed?\n"); krh@248: krh@248: /* FIXME: Use fcntl advisory locking on the system krh@248: * package set file to figure out whether previous krh@248: * operation crashed or is still in progress. */ krh@248: krh@248: free(image); krh@248: return NULL; krh@248: } krh@248: krh@248: snprintf(image->path, sizeof image->path, krh@248: "%s%s/%s", root, razor_root_path, system_repo_filename); krh@315: snprintf(details_path, sizeof details_path, krh@315: "%s%s/%s", root, razor_root_path, system_repo_details_filename); krh@315: snprintf(files_path, sizeof files_path, krh@315: "%s%s/%s", root, razor_root_path, system_repo_files_filename); krh@315: krh@317: /* FIXME: We store the root path to make the hack in krh@317: * razor_root_update() work. Need to get rid of this. */ krh@317: strcpy(image->root, root); krh@317: krh@248: image->system = razor_set_open(image->path); krh@315: if (image->system == NULL || krh@315: razor_set_open_details(image->system, details_path) || krh@315: razor_set_open_files(image->system, files_path)) { krh@248: unlink(image->new_path); krh@248: close(image->fd); 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 * krh@248: razor_root_open_read_only(const char *root) krh@248: { krh@317: char path[PATH_MAX], details_path[PATH_MAX], files_path[PATH_MAX]; krh@317: struct razor_set *set; krh@248: richard@301: assert (root != NULL); richard@301: ali@340: razor_root_init(); krh@248: snprintf(path, sizeof path, "%s%s/%s", krh@248: root, razor_root_path, system_repo_filename); krh@317: snprintf(details_path, sizeof details_path, krh@317: "%s%s/%s", root, razor_root_path, system_repo_details_filename); krh@317: snprintf(files_path, sizeof files_path, krh@317: "%s%s/%s", root, razor_root_path, system_repo_files_filename); krh@248: krh@317: krh@317: set = razor_set_open(path); krh@317: if (set == NULL) krh@317: return NULL; krh@317: krh@317: if (razor_set_open_details(set, details_path) || krh@317: razor_set_open_files(set, files_path)) { krh@317: razor_set_destroy(set); krh@317: return NULL; krh@317: } krh@317: krh@317: 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: krh@250: razor_set_destroy(root->system); ali@341: close(root->fd); krh@250: unlink(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: { krh@317: char path[PATH_MAX]; krh@317: richard@301: assert (root != NULL); richard@301: assert (next != NULL); richard@301: ali@340: razor_root_init(); jbowes@258: razor_set_write_to_fd(next, root->fd, RAZOR_REPO_FILE_MAIN); krh@248: root->next = next; krh@248: krh@317: /* FIXME: This is a pretty bad hack that just overwrites the krh@317: * system details and files rzdb files before the transaction krh@317: * succeeds. We need to fix this by merging the separate krh@317: * details and files rzdb files back into the main rzdb krh@317: * file. */ krh@317: snprintf(path, sizeof path, krh@317: "%s%s/%s", root->root, razor_root_path, system_repo_details_filename); krh@317: razor_set_write(next, path, RAZOR_REPO_FILE_DETAILS); krh@317: snprintf(path, sizeof path, krh@317: "%s%s/%s", root->root, razor_root_path, system_repo_files_filename); krh@317: razor_set_write(next, path, RAZOR_REPO_FILE_FILES); krh@317: krh@248: /* Sync the new repo file so the new package set is on disk krh@248: * before we start upgrading. */ krh@248: fsync(root->fd); krh@248: printf("wrote %s\n", root->new_path); krh@248: } krh@248: krh@269: RAZOR_EXPORT int krh@250: razor_root_commit(struct razor_root *root) krh@248: { richard@301: assert (root != NULL); richard@301: krh@248: /* Make it so. */ krh@250: rename(root->new_path, root->path); krh@250: printf("renamed %s to %s\n", root->new_path, root->path); krh@250: razor_set_destroy(root->system); krh@250: close(root->fd); krh@250: free(root); krh@248: krh@248: return 0; krh@248: }