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
dbase_file_cache(semanage_handle_t * handle,dbase_file_t * dbase)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 */
dbase_file_flush(semanage_handle_t * handle,dbase_file_t * dbase)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
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)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 */
dbase_file_release(dbase_file_t * dbase)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