librazor/root.c
author J. Ali Harlow <ali@juiblex.co.uk>
Thu Feb 09 20:45:27 2012 +0000 (2012-02-09)
changeset 418 33b825d3128d
parent 403 e63951c1d0f8
child 424 8cbc438cc298
permissions -rw-r--r--
Add transaction barriers
These allow packages to be installed and removed which have scripts
that depend on each other when atomic transactions are involved.
Note that yum supports pre, but not other requires flags. post will
need similar support to the post scripts themselves pulling in the
requires flags from the rpms. Likewise preun and postun will need
similar handling to those scrips since the requires flags will need
to be stored in the razor database.
     1 /*
     2  * Copyright (C) 2008  Kristian Høgsberg <krh@redhat.com>
     3  * Copyright (C) 2008  Red Hat, Inc
     4  * Copyright (C) 2009, 2011  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 /*
    46  * system_lock_filename is chosen to be the same as the pre v0.3
    47  * next_repo_filename. This means that once a system has been
    48  * updated by a v0.3+ copy of razor all pre v0.3 versions of razor
    49  * will see the system as permenantly locked.
    50  */
    51 static const char system_lock_filename[] = "system-next.rzdb";
    52 static const char system_tmp_filename[] = "system.tmp";
    53 #ifdef MSWIN_API
    54 #define RAZOR_ROOT_PATH	NULL
    55 #else
    56 #define RAZOR_ROOT_PATH	"/var/lib/razor"
    57 #endif
    58 static const char *razor_root_path = RAZOR_ROOT_PATH;
    59 
    60 struct razor_root {
    61 	struct razor_set *system;
    62 	struct razor_set *next;
    63 	struct razor_atomic *atomic;
    64 	int handle;
    65 	char *path, *new_path;
    66 };
    67 
    68 static void
    69 razor_root_init(void)
    70 {
    71 #ifdef MSWIN_API
    72 	static char root_path[MAX_PATH];
    73 	if (!razor_root_path) {
    74 		SHGetFolderPath(NULL,
    75 			CSIDL_COMMON_APPDATA | CSIDL_FLAG_DONT_VERIFY, NULL, 0,
    76 			root_path);
    77 		strcat(root_path, "\\Razor");
    78 		razor_root_path = root_path;
    79 	}
    80 #endif
    81 }
    82 
    83 RAZOR_EXPORT int
    84 razor_root_create(const char *root)
    85 {
    86 	int retval;
    87 	struct stat buf;
    88 	struct razor_set *set;
    89 	struct razor_atomic *atomic;
    90 	char *file, *path;
    91 
    92 	assert (root != NULL);
    93 
    94 	razor_root_init();
    95 	if (root[0] == '\0') {
    96 		/* root is file system root */
    97 	} else if (stat(root, &buf) < 0) {
    98 		if (mkdir(root, 0777) < 0) {
    99 			fprintf(stderr,
   100 				"could not create install root \"%s\"\n",
   101 				root);
   102 			return -1;
   103 		}
   104 		fprintf(stderr, "created install root \"%s\"\n", root);
   105 	} else if (!S_ISDIR(buf.st_mode)) {
   106 		fprintf(stderr,
   107 			"install root \"%s\" exists, but is not a directory\n",
   108 			root);
   109 		return -1;
   110 	}
   111 
   112 	file = razor_concat(razor_root_path, "/", system_repo_filename, NULL);
   113 	path = razor_concat(root, file, NULL);
   114 	retval = !stat(path, &buf);
   115 	if (retval) {
   116 		fprintf(stderr,
   117 			"a razor install root is already initialized\n");
   118 		free(path);
   119 		free(file);
   120 		return retval;
   121 	}
   122 
   123 	atomic = razor_atomic_open("Create initial package set");
   124 	razor_atomic_make_dirs(atomic, root, file);
   125 	set = razor_set_create();
   126 	razor_set_write(set, atomic, path, RAZOR_SECTION_ALL);
   127 	free(path);
   128 	free(file);
   129 	retval = razor_atomic_commit(atomic);
   130 	if (retval)
   131 		fprintf(stderr, "could not write initial package set\n");
   132 	razor_set_unref(set);
   133 	razor_atomic_destroy(atomic);
   134 
   135 	return retval;
   136 }
   137 
   138 RAZOR_EXPORT struct razor_root *
   139 razor_root_open(const char *root, struct razor_atomic *atomic)
   140 {
   141 	struct razor_root *image;
   142 	char *lock_path;
   143 	int r;
   144 
   145 	assert (root != NULL);
   146 
   147 	razor_root_init();
   148 	image = malloc(sizeof *image);
   149 	if (image == NULL) {
   150 		razor_atomic_abort(atomic, "Not enough memory");
   151 		return NULL;
   152 	}
   153 
   154 	image->atomic = atomic;
   155 
   156 	image->system = razor_set_create_without_root();
   157 	if (image->system == NULL) {
   158 		free(image);
   159 		razor_atomic_abort(atomic, "Not enough memory");
   160 		return NULL;
   161 	}
   162 
   163 	lock_path = razor_concat(root, razor_root_path, "/",
   164 				 system_lock_filename, NULL);
   165 
   166 	r = razor_set_aquire_lock(image->system, lock_path, 1);
   167 
   168 	free(lock_path);
   169 
   170 	if (r < 0) {
   171 		razor_atomic_abort(atomic,
   172 				   "Failed to aquire exclusive system lock");
   173 		razor_set_unref(image->system);
   174 		free(image);
   175 		return NULL;
   176 	}
   177 
   178 	image->new_path = razor_concat(root, razor_root_path, "/",
   179 				       system_tmp_filename, NULL);
   180 	image->handle = razor_atomic_create_file(atomic, image->new_path,
   181 						 S_IRWXU | S_IRWXG | S_IRWXO);
   182 	if (image->handle < 0) {
   183 		free(image->new_path);
   184 		razor_set_unref(image->system);
   185 		free(image);
   186 		return NULL;
   187 	}
   188 
   189 	image->path = razor_concat(root, razor_root_path, "/",
   190 				   system_repo_filename, NULL);
   191 
   192 	if (razor_set_bind_sections(image->system, atomic, image->path)) {
   193 		unlink(image->new_path);
   194 		free(image->new_path);
   195 		free(image->path);
   196 		razor_set_unref(image->system);
   197 		free(image);
   198 		return NULL;
   199 	}
   200 
   201 	return image;
   202 }
   203 
   204 RAZOR_EXPORT struct razor_set *
   205 razor_root_open_read_only(const char *root, struct razor_atomic *atomic)
   206 {
   207 	char *path;
   208 	struct razor_set *set;
   209 
   210 	assert (root != NULL);
   211 
   212 	razor_root_init();
   213 	set = razor_set_create_without_root();
   214 	if (set == NULL) {
   215 		razor_atomic_abort(atomic, "Not enough memory");
   216 		return NULL;
   217 	}
   218 
   219 	path = razor_concat(root, razor_root_path, "/", system_lock_filename,
   220 			    NULL);
   221 	if (razor_set_aquire_lock(set, path, 0) < 0) {
   222 		razor_atomic_abort(atomic, "Failed to aquire non-exclusive "
   223 					   "system lock");
   224 		free(path);
   225 		razor_set_unref(set);
   226 		return NULL;
   227 	}
   228 
   229 	free(path);
   230 	path = razor_concat(root, razor_root_path, "/", system_repo_filename,
   231 			    NULL);
   232 
   233 	if (razor_set_bind_sections(set, atomic, path)) {
   234 		razor_set_unref(set);
   235 		set = NULL;
   236 	}
   237 
   238 	free(path);
   239 
   240 	return set;
   241 }
   242 
   243 RAZOR_EXPORT struct razor_set *
   244 razor_root_get_system_set(struct razor_root *root)
   245 {
   246 	assert (root != NULL);
   247 
   248 	return root->system;
   249 }
   250 
   251 RAZOR_EXPORT int
   252 razor_root_close(struct razor_root *root)
   253 {
   254 	assert (root != NULL);
   255 
   256 	razor_set_unref(root->system);
   257 	razor_atomic_close(root->atomic, root->handle);
   258 	razor_atomic_remove(root->atomic, root->new_path);
   259 	free(root->path);
   260 	free(root->new_path);
   261 	free(root);
   262 
   263 	return 0;
   264 }
   265 
   266 RAZOR_EXPORT void
   267 razor_root_update(struct razor_root *root, struct razor_set *next)
   268 {
   269 	assert (root != NULL);
   270 	assert (next != NULL);
   271 
   272 	razor_root_init();
   273 	razor_set_write_to_handle(next, root->atomic, root->handle,
   274 				  RAZOR_SECTION_ALL);
   275 	root->next = next;
   276 
   277 	/* Sync the new repo file so the new package set is on disk
   278 	 * before we start upgrading. */
   279 	razor_atomic_sync(root->atomic, root->handle);
   280 }
   281 
   282 RAZOR_EXPORT int
   283 razor_root_commit(struct razor_root *root)
   284 {
   285 	int retval;
   286 	assert (root != NULL);
   287 
   288 	razor_atomic_close(root->atomic, root->handle);
   289 	retval = razor_atomic_rename_file(root->atomic, root->new_path,
   290 					  root->path);
   291 	razor_set_unref(root->system);
   292 	free(root->path);
   293 	free(root->new_path);
   294 	free(root);
   295 
   296 	return retval;
   297 }