librazor/root.c
author J. Ali Harlow <ali@juiblex.co.uk>
Fri Oct 03 12:26:22 2014 +0100 (2014-10-03)
changeset 452 06885e558546
parent 445 aada48958b92
child 475 008c75a5e08d
permissions -rw-r--r--
Add RAZOR_HAVE_ATOMIC_ROLLBACK
     1 /*
     2  * Copyright (C) 2008  Kristian Høgsberg <krh@redhat.com>
     3  * Copyright (C) 2008  Red Hat, Inc
     4  * Copyright (C) 2009, 2011, 2012, 2014  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 <errno.h>
    28 #include <sys/stat.h>
    29 #include <dirent.h>
    30 #include <unistd.h>
    31 #include <fcntl.h>
    32 #include <limits.h>
    33 #include <assert.h>
    34 #ifdef MSWIN_API
    35 #include <shlobj.h>
    36 #endif
    37 
    38 #include "razor.h"
    39 #include "razor-internal.h"
    40 
    41 #ifndef O_BINARY
    42 #define O_BINARY	0
    43 #endif
    44 
    45 #ifndef FALSE
    46 #define FALSE 0
    47 #endif
    48 
    49 #ifndef TRUE
    50 #define TRUE (!FALSE)
    51 #endif
    52 
    53 static const char system_repo_filename[] = "system.rzdb";
    54 /*
    55  * system_lock_filename is chosen to be the same as the pre v0.3
    56  * next_repo_filename. This means that once a system has been
    57  * updated by a v0.3+ copy of razor all pre v0.3 versions of razor
    58  * will see the system as permenantly locked.
    59  */
    60 static const char system_lock_filename[] = "system-next.rzdb";
    61 #ifdef MSWIN_API
    62 #define RAZOR_DATABASE_PATH	NULL
    63 #else
    64 #define RAZOR_DATABASE_PATH	"/var/lib/razor"
    65 #endif
    66 static char *razor_database_path = RAZOR_DATABASE_PATH;
    67 static int razor_database_path_alloced = FALSE;
    68 
    69 struct razor_root {
    70 	struct razor_set *system;
    71 	char *path;
    72 };
    73 
    74 static void
    75 razor_root_init(void)
    76 {
    77 #ifdef MSWIN_API
    78 	static char database_path[MAX_PATH];
    79 	if (!razor_database_path) {
    80 		SHGetFolderPath(NULL,
    81 			CSIDL_COMMON_APPDATA | CSIDL_FLAG_DONT_VERIFY, NULL, 0,
    82 			database_path);
    83 		strcat(database_path, "\\Razor");
    84 		razor_database_path = database_path;
    85 		razor_database_path_alloced = FALSE;
    86 	}
    87 #endif
    88 }
    89 
    90 RAZOR_EXPORT const char *
    91 razor_get_database_path()
    92 {
    93 	razor_root_init();
    94 
    95 	return razor_database_path;
    96 }
    97 
    98 RAZOR_EXPORT void
    99 razor_set_database_path(const char *database_path)
   100 {
   101 	if (razor_database_path_alloced)
   102 		free(razor_database_path);
   103 
   104 	if (database_path) {
   105 		razor_database_path = strdup(database_path);
   106 		razor_database_path_alloced = TRUE;
   107 	} else {
   108 		razor_database_path = RAZOR_DATABASE_PATH;
   109 		razor_database_path_alloced = FALSE;
   110 	}
   111 }
   112 
   113 RAZOR_EXPORT int
   114 razor_root_create(const char *root, struct razor_error **error)
   115 {
   116 	int retval;
   117 	struct stat buf;
   118 	struct razor_set *set;
   119 	struct razor_atomic *atomic;
   120 	char *file, *path;
   121 
   122 	assert (root != NULL);
   123 
   124 	razor_root_init();
   125 	if (root[0] == '\0') {
   126 		/* root is file system root */
   127 	} else if (stat(root, &buf) < 0) {
   128 		if (mkdir(root, 0777) < 0) {
   129 			razor_set_error(error, RAZOR_POSIX_ERROR, errno, root,
   130 					"Could not create install root");
   131 			return -1;
   132 		}
   133 	} else if (!S_ISDIR(buf.st_mode)) {
   134 		razor_set_error(error, RAZOR_POSIX_ERROR, ENOTDIR, root,
   135 				"Not a directory");
   136 		return -1;
   137 	}
   138 
   139 	file = razor_concat(razor_database_path, "/", system_repo_filename,
   140 			    NULL);
   141 	path = razor_path_add_root(file, root);
   142 	retval = !stat(path, &buf);
   143 	if (retval) {
   144 		razor_set_error(error, RAZOR_GENERAL_ERROR,
   145 				RAZOR_GENERAL_ERROR_DATABASE_EXISTS, NULL,
   146 				"A razor install root is already initialized");
   147 		free(path);
   148 		free(file);
   149 		return retval;
   150 	}
   151 
   152 	atomic = razor_atomic_open("Create initial package set");
   153 	razor_atomic_make_dirs(atomic, root, file);
   154 	set = razor_set_create();
   155 	razor_set_write(set, atomic, path, RAZOR_SECTION_ALL);
   156 	free(path);
   157 	free(file);
   158 	retval = razor_atomic_commit(atomic);
   159 	if (retval)
   160 		razor_propagate_error(error,
   161 				      razor_atomic_get_error(atomic),
   162 				      "Could not write initial package set");
   163 	razor_set_unref(set);
   164 	razor_atomic_destroy(atomic);
   165 
   166 	return retval;
   167 }
   168 
   169 RAZOR_EXPORT struct razor_root *
   170 razor_root_open(const char *root, struct razor_error **error)
   171 {
   172 	struct razor_root *image;
   173 	char *s, *lock_path;
   174 	int r;
   175 
   176 	assert (root != NULL);
   177 
   178 	razor_root_init();
   179 	image = malloc(sizeof *image);
   180 	if (image == NULL) {
   181 		razor_set_error(error, RAZOR_POSIX_ERROR, ENOMEM, NULL,
   182 				"Not enough memory");
   183 		return NULL;
   184 	}
   185 
   186 	image->system = razor_set_create_without_root();
   187 	if (image->system == NULL) {
   188 		free(image);
   189 		razor_set_error(error, RAZOR_POSIX_ERROR, ENOMEM, NULL,
   190 				"Not enough memory");
   191 		return NULL;
   192 	}
   193 
   194 	s = razor_concat(razor_database_path, "/", system_lock_filename, NULL);
   195 	lock_path = razor_path_add_root(s, root);
   196 	free(s);
   197 
   198 	r = razor_set_aquire_lock(image->system, lock_path, 1);
   199 
   200 	free(lock_path);
   201 
   202 	if (r < 0) {
   203 		razor_set_error(error, RAZOR_GENERAL_ERROR,
   204 				RAZOR_GENERAL_ERROR_DATABASE_LOCKED, NULL,
   205 				"Failed to aquire exclusive system lock");
   206 		razor_set_unref(image->system);
   207 		free(image);
   208 		return NULL;
   209 	}
   210 
   211 	s = razor_concat(razor_database_path, "/", system_repo_filename, NULL);
   212 	image->path = razor_path_add_root(s, root);
   213 	free(s);
   214 
   215 	if (razor_set_bind_sections(image->system, image->path,
   216 				    RAZOR_SET_PRIVATE, error)) {
   217 		free(image->path);
   218 		razor_set_unref(image->system);
   219 		free(image);
   220 		return NULL;
   221 	}
   222 
   223 	return image;
   224 }
   225 
   226 RAZOR_EXPORT struct razor_set *
   227 razor_root_open_read_only(const char *root, struct razor_error **error)
   228 {
   229 	char *s, *path;
   230 	struct razor_set *set;
   231 
   232 	assert (root != NULL);
   233 
   234 	razor_root_init();
   235 	set = razor_set_create_without_root();
   236 	if (set == NULL) {
   237 		razor_set_error(error, RAZOR_POSIX_ERROR, ENOMEM, NULL,
   238 				"Not enough memory");
   239 		return NULL;
   240 	}
   241 
   242 	s = razor_concat(razor_database_path, "/", system_lock_filename, NULL);
   243 	path = razor_path_add_root(s, root);
   244 	free(s);
   245 
   246 	if (razor_set_aquire_lock(set, path, 0) < 0) {
   247 		razor_set_error(error, RAZOR_GENERAL_ERROR,
   248 				RAZOR_GENERAL_ERROR_DATABASE_LOCKED, NULL,
   249 				"Failed to aquire non-exclusive system lock");
   250 		free(path);
   251 		razor_set_unref(set);
   252 		return NULL;
   253 	}
   254 
   255 	free(path);
   256 
   257 	s = razor_concat(razor_database_path, "/", system_repo_filename, NULL);
   258 	path = razor_path_add_root(s, root);
   259 	free(s);
   260 
   261 	if (razor_set_bind_sections(set, path, 0, error)) {
   262 		razor_set_unref(set);
   263 		set = NULL;
   264 	}
   265 
   266 	free(path);
   267 
   268 	return set;
   269 }
   270 
   271 RAZOR_EXPORT struct razor_set *
   272 razor_root_get_system_set(struct razor_root *root)
   273 {
   274 	assert (root != NULL);
   275 
   276 	return root->system;
   277 }
   278 
   279 RAZOR_EXPORT int
   280 razor_root_close(struct razor_root *root)
   281 {
   282 	assert (root != NULL);
   283 
   284 	razor_set_unref(root->system);
   285 	free(root->path);
   286 	free(root);
   287 
   288 	return 0;
   289 }
   290 
   291 RAZOR_EXPORT int
   292 razor_root_update(struct razor_root *root, struct razor_set *next,
   293 		  struct razor_atomic *atomic)
   294 {
   295 	int handle, retval;
   296 
   297 	assert (root != NULL);
   298 	assert (next != NULL);
   299 
   300 	handle = razor_atomic_create_file(atomic, root->path,
   301 					  S_IRWXU | S_IRWXG | S_IRWXO);
   302 	if (handle < 0)
   303 		return handle;
   304 
   305 	razor_set_write_to_handle(next, atomic, handle, RAZOR_SECTION_ALL);
   306 
   307 	retval = razor_atomic_close(atomic, handle);
   308 
   309 	if (!retval) {
   310 		razor_set_unref(root->system);
   311 		root->system = razor_set_ref(next);
   312 	}
   313 
   314 	return retval;
   315 }