librazor/root.c
author J. Ali Harlow <ali@juiblex.co.uk>
Fri Jul 08 17:52:27 2016 +0100 (2016-07-08)
changeset 486 53789690374c
parent 447 0a5e583393e1
child 499 c89e5edb8eae
permissions -rw-r--r--
Release 0.6.3.103
     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, 2016  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 <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 #ifndef FALSE
    45 #define FALSE 0
    46 #endif
    47 
    48 #ifndef TRUE
    49 #define TRUE (!FALSE)
    50 #endif
    51 
    52 static const char system_repo_filename[] = "system.rzdb";
    53 /*
    54  * system_lock_filename is chosen to be the same as the pre v0.3
    55  * next_repo_filename. This means that once a system has been
    56  * updated by a v0.3+ copy of razor all pre v0.3 versions of razor
    57  * will see the system as permenantly locked.
    58  */
    59 static const char system_lock_filename[] = "system-next.rzdb";
    60 #ifdef MSWIN_API
    61 #define RAZOR_DATABASE_URI	NULL
    62 #else
    63 /*
    64  * The non-MSWIN default is a relative-ref and thus affected by the root
    65  */
    66 #define RAZOR_DATABASE_URI	"var/lib/razor"
    67 #endif
    68 static char *razor_database_uri = RAZOR_DATABASE_URI;
    69 static int razor_database_uri_alloced = FALSE;
    70 
    71 struct razor_root {
    72 	struct razor_set *system;
    73 	char *uri;
    74 };
    75 
    76 static void
    77 razor_root_init(void)
    78 {
    79 #ifdef MSWIN_API
    80 	/*
    81 	 * The MSWIN default is an absolute-URI and thus unaffected by the root
    82 	 */
    83 	char database_path[MAX_PATH];
    84 	if (!razor_database_uri) {
    85 		SHGetFolderPath(NULL,
    86 			CSIDL_COMMON_APPDATA | CSIDL_FLAG_DONT_VERIFY, NULL, 0,
    87 			database_path);
    88 		strcat(database_path, "\\Razor");
    89 		razor_database_uri = razor_path_to_uri(database_path);
    90 		razor_database_uri_alloced = TRUE;
    91 	}
    92 #endif
    93 }
    94 
    95 RAZOR_EXPORT const char *razor_get_database_uri(void)
    96 {
    97 	razor_root_init();
    98 	return razor_database_uri;
    99 }
   100 
   101 RAZOR_EXPORT void
   102 razor_set_database_uri(const char *database_uri)
   103 {
   104 	if (razor_database_uri_alloced)
   105 		free(razor_database_uri);
   106 
   107 	if (database_uri) {
   108 		razor_database_uri = strdup(database_uri);
   109 		razor_database_uri_alloced = TRUE;
   110 	} else {
   111 		razor_database_uri = RAZOR_DATABASE_URI;
   112 		razor_database_uri_alloced = FALSE;
   113 	}
   114 }
   115 
   116 char *razor_resolve_database_file(const char *root_uri, const char *filename,
   117 				  struct razor_error **error)
   118 {
   119 	char *s, *uri;
   120 
   121 	razor_root_init();
   122 
   123 	s = razor_concat(razor_database_uri, "/", filename, NULL);
   124 
   125 	uri = razor_resolve_uri_root(root_uri, s, -1, error);
   126 
   127 	free(s);
   128 
   129 	return uri;
   130 }
   131 
   132 RAZOR_EXPORT int
   133 razor_root_create(const char *root_uri, struct razor_error **error)
   134 {
   135 	int retval, is_within_root, is_directory;
   136 	struct razor_set *set;
   137 	struct razor_atomic *atomic;
   138 	struct razor_error *tmp_err = NULL;
   139 	char *uri;
   140 
   141 	uri = razor_resolve_database_file(root_uri, system_repo_filename,
   142 					  error);
   143 
   144 	if (!uri)
   145 		return -1;
   146 
   147 	if (razor_uri_is_directory(uri, NULL) >= 0) {
   148 		razor_set_error(error, RAZOR_GENERAL_ERROR,
   149 				RAZOR_GENERAL_ERROR_DATABASE_EXISTS, NULL,
   150 				"A razor install root is already initialized");
   151 		free(uri);
   152 		return -1;
   153 	}
   154 
   155 	is_within_root = root_uri && strchr(root_uri, '/') &&
   156 			 str_has_prefix(uri, root_uri);
   157 
   158 	atomic = razor_atomic_open("Create initial package set");
   159 
   160 	if (is_within_root) {
   161 		is_directory = razor_uri_is_directory(root_uri, NULL);
   162 
   163 		if (!is_directory) {
   164 			razor_set_error(error, RAZOR_POSIX_ERROR, ENOTDIR,
   165 					root_uri, "Not a directory");
   166 			return -1;
   167 		} else if (is_directory < 0 &&
   168 			   razor_uri_mkdir(root_uri, 0777, &tmp_err) < 0) {
   169 			razor_set_error(error,
   170 					razor_error_get_domain(tmp_err),
   171 					razor_error_get_code(tmp_err),
   172 					root_uri,
   173 					"Could not create install root");
   174 			return -1;
   175 		}
   176 
   177 		razor_atomic_make_dirs(atomic, root_uri,
   178 				       uri + strlen(root_uri));
   179 	} else
   180 		razor_atomic_make_dirs(atomic, "", uri);
   181 
   182 	set = razor_set_create();
   183 	razor_set_write(set, atomic, uri, RAZOR_SECTION_ALL);
   184 	free(uri);
   185 	retval = razor_atomic_commit(atomic);
   186 	if (retval)
   187 		razor_propagate_error(error,
   188 				      razor_atomic_get_error(atomic),
   189 				      "Could not write initial package set");
   190 	razor_set_unref(set);
   191 	razor_atomic_destroy(atomic);
   192 
   193 	return retval;
   194 }
   195 
   196 RAZOR_EXPORT struct razor_root *
   197 razor_root_open(const char *root_uri, struct razor_error **error)
   198 {
   199 	struct razor_root *image;
   200 	char *lock_uri;
   201 	int r;
   202 
   203 	lock_uri = razor_resolve_database_file(root_uri, system_lock_filename,
   204 					       error);
   205 
   206 	if (!lock_uri)
   207 		return NULL;
   208 
   209 	image = malloc(sizeof *image);
   210 	if (image == NULL) {
   211 		free(lock_uri);
   212 		razor_set_error(error, RAZOR_POSIX_ERROR, ENOMEM, NULL,
   213 				"Not enough memory");
   214 		return NULL;
   215 	}
   216 
   217 	image->system = razor_set_create_without_root();
   218 	if (image->system == NULL) {
   219 		free(image);
   220 		free(lock_uri);
   221 		razor_set_error(error, RAZOR_POSIX_ERROR, ENOMEM, NULL,
   222 				"Not enough memory");
   223 		return NULL;
   224 	}
   225 
   226 	r = razor_set_acquire_lock(image->system, lock_uri, 1);
   227 
   228 	free(lock_uri);
   229 
   230 	if (r < 0) {
   231 		razor_set_error(error, RAZOR_GENERAL_ERROR,
   232 				RAZOR_GENERAL_ERROR_DATABASE_LOCKED, NULL,
   233 				"Failed to acquire exclusive system lock");
   234 		razor_set_unref(image->system);
   235 		free(image);
   236 		return NULL;
   237 	}
   238 
   239 	image->uri = razor_resolve_database_file(root_uri, system_repo_filename,
   240 						 error);
   241 
   242 	if (!image->uri) {
   243 		razor_set_unref(image->system);
   244 		free(image);
   245 		return NULL;
   246 	}
   247 
   248 	if (razor_set_bind_sections(image->system, image->uri,
   249 				    RAZOR_SET_PRIVATE, error)) {
   250 		free(image->uri);
   251 		razor_set_unref(image->system);
   252 		free(image);
   253 		return NULL;
   254 	}
   255 
   256 	return image;
   257 }
   258 
   259 RAZOR_EXPORT struct razor_set *
   260 razor_root_open_read_only(const char *root_uri, struct razor_error **error)
   261 {
   262 	int r;
   263 	char *uri;
   264 	struct razor_set *set;
   265 
   266 	uri = razor_resolve_database_file(root_uri, system_lock_filename,
   267 					  error);
   268 
   269 	if (!uri)
   270 		return NULL;
   271 
   272 	set = razor_set_create_without_root();
   273 	if (set == NULL) {
   274 		free(uri);
   275 		razor_set_error(error, RAZOR_POSIX_ERROR, ENOMEM, NULL,
   276 				"Not enough memory");
   277 		return NULL;
   278 	}
   279 
   280 	r = razor_set_acquire_lock(set, uri, 0);
   281 
   282 	free(uri);
   283 
   284 	if (r < 0) {
   285 		razor_set_error(error, RAZOR_GENERAL_ERROR,
   286 				RAZOR_GENERAL_ERROR_DATABASE_LOCKED, NULL,
   287 				"Failed to acquire non-exclusive system lock");
   288 		razor_set_unref(set);
   289 		return NULL;
   290 	}
   291 
   292 	uri = razor_resolve_database_file(root_uri, system_repo_filename,
   293 					  error);
   294 
   295 	if (!uri || razor_set_bind_sections(set, uri, 0, error)) {
   296 		razor_set_unref(set);
   297 		set = NULL;
   298 	}
   299 
   300 	free(uri);
   301 
   302 	return set;
   303 }
   304 
   305 RAZOR_EXPORT struct razor_set *
   306 razor_root_get_system_set(struct razor_root *root)
   307 {
   308 	assert (root != NULL);
   309 
   310 	return root->system;
   311 }
   312 
   313 RAZOR_EXPORT int
   314 razor_root_close(struct razor_root *root)
   315 {
   316 	assert (root != NULL);
   317 
   318 	razor_set_unref(root->system);
   319 	free(root->uri);
   320 	free(root);
   321 
   322 	return 0;
   323 }
   324 
   325 RAZOR_EXPORT int
   326 razor_root_update(struct razor_root *root, struct razor_set *next,
   327 		  struct razor_atomic *atomic)
   328 {
   329 	int handle, retval;
   330 
   331 	assert (root != NULL);
   332 	assert (next != NULL);
   333 
   334 	handle = razor_atomic_create_file(atomic, root->uri,
   335 					  S_IRWXU | S_IRWXG | S_IRWXO);
   336 	if (handle < 0)
   337 		return handle;
   338 
   339 	razor_set_write_to_handle(next, atomic, handle, RAZOR_SECTION_ALL);
   340 
   341 	retval = razor_atomic_close(atomic, handle);
   342 
   343 	if (!retval) {
   344 		razor_set_unref(root->system);
   345 		root->system = razor_set_ref(next);
   346 	}
   347 
   348 	return retval;
   349 }