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 	mode_t mask;
    123 
    124 	if (!dbase_llist_is_modified(&dbase->llist))
    125 		return STATUS_SUCCESS;
    126 
    127 	fname = dbase->path[handle->is_in_transaction];
    128 
    129 	mask = umask(0077);
    130 	str = fopen(fname, "w");
    131 	umask(mask);
    132 	if (!str) {
    133 		ERR(handle, "could not open %s for writing: %s",
    134 		    fname, strerror(errno));
    135 		goto err;
    136 	}
    137 	__fsetlocking(str, FSETLOCKING_BYCALLER);
    138 
    139 	if (fprintf(str, "# This file is auto-generated by libsemanage\n"
    140 		    "# Do not edit directly.\n\n") < 0) {
    141 
    142 		ERR(handle, "could not write file header for %s", fname);
    143 		goto err;
    144 	}
    145 
    146 	for (ptr = dbase->llist.cache_tail; ptr != NULL; ptr = ptr->prev) {
    147 		if (rftable->print(handle, ptr->data, str) < 0)
    148 			goto err;
    149 	}
    150 
    151 	dbase_llist_set_modified(&dbase->llist, 0);
    152 	fclose(str);
    153 	return STATUS_SUCCESS;
    154 
    155       err:
    156 	if (str != NULL)
    157 		fclose(str);
    158 
    159 	ERR(handle, "could not flush database to file");
    160 	return STATUS_ERR;
    161 }
    162 
    163 int dbase_file_init(semanage_handle_t * handle,
    164 		    const char *path_ro,
    165 		    const char *path_rw,
    166 		    record_table_t * rtable,
    167 		    record_file_table_t * rftable, dbase_file_t ** dbase)
    168 {
    169 
    170 	dbase_file_t *tmp_dbase = (dbase_file_t *) malloc(sizeof(dbase_file_t));
    171 
    172 	if (!tmp_dbase)
    173 		goto omem;
    174 
    175 	tmp_dbase->path[0] = path_ro;
    176 	tmp_dbase->path[1] = path_rw;
    177 	tmp_dbase->rftable = rftable;
    178 	dbase_llist_init(&tmp_dbase->llist, rtable, &SEMANAGE_FILE_DTABLE);
    179 
    180 	*dbase = tmp_dbase;
    181 
    182 	return STATUS_SUCCESS;
    183 
    184       omem:
    185 	ERR(handle, "out of memory, could not initialize file database");
    186 	free(tmp_dbase);
    187 	return STATUS_ERR;
    188 }
    189 
    190 /* Release dbase resources */
    191 void dbase_file_release(dbase_file_t * dbase)
    192 {
    193 
    194 	dbase_llist_drop_cache(&dbase->llist);
    195 	free(dbase);
    196 }
    197 
    198 /* FILE dbase - method table implementation */
    199 dbase_table_t SEMANAGE_FILE_DTABLE = {
    200 
    201 	/* Cache/Transactions */
    202 	.cache = dbase_file_cache,
    203 	.drop_cache = (void *)dbase_llist_drop_cache,
    204 	.flush = dbase_file_flush,
    205 	.is_modified = (void *)dbase_llist_is_modified,
    206 
    207 	/* Database API */
    208 	.iterate = (void *)dbase_llist_iterate,
    209 	.exists = (void *)dbase_llist_exists,
    210 	.list = (void *)dbase_llist_list,
    211 	.add = (void *)dbase_llist_add,
    212 	.set = (void *)dbase_llist_set,
    213 	.del = (void *)dbase_llist_del,
    214 	.clear = (void *)dbase_llist_clear,
    215 	.modify = (void *)dbase_llist_modify,
    216 	.query = (void *)dbase_llist_query,
    217 	.count = (void *)dbase_llist_count,
    218 
    219 	/* Polymorphism */
    220 	.get_rtable = (void *)dbase_llist_get_rtable
    221 };
    222