librazor/root.c
author J. Ali Harlow <ali@juiblex.co.uk>
Wed Apr 29 17:00:01 2009 +0100 (2009-04-29)
changeset 361 2523d03a840e
parent 345 edd9b0fa63ca
child 373 fda83d91e600
permissions -rw-r--r--
Add support for preloading lua modules. This is useful both when
providing lua bindings to applications based on librazor and when
producing static binaries using librazor (where otherwise the lua
POSIX library would need to be included as an additional dynamic
object).
     1 /*
     2  * Copyright (C) 2008  Kristian Høgsberg <krh@redhat.com>
     3  * Copyright (C) 2008  Red Hat, Inc
     4  * Copyright (C) 2009  J. Ali Harlow <ali@juiblex.co.uk>
     5  *
     6  * This program is free software; you can redistribute it and/or modify
     7  * it under the terms of the GNU General Public License as published by
     8  * the Free Software Foundation; either version 2 of the License, or
     9  * (at your option) any later version.
    10  *
    11  * This program is distributed in the hope that it will be useful,
    12  * but WITHOUT ANY WARRANTY; without even the implied warranty of
    13  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
    14  * GNU General Public License for more details.
    15  *
    16  * You should have received a copy of the GNU General Public License along
    17  * with this program; if not, write to the Free Software Foundation, Inc.,
    18  * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
    19  */
    20 
    21 #include "config.h"
    22 
    23 #include <stdlib.h>
    24 #include <stdint.h>
    25 #include <stdio.h>
    26 #include <string.h>
    27 #include <sys/stat.h>
    28 #include <dirent.h>
    29 #include <unistd.h>
    30 #include <fcntl.h>
    31 #include <limits.h>
    32 #include <assert.h>
    33 #ifdef MSWIN_API
    34 #include <shlobj.h>
    35 #endif
    36 
    37 #include "razor.h"
    38 #include "razor-internal.h"
    39 
    40 #ifndef O_BINARY
    41 #define O_BINARY	0
    42 #endif
    43 
    44 static const char system_repo_filename[] = "system.rzdb";
    45 static const char system_repo_details_filename[] = "system-details.rzdb";
    46 static const char system_repo_files_filename[] = "system-files.rzdb";
    47 
    48 static const char next_repo_filename[] = "system-next.rzdb";
    49 #ifdef MSWIN_API
    50 #define RAZOR_ROOT_PATH	NULL
    51 #else
    52 #define RAZOR_ROOT_PATH	"/var/lib/razor"
    53 #endif
    54 static const char *razor_root_path = RAZOR_ROOT_PATH;
    55 
    56 struct razor_root {
    57 	struct razor_set *system;
    58 	struct razor_set *next;
    59 	int fd;
    60 	char root[PATH_MAX];
    61 	char path[PATH_MAX];
    62 	char new_path[PATH_MAX];
    63 };
    64 
    65 static void
    66 razor_root_init(void)
    67 {
    68 #ifdef MSWIN_API
    69 	static char root_path[MAX_PATH];
    70 	if (!razor_root_path) {
    71 		SHGetFolderPath(NULL,
    72 			CSIDL_COMMON_APPDATA | CSIDL_FLAG_DONT_VERIFY, NULL, 0,
    73 			root_path);
    74 		strcat(root_path, "\\Razor");
    75 		razor_root_path = root_path;
    76 	}
    77 #endif
    78 }
    79 
    80 RAZOR_EXPORT int
    81 razor_root_create(const char *root)
    82 {
    83 	struct stat buf;
    84 	struct razor_set *set;
    85 	char path[PATH_MAX], details_path[PATH_MAX], files_path[PATH_MAX];
    86 
    87 	assert (root != NULL);
    88 
    89 	razor_root_init();
    90 	if (root[0] == '\0') {
    91 		/* root is file system root */
    92 	} else if (stat(root, &buf) < 0) {
    93 		if (mkdir(root, 0777) < 0) {
    94 			fprintf(stderr,
    95 				"could not create install root \"%s\"\n",
    96 				root);
    97 			return -1;
    98 		}
    99 		fprintf(stderr, "created install root \"%s\"\n", root);
   100 	} else if (!S_ISDIR(buf.st_mode)) {
   101 		fprintf(stderr,
   102 			"install root \"%s\" exists, but is not a directory\n",
   103 			root);
   104 		return -1;
   105 	}
   106 
   107 	snprintf(path, sizeof path, "%s/%s",
   108 		 razor_root_path, system_repo_filename);
   109 	if (razor_create_dir(root, path) < 0) {
   110 		fprintf(stderr, "could not create %s%s\n",
   111 			root, razor_root_path);
   112 		return -1;
   113 	}
   114 
   115 	set = razor_set_create();
   116 	snprintf(path, sizeof path, "%s%s/%s",
   117 		 root, razor_root_path, system_repo_filename);
   118 	snprintf(details_path, sizeof details_path, "%s%s/%s",
   119 		 root, razor_root_path, system_repo_details_filename);
   120 	snprintf(files_path, sizeof files_path, "%s%s/%s",
   121 		 root, razor_root_path, system_repo_files_filename);
   122 	if (stat(path, &buf) == 0) {
   123 		fprintf(stderr,
   124 			"a razor install root is already initialized\n");
   125 		return -1;
   126 	}
   127 	if (razor_set_write(set, path, RAZOR_REPO_FILE_MAIN) < 0 ||
   128 	    razor_set_write(set, details_path, RAZOR_REPO_FILE_DETAILS) < 0 ||
   129 	    razor_set_write(set, files_path, RAZOR_REPO_FILE_FILES) < 0 ) {
   130 		fprintf(stderr, "could not write initial package set\n");
   131 		return -1;
   132 	}
   133 	razor_set_destroy(set);
   134 
   135 	return 0;
   136 }
   137 
   138 RAZOR_EXPORT struct razor_root *
   139 razor_root_open(const char *root)
   140 {
   141 	struct razor_root *image;
   142 	char details_path[PATH_MAX], files_path[PATH_MAX];
   143 
   144 	assert (root != NULL);
   145 
   146 	razor_root_init();
   147 	image = malloc(sizeof *image);
   148 	if (image == NULL)
   149 		return NULL;
   150 
   151 	/* Create the new next repo file up front to ensure exclusive
   152 	 * access. */
   153 	snprintf(image->new_path, sizeof image->new_path,
   154 		 "%s%s/%s", root, razor_root_path, next_repo_filename);
   155 	image->fd = open(image->new_path,
   156 			 O_CREAT | O_WRONLY | O_TRUNC | O_EXCL | O_BINARY,
   157 			 0666);
   158 	if (image->fd < 0) {
   159 		fprintf(stderr, "failed to get lock file, "
   160 			"maybe previous operation crashed?\n");
   161 
   162 		/* FIXME: Use fcntl advisory locking on the system
   163 		 * package set file to figure out whether previous
   164 		 * operation crashed or is still in progress. */
   165 
   166 		free(image);
   167 		return NULL;
   168 	}
   169 
   170 	snprintf(image->path, sizeof image->path,
   171 		 "%s%s/%s", root, razor_root_path, system_repo_filename);
   172 	snprintf(details_path, sizeof details_path,
   173 		 "%s%s/%s", root, razor_root_path, system_repo_details_filename);
   174 	snprintf(files_path, sizeof files_path,
   175 		 "%s%s/%s", root, razor_root_path, system_repo_files_filename);
   176 
   177 	/* FIXME: We store the root path to make the hack in
   178 	 * razor_root_update() work.  Need to get rid of this. */
   179 	strcpy(image->root, root);
   180 
   181 	image->system = razor_set_open(image->path);
   182 	if (image->system == NULL ||
   183 	    razor_set_open_details(image->system, details_path) ||
   184 	    razor_set_open_files(image->system, files_path)) {
   185 		unlink(image->new_path);
   186 		close(image->fd);
   187 		free(image);
   188 		return NULL;
   189 	}
   190 
   191 	return image;
   192 }
   193 
   194 RAZOR_EXPORT struct razor_set *
   195 razor_root_open_read_only(const char *root)
   196 {
   197 	char path[PATH_MAX], details_path[PATH_MAX], files_path[PATH_MAX];
   198 	struct razor_set *set;
   199 
   200 	assert (root != NULL);
   201 
   202 	razor_root_init();
   203 	snprintf(path, sizeof path, "%s%s/%s",
   204 		 root, razor_root_path, system_repo_filename);
   205 	snprintf(details_path, sizeof details_path,
   206 		 "%s%s/%s", root, razor_root_path, system_repo_details_filename);
   207 	snprintf(files_path, sizeof files_path,
   208 		 "%s%s/%s", root, razor_root_path, system_repo_files_filename);
   209 
   210 
   211 	set = razor_set_open(path);
   212 	if (set == NULL)
   213 		return NULL;
   214 
   215 	if (razor_set_open_details(set, details_path) ||
   216 	    razor_set_open_files(set, files_path)) {
   217 		razor_set_destroy(set);
   218 		return NULL;
   219 	}
   220 
   221 	return set;
   222 }
   223 
   224 RAZOR_EXPORT struct razor_set *
   225 razor_root_get_system_set(struct razor_root *root)
   226 {
   227 	assert (root != NULL);
   228 
   229 	return root->system;
   230 }
   231 
   232 RAZOR_EXPORT int
   233 razor_root_close(struct razor_root *root)
   234 {
   235 	assert (root != NULL);
   236 
   237 	razor_set_destroy(root->system);
   238 	close(root->fd);
   239 	unlink(root->new_path);
   240 	free(root);
   241 
   242 	return 0;
   243 }
   244 
   245 RAZOR_EXPORT void
   246 razor_root_update(struct razor_root *root, struct razor_set *next)
   247 {
   248 	char path[PATH_MAX];
   249 
   250 	assert (root != NULL);
   251 	assert (next != NULL);
   252 
   253 	razor_root_init();
   254 	razor_set_write_to_fd(next, root->fd, RAZOR_REPO_FILE_MAIN);
   255 	root->next = next;
   256 
   257 	/* FIXME: This is a pretty bad hack that just overwrites the
   258 	 * system details and files rzdb files before the transaction
   259 	 * succeeds.  We need to fix this by merging the separate
   260 	 * details and files rzdb files back into the main rzdb
   261 	 * file. */
   262 	snprintf(path, sizeof path,
   263 		 "%s%s/%s", root->root, razor_root_path, system_repo_details_filename);
   264 	razor_set_write(next, path, RAZOR_REPO_FILE_DETAILS);
   265 	snprintf(path, sizeof path,
   266 		 "%s%s/%s", root->root, razor_root_path, system_repo_files_filename);
   267 	razor_set_write(next, path, RAZOR_REPO_FILE_FILES);
   268 
   269 	/* Sync the new repo file so the new package set is on disk
   270 	 * before we start upgrading. */
   271 	fsync(root->fd);
   272 	printf("wrote %s\n", root->new_path);
   273 }
   274 
   275 RAZOR_EXPORT int
   276 razor_root_commit(struct razor_root *root)
   277 {
   278 	int retval;
   279 	assert (root != NULL);
   280 
   281 	/* Make it so. */
   282 	close(root->fd);
   283 #ifdef MSWIN_API
   284 	/* Rename is not atomic under MS-Windows */
   285 	remove(root->path);
   286 #endif
   287 	retval = rename(root->new_path, root->path);
   288 	if (retval)
   289 		perror(root->path);
   290 	else
   291 		printf("renamed %s to %s\n", root->new_path, root->path);
   292 	razor_set_destroy(root->system);
   293 	free(root);
   294 
   295 	return retval;
   296 }