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