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