Blame src/database_file.c

Packit Service 102278
/* Copyright (C) 2005 Red Hat, Inc. */
Packit Service 102278
Packit Service 102278
/* Object: dbase_file_t (File)
Packit Service 102278
 * Extends: dbase_llist_t (Linked List) 
Packit Service 102278
 * Implements: dbase_t (Database)
Packit Service 102278
 */
Packit Service 102278
Packit Service 102278
struct dbase_file;
Packit Service 102278
typedef struct dbase_file dbase_t;
Packit Service 102278
#define DBASE_DEFINED
Packit Service 102278
Packit Service 102278
#include <stdlib.h>
Packit Service 102278
#include <stddef.h>
Packit Service 102278
#include <string.h>
Packit Service 102278
#include <errno.h>
Packit Service 102278
#include <stdio.h>
Packit Service 102278
#include <stdio_ext.h>
Packit Service 102278
#include "debug.h"
Packit Service 102278
#include "handle.h"
Packit Service 102278
#include "parse_utils.h"
Packit Service 102278
#include "database_file.h"
Packit Service 102278
#include "database_llist.h"
Packit Service 102278
#include "semanage_store.h"
Packit Service 102278
Packit Service 102278
/* FILE dbase */
Packit Service 102278
struct dbase_file {
Packit Service 102278
Packit Service 102278
	/* Parent object - must always be 
Packit Service 102278
	 * the first field - here we are using
Packit Service 102278
	 * a linked list to store the records */
Packit Service 102278
	dbase_llist_t llist;
Packit Service 102278
Packit Service 102278
	/* Backing path for read-only[0] and transaction[1] */
Packit Service 102278
	const char *path[2];
Packit Service 102278
Packit Service 102278
	/* FILE extension */
Packit Service 102278
	record_file_table_t *rftable;
Packit Service 102278
};
Packit Service 102278
Packit Service 102278
static int dbase_file_cache(semanage_handle_t * handle, dbase_file_t * dbase)
Packit Service 102278
{
Packit Service 102278
Packit Service 102278
	record_table_t *rtable = dbase_llist_get_rtable(&dbase->llist);
Packit Service 102278
	record_file_table_t *rftable = dbase->rftable;
Packit Service 102278
Packit Service 102278
	record_t *process_record = NULL;
Packit Service 102278
	int pstatus = STATUS_SUCCESS;
Packit Service 102278
Packit Service 102278
	parse_info_t *parse_info = NULL;
Packit Service 102278
	const char *fname = NULL;
Packit Service 102278
Packit Service 102278
	/* Already cached */
Packit Service 102278
	if (!dbase_llist_needs_resync(handle, &dbase->llist))
Packit Service 102278
		return STATUS_SUCCESS;
Packit Service 102278
Packit Service 102278
	/* Update cache serial */
Packit Service 102278
	dbase_llist_cache_init(&dbase->llist);
Packit Service 102278
	if (dbase_llist_set_serial(handle, &dbase->llist) < 0)
Packit Service 102278
		goto err;
Packit Service 102278
Packit Service 102278
	fname = dbase->path[handle->is_in_transaction];
Packit Service 102278
Packit Service 102278
	if (parse_init(handle, fname, NULL, &parse_info) < 0)
Packit Service 102278
		goto err;
Packit Service 102278
Packit Service 102278
	if (parse_open(handle, parse_info) < 0)
Packit Service 102278
		goto err;
Packit Service 102278
Packit Service 102278
	/* Main processing loop */
Packit Service 102278
	do {
Packit Service 102278
Packit Service 102278
		/* Create record */
Packit Service 102278
		if (rtable->create(handle, &process_record) < 0)
Packit Service 102278
			goto err;
Packit Service 102278
Packit Service 102278
		/* Parse record */
Packit Service 102278
		pstatus = rftable->parse(handle, parse_info, process_record);
Packit Service 102278
Packit Service 102278
		/* Parse error */
Packit Service 102278
		if (pstatus < 0)
Packit Service 102278
			goto err;
Packit Service 102278
Packit Service 102278
		/* End of file */
Packit Service 102278
		else if (pstatus == STATUS_NODATA)
Packit Service 102278
			break;
Packit Service 102278
Packit Service 102278
		/* Prepend to cache */
Packit Service 102278
		if (dbase_llist_cache_prepend(handle, &dbase->llist,
Packit Service 102278
					      process_record) < 0)
Packit Service 102278
			goto err;
Packit Service 102278
Packit Service 102278
		rtable->free(process_record);
Packit Service 102278
		process_record = NULL;
Packit Service 102278
Packit Service 102278
	} while (pstatus != STATUS_NODATA);
Packit Service 102278
Packit Service 102278
	rtable->free(process_record);
Packit Service 102278
	parse_close(parse_info);
Packit Service 102278
	parse_release(parse_info);
Packit Service 102278
	return STATUS_SUCCESS;
Packit Service 102278
Packit Service 102278
      err:
Packit Service 102278
	ERR(handle, "could not cache file database");
Packit Service 102278
	rtable->free(process_record);
Packit Service 102278
	if (parse_info) {
Packit Service 102278
		parse_close(parse_info);
Packit Service 102278
		parse_release(parse_info);
Packit Service 102278
	}
Packit Service 102278
	dbase_llist_drop_cache(&dbase->llist);
Packit Service 102278
	return STATUS_ERR;
Packit Service 102278
}
Packit Service 102278
Packit Service 102278
/* Flush database to file */
Packit Service 102278
static int dbase_file_flush(semanage_handle_t * handle, dbase_file_t * dbase)
Packit Service 102278
{
Packit Service 102278
Packit Service 102278
	record_file_table_t *rftable = dbase->rftable;
Packit Service 102278
Packit Service 102278
	cache_entry_t *ptr;
Packit Service 102278
	const char *fname = NULL;
Packit Service 102278
	FILE *str = NULL;
Packit Service 102278
	mode_t mask;
Packit Service 102278
Packit Service 102278
	if (!dbase_llist_is_modified(&dbase->llist))
Packit Service 102278
		return STATUS_SUCCESS;
Packit Service 102278
Packit Service 102278
	fname = dbase->path[handle->is_in_transaction];
Packit Service 102278
Packit Service 102278
	mask = umask(0077);
Packit Service 102278
	str = fopen(fname, "w");
Packit Service 102278
	umask(mask);
Packit Service 102278
	if (!str) {
Packit Service 102278
		ERR(handle, "could not open %s for writing: %s",
Packit Service 102278
		    fname, strerror(errno));
Packit Service 102278
		goto err;
Packit Service 102278
	}
Packit Service 102278
	__fsetlocking(str, FSETLOCKING_BYCALLER);
Packit Service 102278
Packit Service 102278
	if (fprintf(str, "# This file is auto-generated by libsemanage\n"
Packit Service 102278
		    "# Do not edit directly.\n\n") < 0) {
Packit Service 102278
Packit Service 102278
		ERR(handle, "could not write file header for %s", fname);
Packit Service 102278
		goto err;
Packit Service 102278
	}
Packit Service 102278
Packit Service 102278
	for (ptr = dbase->llist.cache_tail; ptr != NULL; ptr = ptr->prev) {
Packit Service 102278
		if (rftable->print(handle, ptr->data, str) < 0)
Packit Service 102278
			goto err;
Packit Service 102278
	}
Packit Service 102278
Packit Service 102278
	dbase_llist_set_modified(&dbase->llist, 0);
Packit Service 102278
	fclose(str);
Packit Service 102278
	return STATUS_SUCCESS;
Packit Service 102278
Packit Service 102278
      err:
Packit Service 102278
	if (str != NULL)
Packit Service 102278
		fclose(str);
Packit Service 102278
Packit Service 102278
	ERR(handle, "could not flush database to file");
Packit Service 102278
	return STATUS_ERR;
Packit Service 102278
}
Packit Service 102278
Packit Service 102278
int dbase_file_init(semanage_handle_t * handle,
Packit Service 102278
		    const char *path_ro,
Packit Service 102278
		    const char *path_rw,
Packit Service 102278
		    record_table_t * rtable,
Packit Service 102278
		    record_file_table_t * rftable, dbase_file_t ** dbase)
Packit Service 102278
{
Packit Service 102278
Packit Service 102278
	dbase_file_t *tmp_dbase = (dbase_file_t *) malloc(sizeof(dbase_file_t));
Packit Service 102278
Packit Service 102278
	if (!tmp_dbase)
Packit Service 102278
		goto omem;
Packit Service 102278
Packit Service 102278
	tmp_dbase->path[0] = path_ro;
Packit Service 102278
	tmp_dbase->path[1] = path_rw;
Packit Service 102278
	tmp_dbase->rftable = rftable;
Packit Service 102278
	dbase_llist_init(&tmp_dbase->llist, rtable, &SEMANAGE_FILE_DTABLE);
Packit Service 102278
Packit Service 102278
	*dbase = tmp_dbase;
Packit Service 102278
Packit Service 102278
	return STATUS_SUCCESS;
Packit Service 102278
Packit Service 102278
      omem:
Packit Service 102278
	ERR(handle, "out of memory, could not initialize file database");
Packit Service 102278
	free(tmp_dbase);
Packit Service 102278
	return STATUS_ERR;
Packit Service 102278
}
Packit Service 102278
Packit Service 102278
/* Release dbase resources */
Packit Service 102278
void dbase_file_release(dbase_file_t * dbase)
Packit Service 102278
{
Packit Service 102278
Packit Service 102278
	dbase_llist_drop_cache(&dbase->llist);
Packit Service 102278
	free(dbase);
Packit Service 102278
}
Packit Service 102278
Packit Service 102278
/* FILE dbase - method table implementation */
Packit Service 102278
dbase_table_t SEMANAGE_FILE_DTABLE = {
Packit Service 102278
Packit Service 102278
	/* Cache/Transactions */
Packit Service 102278
	.cache = dbase_file_cache,
Packit Service 102278
	.drop_cache = (void *)dbase_llist_drop_cache,
Packit Service 102278
	.flush = dbase_file_flush,
Packit Service 102278
	.is_modified = (void *)dbase_llist_is_modified,
Packit Service 102278
Packit Service 102278
	/* Database API */
Packit Service 102278
	.iterate = (void *)dbase_llist_iterate,
Packit Service 102278
	.exists = (void *)dbase_llist_exists,
Packit Service 102278
	.list = (void *)dbase_llist_list,
Packit Service 102278
	.add = (void *)dbase_llist_add,
Packit Service 102278
	.set = (void *)dbase_llist_set,
Packit Service 102278
	.del = (void *)dbase_llist_del,
Packit Service 102278
	.clear = (void *)dbase_llist_clear,
Packit Service 102278
	.modify = (void *)dbase_llist_modify,
Packit Service 102278
	.query = (void *)dbase_llist_query,
Packit Service 102278
	.count = (void *)dbase_llist_count,
Packit Service 102278
Packit Service 102278
	/* Polymorphism */
Packit Service 102278
	.get_rtable = (void *)dbase_llist_get_rtable
Packit Service 102278
};