Home | History | Annotate | Download | only in src
      1 /* Copyright (C) 2005 Red Hat, Inc. */
      2 
      3 /* Object: dbase_file_t (File)
      4  * Extends: dbase_llist_t (Linked List)
      5  * Implements: dbase_t (Database)
      6  */
      7 
      8 struct dbase_file;
      9 typedef struct dbase_file dbase_t;
     10 #define DBASE_DEFINED
     11 
     12 #include <stdlib.h>
     13 #include <stddef.h>
     14 #include <string.h>
     15 #include <errno.h>
     16 #include <stdio.h>
     17 #include <stdio_ext.h>
     18 #include "debug.h"
     19 #include "handle.h"
     20 #include "parse_utils.h"
     21 #include "database_file.h"
     22 #include "database_llist.h"
     23 #include "semanage_store.h"
     24 
     25 /* FILE dbase */
     26 struct dbase_file {
     27 
     28 	/* Parent object - must always be
     29 	 * the first field - here we are using
     30 	 * a linked list to store the records */
     31 	dbase_llist_t llist;
     32 
     33 	/* Backing path for read-only[0] and transaction[1] */
     34 	const char *path[2];
     35 
     36 	/* FILE extension */
     37 	record_file_table_t *rftable;
     38 };
     39 
     40 static int dbase_file_cache(semanage_handle_t * handle, dbase_file_t * dbase)
     41 {
     42 
     43 	record_table_t *rtable = dbase_llist_get_rtable(&dbase->llist);
     44 	record_file_table_t *rftable = dbase->rftable;
     45 
     46 	record_t *process_record = NULL;
     47 	int pstatus = STATUS_SUCCESS;
     48 
     49 	parse_info_t *parse_info = NULL;
     50 	const char *fname = NULL;
     51 
     52 	/* Already cached */
     53 	if (!dbase_llist_needs_resync(handle, &dbase->llist))
     54 		return STATUS_SUCCESS;
     55 
     56 	/* Update cache serial */
     57 	dbase_llist_cache_init(&dbase->llist);
     58 	if (dbase_llist_set_serial(handle, &dbase->llist) < 0)
     59 		goto err;
     60 
     61 	fname = dbase->path[handle->is_in_transaction];
     62 
     63 	if (parse_init(handle, fname, NULL, &parse_info) < 0)
     64 		goto err;
     65 
     66 	if (parse_open(handle, parse_info) < 0)
     67 		goto err;
     68 
     69 	/* Main processing loop */
     70 	do {
     71 
     72 		/* Create record */
     73 		if (rtable->create(handle, &process_record) < 0)
     74 			goto err;
     75 
     76 		/* Parse record */
     77 		pstatus = rftable->parse(handle, parse_info, process_record);
     78 
     79 		/* Parse error */
     80 		if (pstatus < 0)
     81 			goto err;
     82 
     83 		/* End of file */
     84 		else if (pstatus == STATUS_NODATA)
     85 			break;
     86 
     87 		/* Prepend to cache */
     88 		if (dbase_llist_cache_prepend(handle, &dbase->llist,
     89 					      process_record) < 0)
     90 			goto err;
     91 
     92 		rtable->free(process_record);
     93 		process_record = NULL;
     94 
     95 	} while (pstatus != STATUS_NODATA);
     96 
     97 	rtable->free(process_record);
     98 	parse_close(parse_info);
     99 	parse_release(parse_info);
    100 	return STATUS_SUCCESS;
    101 
    102       err:
    103 	ERR(handle, "could not cache file database");
    104 	rtable->free(process_record);
    105 	if (parse_info) {
    106 		parse_close(parse_info);
    107 		parse_release(parse_info);
    108 	}
    109 	dbase_llist_drop_cache(&dbase->llist);
    110 	return STATUS_ERR;
    111 }
    112 
    113 /* Flush database to file */
    114 static int dbase_file_flush(semanage_handle_t * handle, dbase_file_t * dbase)
    115 {
    116 
    117 	record_file_table_t *rftable = dbase->rftable;
    118 
    119 	cache_entry_t *ptr;
    120 	const char *fname = NULL;
    121 	FILE *str = NULL;
    122 
    123 	if (!dbase_llist_is_modified(&dbase->llist))
    124 		return STATUS_SUCCESS;
    125 
    126 	fname = dbase->path[handle->is_in_transaction];
    127 
    128 	str = fopen(fname, "w");
    129 	if (!str) {
    130 		ERR(handle, "could not open %s for writing: %s",
    131 		    fname, strerror(errno));
    132 		goto err;
    133 	}
    134 	__fsetlocking(str, FSETLOCKING_BYCALLER);
    135 
    136 	if (fprintf(str, "# This file is auto-generated by libsemanage\n"
    137 		    "# Do not edit directly.\n\n") < 0) {
    138 
    139 		ERR(handle, "could not write file header for %s", fname);
    140 		goto err;
    141 	}
    142 
    143 	for (ptr = dbase->llist.cache_tail; ptr != NULL; ptr = ptr->prev) {
    144 		if (rftable->print(handle, ptr->data, str) < 0)
    145 			goto err;
    146 	}
    147 
    148 	dbase_llist_set_modified(&dbase->llist, 0);
    149 	fclose(str);
    150 	return STATUS_SUCCESS;
    151 
    152       err:
    153 	if (str != NULL)
    154 		fclose(str);
    155 
    156 	ERR(handle, "could not flush database to file");
    157 	return STATUS_ERR;
    158 }
    159 
    160 int dbase_file_init(semanage_handle_t * handle,
    161 		    const char *path_ro,
    162 		    const char *path_rw,
    163 		    record_table_t * rtable,
    164 		    record_file_table_t * rftable, dbase_file_t ** dbase)
    165 {
    166 
    167 	dbase_file_t *tmp_dbase = (dbase_file_t *) malloc(sizeof(dbase_file_t));
    168 
    169 	if (!tmp_dbase)
    170 		goto omem;
    171 
    172 	tmp_dbase->path[0] = path_ro;
    173 	tmp_dbase->path[1] = path_rw;
    174 	tmp_dbase->rftable = rftable;
    175 	dbase_llist_init(&tmp_dbase->llist, rtable, &SEMANAGE_FILE_DTABLE);
    176 
    177 	*dbase = tmp_dbase;
    178 
    179 	return STATUS_SUCCESS;
    180 
    181       omem:
    182 	ERR(handle, "out of memory, could not initialize file database");
    183 	free(tmp_dbase);
    184 	return STATUS_ERR;
    185 }
    186 
    187 /* Release dbase resources */
    188 void dbase_file_release(dbase_file_t * dbase)
    189 {
    190 
    191 	dbase_llist_drop_cache(&dbase->llist);
    192 	free(dbase);
    193 }
    194 
    195 /* FILE dbase - method table implementation */
    196 dbase_table_t SEMANAGE_FILE_DTABLE = {
    197 
    198 	/* Cache/Transactions */
    199 	.cache = dbase_file_cache,
    200 	.drop_cache = (void *)dbase_llist_drop_cache,
    201 	.flush = dbase_file_flush,
    202 	.is_modified = (void *)dbase_llist_is_modified,
    203 
    204 	/* Database API */
    205 	.iterate = (void *)dbase_llist_iterate,
    206 	.exists = (void *)dbase_llist_exists,
    207 	.list = (void *)dbase_llist_list,
    208 	.add = (void *)dbase_llist_add,
    209 	.set = (void *)dbase_llist_set,
    210 	.del = (void *)dbase_llist_del,
    211 	.clear = (void *)dbase_llist_clear,
    212 	.modify = (void *)dbase_llist_modify,
    213 	.query = (void *)dbase_llist_query,
    214 	.count = (void *)dbase_llist_count,
    215 
    216 	/* Polymorphism */
    217 	.get_rtable = (void *)dbase_llist_get_rtable
    218 };
    219