ViewVC Help
View File | Revision Log | Show Annotations | View Changeset | Root Listing
root/svn/vendor/ircservices-5.1.24/databases.c
Revision: 1171
Committed: Fri Aug 12 20:00:46 2011 UTC (12 years, 8 months ago) by michael
Content type: text/x-csrc
File size: 9571 byte(s)
Log Message:
- Import ircservices-5.1.24. Don't ever think about modifying anything in this
  folder!
  Since Andrew Church has discontinued his services project in April 2011, the
  ircd-hybrid team has been given permissions to officially continue and
  maintain the already mentioned project.
  The name of this project will be changed for the reason being that the current
  name "IRC Services" is way too generic these days.

  Remember: Don't ever modify anything in here. This folder is kept for reference.

File Contents

# Content
1 /* Database core routines.
2 *
3 * IRC Services is copyright (c) 1996-2009 Andrew Church.
4 * E-mail: <achurch@achurch.org>
5 * Parts written by Andrew Kempe and others.
6 * This program is free but copyrighted software; see the file GPL.txt for
7 * details.
8 */
9
10 #include "services.h"
11 #include "databases.h"
12 #include "encrypt.h"
13 #include "modules.h"
14
15 /*************************************************************************/
16
17 /* List of registered tables */
18 typedef struct dbtablenode_ DBTableNode;
19 struct dbtablenode_ {
20 DBTableNode *next, *prev;
21 DBTable *table;
22 const Module *owner; /* Which module registered this table? */
23 int loaded; /* Has this table been loaded? */
24 };
25 static DBTableNode *tables = NULL;
26
27 /* Currently active database module */
28 static DBModule *dbmodule = NULL;
29
30
31 /* Local routines: */
32 static int do_unload_module(const Module *module);
33
34 /*************************************************************************/
35 /*************************************************************************/
36
37 /* Initialization/cleanup routines. */
38
39 int database_init(int ac, char **av)
40 {
41 if (!add_callback(NULL, "unload module", do_unload_module)) {
42 log("database_init: add_callback() failed");
43 return 0;
44 }
45 return 1;
46 }
47
48 /************************************/
49
50 void database_cleanup(void)
51 {
52 remove_callback(NULL, "unload module", do_unload_module);
53 }
54
55 /************************************/
56
57 /* Check for tables that the module forgot to unload. */
58
59 static int do_unload_module(const Module *module)
60 {
61 DBTableNode *t, *t2;
62
63 LIST_FOREACH_SAFE (t, tables, t2) {
64 if (t->owner == module) {
65 log("database: Module `%s' forgot to unregister table `%s'",
66 get_module_name(module), t->table->name);
67 unregister_dbtable(t->table);
68 }
69 }
70 return 0;
71 }
72
73 /*************************************************************************/
74
75 /* Register a new database table. Returns nonzero on success, zero on
76 * error.
77 */
78
79 int _register_dbtable(DBTable *table, const Module *caller)
80 {
81 DBTableNode *t;
82
83 /* Sanity checks on parameter */
84 if (!table) {
85 log("BUG: register_dbtable() with NULL table!");
86 return 0;
87 }
88 if (!table->name) {
89 log("BUG: register_dbtable(): table->name is NULL!");
90 return 0;
91 }
92 if (!table->fields || !table->newrec || !table->freerec
93 || !table->insert || !table->first || !table->next
94 ) {
95 log("BUG: register_dbtable(%s): table->%s is NULL!", table->name,
96 !table->fields ? "fields" :
97 !table->newrec ? "newrec" :
98 !table->freerec ? "freerec" :
99 !table->insert ? "insert" :
100 !table->first ? "first" :
101 !table->next ? "next" :
102 "???");
103 return 0;
104 }
105
106 /* Sanity check: make sure it's not already registered */
107 LIST_FOREACH (t, tables) {
108 if (t->table == table) {
109 log("BUG: register_dbtable(%s): table already registered!",
110 table->name);
111 break;
112 }
113 }
114
115 /* Allocate and append to list (make sure to preserve order, since
116 * later tables may depend on earlier ones); if a database module is
117 * available, load the table ammediately*/
118 t = smalloc(sizeof(*t));
119 t->table = table;
120 t->owner = caller;
121 t->loaded = 0;
122 LIST_APPEND(t, tables);
123 if (dbmodule)
124 t->loaded = (*dbmodule->load_table)(t->table);
125
126 return 1;
127 }
128
129 /*************************************************************************/
130
131 /* Unregister a database table. Does nothing if the table was not
132 * registered in the first place.
133 */
134
135 void unregister_dbtable(DBTable *table)
136 {
137 DBTableNode *t;
138
139 if (!table) {
140 log("BUG: unregister_dbtable() with NULL table!");
141 return;
142 }
143 /* Sanity check: make sure it was registered first */
144 LIST_FOREACH (t, tables) {
145 if (t->table == table) {
146 LIST_REMOVE(t, tables);
147 free(t);
148 break;
149 }
150 }
151 }
152
153 /*************************************************************************/
154
155 /* Save all registered database tables to permanent storage. Returns 1 if
156 * all tables were successfully saved or no tables are registered, 0 if
157 * some tables were successfully saved (but some were not), or -1 if no
158 * tables were successfully saved.
159 */
160
161 int save_all_dbtables(void)
162 {
163 DBTableNode *t;
164 int some_saved = 0;
165 int some_failed = 0;
166
167 if (!tables)
168 return 1;
169 if (!dbmodule) {
170 log("save_all_dbtables(): No database module registered!");
171 return -1;
172 }
173 LIST_FOREACH (t, tables) {
174 if ((*dbmodule->save_table)(t->table)) {
175 some_saved = 1;
176 } else {
177 log("save_all_dbtables(): Failed to save table `%s'",
178 t->table->name);
179 some_failed = 1;
180 }
181 }
182 return some_saved - some_failed;
183 }
184
185 /*************************************************************************/
186 /*************************************************************************/
187
188 /* Register a database module. Returns nonzero on success, zero on error.
189 * On success, all registered tables which have not already been loaded
190 * will be loaded from permanent storage. Only one database module can be
191 * registered.
192 */
193
194 int register_dbmodule(DBModule *module)
195 {
196 DBTableNode *t;
197
198 if (!module) {
199 log("BUG: register_dbmodule() with NULL module!");
200 return 0;
201 }
202 if (!module->load_table || !module->save_table) {
203 log("BUG: register_dbmodule(): module->%s is NULL!",
204 !module->load_table ? "load_table" : "save_table");
205 return 0;
206 }
207 if (dbmodule) {
208 if (module == dbmodule)
209 log("BUG: register_dbmodule(): attempt to re-register module!");
210 else
211 log("register_dbmodule(): a database module is already registered");
212 return 0;
213 }
214
215 dbmodule = module;
216 LIST_FOREACH (t, tables) {
217 if (!t->loaded)
218 t->loaded = (*dbmodule->load_table)(t->table);
219 }
220 return 1;
221 }
222
223 /*************************************************************************/
224
225 /* Unregister a database module. Does nothing if the module was not
226 * registered in the first place.
227 */
228
229 void unregister_dbmodule(DBModule *module)
230 {
231 if (!module) {
232 log("BUG: unregister_dbmodule() with NULL module!");
233 return;
234 }
235 if (dbmodule == module)
236 dbmodule = NULL;
237 }
238
239 /*************************************************************************/
240
241 /* Read a value from a database field. The value buffer is assumed to be
242 * large enough to hold the retrieved value.
243 */
244
245 void get_dbfield(const void *record, const DBField *field, void *buffer)
246 {
247 int size;
248
249 if (!record || !field || !buffer) {
250 log("BUG: get_dbfield(): %s is NULL!",
251 !record ? "record" : !field ? "field" : "buffer");
252 return;
253 }
254 if (field->get) {
255 (*field->get)(record, buffer);
256 return;
257 }
258 switch (field->type) {
259 case DBTYPE_INT8: size = 1; break;
260 case DBTYPE_UINT8: size = 1; break;
261 case DBTYPE_INT16: size = 2; break;
262 case DBTYPE_UINT16: size = 2; break;
263 case DBTYPE_INT32: size = 4; break;
264 case DBTYPE_UINT32: size = 4; break;
265 case DBTYPE_TIME: size = sizeof(time_t); break;
266 case DBTYPE_STRING: size = sizeof(char *); break;
267 case DBTYPE_BUFFER: size = field->length; break;
268 case DBTYPE_PASSWORD: size = sizeof(Password); break;
269 default:
270 log("BUG: bad field type %d in get_dbfield()", field->type);
271 return;
272 }
273 if (!size) {
274 return;
275 }
276 memcpy(buffer, (const uint8 *)record + field->offset, size);
277 }
278
279 /*************************************************************************/
280
281 /* Store a value to a database field. */
282
283 void put_dbfield(void *record, const DBField *field, const void *value)
284 {
285 int size;
286
287 if (!record || !field || !value) {
288 log("BUG: get_dbfield(): %s is NULL!",
289 !record ? "record" : !field ? "field" : "value");
290 return;
291 }
292 if (field->put) {
293 (*field->put)(record, value);
294 return;
295 }
296 switch (field->type) {
297 case DBTYPE_INT8: size = 1; break;
298 case DBTYPE_UINT8: size = 1; break;
299 case DBTYPE_INT16: size = 2; break;
300 case DBTYPE_UINT16: size = 2; break;
301 case DBTYPE_INT32: size = 4; break;
302 case DBTYPE_UINT32: size = 4; break;
303 case DBTYPE_TIME: size = sizeof(time_t); break;
304 case DBTYPE_STRING: size = sizeof(char *); break;
305 case DBTYPE_BUFFER: size = field->length; break;
306 case DBTYPE_PASSWORD: size = sizeof(Password); break;
307 default:
308 log("BUG: bad field type %d in get_dbfield()", field->type);
309 return;
310 }
311 if (!size) {
312 return;
313 }
314 memcpy((uint8 *)record + field->offset, value, size);
315 }
316
317 /*************************************************************************/
318
319 /*
320 * Local variables:
321 * c-file-style: "stroustrup"
322 * c-file-offsets: ((case-label . *) (statement-case-intro . *))
323 * indent-tabs-mode: nil
324 * End:
325 *
326 * vim: expandtab shiftwidth=4:
327 */