Revert Jim's earlier "fix" :)
[asterisk/asterisk.git] / db.c
1 /*
2  * Asterisk -- A telephony toolkit for Linux.
3  *
4  * Channel Management
5  * 
6  * Copyright (C) 1999, Mark Spencer
7  *
8  * Mark Spencer <markster@linux-support.net>
9  *
10  * This program is free software, distributed under the terms of
11  * the GNU General Public License
12  */
13
14 /* DB3 is licensed under Sleepycat Public License and is thus incompatible
15    with GPL.  To avoid having to make another exception (and complicate 
16    licensing even further) we elect to use DB1 which is BSD licensed */
17
18 #include <stdio.h>
19 #include <stdlib.h>
20 #include <string.h>
21 #include <sys/time.h>
22 #include <signal.h>
23 #include <errno.h>
24 #include <unistd.h>
25 #include <dirent.h>
26 #include <asterisk/channel.h>
27 #include <asterisk/file.h>
28 #include <asterisk/app.h>
29 #include <asterisk/dsp.h>
30 #include <asterisk/logger.h>
31 #include <asterisk/options.h>
32 #include <asterisk/astdb.h>
33 #include <asterisk/cli.h>
34 #include <asterisk/utils.h>
35 #include <asterisk/lock.h>
36 #include "db1-ast/include/db.h"
37 #include "asterisk.h"
38 #include "astconf.h"
39
40 static DB *astdb;
41 AST_MUTEX_DEFINE_STATIC(dblock);
42
43 static int dbinit(void) 
44 {
45         if (!astdb) {
46                 if (!(astdb = dbopen((char *)ast_config_AST_DB, O_CREAT | O_RDWR, 0664, DB_BTREE, NULL))) {
47                         ast_log(LOG_WARNING, "Unable to open Asterisk database\n");
48                 }
49         }
50         if (astdb)
51                 return 0;
52         return -1;
53 }
54
55
56 static inline int keymatch(const char *key, const char *prefix)
57 {
58         int preflen = strlen(prefix);
59         if (!preflen)
60                 return 1;
61         if (!strcasecmp(key, prefix))
62                 return 1;
63         if ((strlen(key) > preflen) &&
64                 !strncasecmp(key, prefix, preflen)) {
65                 if (key[preflen] == '/')
66                         return 1;
67         }
68         return 0;
69 }
70
71 static inline int subkeymatch(const char *key, const char *suffix)
72 {
73         int suffixlen = strlen(suffix);
74         if (suffixlen) {
75                 const char *subkey = key + strlen(key) - suffixlen;
76                 if (subkey < key)
77                         return 0;
78                 if (!strcasecmp(subkey, suffix))
79                         return 1;
80         }
81         return 0;
82 }
83
84 int ast_db_deltree(const char *family, const char *keytree)
85 {
86         char prefix[256];
87         DBT key, data;
88         char *keys;
89         int res;
90         int pass;
91         
92         if (family) {
93                 if (keytree)
94                         snprintf(prefix, sizeof(prefix), "/%s/%s", family, keytree);
95                 else
96                         snprintf(prefix, sizeof(prefix), "/%s", family);
97         } else if (keytree)
98                 return -1;
99         else
100                 prefix[0] = '\0';
101         
102         ast_mutex_lock(&dblock);
103         if (dbinit()) 
104                 return -1;
105         
106         memset(&key, 0, sizeof(key));
107         memset(&data, 0, sizeof(data));
108         pass = 0;
109         while(!(res = astdb->seq(astdb, &key, &data, pass++ ? R_NEXT : R_FIRST))) {
110                 if (key.size) {
111                         keys = key.data;
112                         keys[key.size - 1] = '\0';
113                 } else
114                         keys = "<bad key>";
115                 if (keymatch(keys, prefix)) {
116                         astdb->del(astdb, &key, 0);
117                 }
118         }
119         astdb->sync(astdb, 0);
120         ast_mutex_unlock(&dblock);
121         return 0;
122 }
123
124 int ast_db_put(const char *family, const char *keys, char *value)
125 {
126         char fullkey[256];
127         DBT key, data;
128         int res, fullkeylen;
129
130         ast_mutex_lock(&dblock);
131         if (dbinit()) {
132                 ast_mutex_unlock(&dblock);
133                 return -1;
134         }
135
136         fullkeylen = snprintf(fullkey, sizeof(fullkey), "/%s/%s", family, keys);
137         memset(&key, 0, sizeof(key));
138         memset(&data, 0, sizeof(data));
139         key.data = fullkey;
140         key.size = fullkeylen + 1;
141         data.data = value;
142         data.size = strlen(value) + 1;
143         res = astdb->put(astdb, &key, &data, 0);
144         astdb->sync(astdb, 0);
145         ast_mutex_unlock(&dblock);
146         if (res)
147                 ast_log(LOG_WARNING, "Unable to put value '%s' for key '%s' in family '%s'\n", value, keys, family);
148         return res;
149 }
150
151 int ast_db_get(const char *family, const char *keys, char *value, int valuelen)
152 {
153         char fullkey[256]="";
154         DBT key, data;
155         int res, fullkeylen;
156
157         ast_mutex_lock(&dblock);
158         if (dbinit()) {
159                 ast_mutex_unlock(&dblock);
160                 return -1;
161         }
162
163         fullkeylen = snprintf(fullkey, sizeof(fullkey), "/%s/%s", family, keys);
164         memset(&key, 0, sizeof(key));
165         memset(&data, 0, sizeof(data));
166         memset(value, 0, valuelen);
167         key.data = fullkey;
168         key.size = fullkeylen + 1;
169         
170         res = astdb->get(astdb, &key, &data, 0);
171         
172         ast_mutex_unlock(&dblock);
173
174         /* Be sure to NULL terminate our data either way */
175         if (res) {
176                 ast_log(LOG_DEBUG, "Unable to find key '%s' in family '%s'\n", keys, family);
177         } else {
178 #if 0
179                 printf("Got value of size %d\n", data.size);
180 #endif
181                 if (data.size) {
182                         ((char *)data.data)[data.size - 1] = '\0';
183                         /* Make sure that we don't write too much to the dst pointer or we don't read too much from the source pointer */
184                         strncpy(value, data.data, (valuelen > data.size) ? data.size : valuelen);
185                         value[valuelen - 1] = '\0';
186                 } else {
187                         ast_log(LOG_NOTICE, "Strange, empty value for /%s/%s\n", family, keys);
188                 }
189         }
190         return res;
191 }
192
193 int ast_db_del(const char *family, const char *keys)
194 {
195         char fullkey[256];
196         DBT key;
197         int res, fullkeylen;
198
199         ast_mutex_lock(&dblock);
200         if (dbinit()) {
201                 ast_mutex_unlock(&dblock);
202                 return -1;
203         }
204         
205         fullkeylen = snprintf(fullkey, sizeof(fullkey), "/%s/%s", family, keys);
206         memset(&key, 0, sizeof(key));
207         key.data = fullkey;
208         key.size = fullkeylen + 1;
209         
210         res = astdb->del(astdb, &key, 0);
211         astdb->sync(astdb, 0);
212         
213         ast_mutex_unlock(&dblock);
214
215         if (res) 
216                 ast_log(LOG_DEBUG, "Unable to find key '%s' in family '%s'\n", keys, family);
217         return res;
218 }
219
220 static int database_put(int fd, int argc, char *argv[])
221 {
222         int res;
223         if (argc != 5)
224                 return RESULT_SHOWUSAGE;
225         res = ast_db_put(argv[2], argv[3], argv[4]);
226         if (res) 
227                 ast_cli(fd, "Failed to update entry\n");
228         else
229                 ast_cli(fd, "Updated database successfully\n");
230         return RESULT_SUCCESS;
231 }
232
233 static int database_get(int fd, int argc, char *argv[])
234 {
235         int res;
236         char tmp[256];
237         if (argc != 4)
238                 return RESULT_SHOWUSAGE;
239         res = ast_db_get(argv[2], argv[3], tmp, sizeof(tmp));
240         if (res) 
241                 ast_cli(fd, "Database entry not found.\n");
242         else
243                 ast_cli(fd, "Value: %s\n", tmp);
244         return RESULT_SUCCESS;
245 }
246
247 static int database_del(int fd, int argc, char *argv[])
248 {
249         int res;
250         if (argc != 4)
251                 return RESULT_SHOWUSAGE;
252         res = ast_db_del(argv[2], argv[3]);
253         if (res) 
254                 ast_cli(fd, "Database entry does not exist.\n");
255         else
256                 ast_cli(fd, "Database entry removed.\n");
257         return RESULT_SUCCESS;
258 }
259
260 static int database_deltree(int fd, int argc, char *argv[])
261 {
262         int res;
263         if ((argc < 3) || (argc > 4))
264                 return RESULT_SHOWUSAGE;
265         if (argc == 4)
266                 res = ast_db_deltree(argv[2], argv[3]);
267         else
268                 res = ast_db_deltree(argv[2], NULL);
269         if (res) 
270                 ast_cli(fd, "Database entries do not exist.\n");
271         else
272                 ast_cli(fd, "Database entries removed.\n");
273         return RESULT_SUCCESS;
274 }
275
276 static int database_show(int fd, int argc, char *argv[])
277 {
278         char prefix[256];
279         DBT key, data;
280         char *keys, *values;
281         int res;
282         int pass;
283
284         if (argc == 4) {
285                 /* Family and key tree */
286                 snprintf(prefix, sizeof(prefix), "/%s/%s", argv[2], argv[3]);
287         } else if (argc == 3) {
288                 /* Family only */
289                 snprintf(prefix, sizeof(prefix), "/%s", argv[2]);
290         } else if (argc == 2) {
291                 /* Neither */
292                 prefix[0] = '\0';
293         } else
294                 return RESULT_SHOWUSAGE;
295         ast_mutex_lock(&dblock);
296         if (dbinit()) {
297                 ast_mutex_unlock(&dblock);
298                 ast_cli(fd, "Database unavailable\n");
299                 return RESULT_SUCCESS;  
300         }
301         memset(&key, 0, sizeof(key));
302         memset(&data, 0, sizeof(data));
303         pass = 0;
304         while(!(res = astdb->seq(astdb, &key, &data, pass++ ? R_NEXT : R_FIRST))) {
305                 if (key.size) {
306                         keys = key.data;
307                         keys[key.size - 1] = '\0';
308                 } else
309                         keys = "<bad key>";
310                 if (data.size) {
311                         values = data.data;
312                         values[data.size - 1]='\0';
313                 } else
314                         values = "<bad value>";
315                 if (keymatch(keys, prefix)) {
316                                 ast_cli(fd, "%-50s: %-25s\n", keys, values);
317                 }
318         }
319         ast_mutex_unlock(&dblock);
320         return RESULT_SUCCESS;  
321 }
322
323 static int database_showkey(int fd, int argc, char *argv[])
324 {
325         char suffix[256];
326         DBT key, data;
327         char *keys, *values;
328         int res;
329         int pass;
330
331         if (argc == 3) {
332                 /* Key only */
333                 snprintf(suffix, sizeof(suffix), "/%s", argv[2]);
334         } else
335                 return RESULT_SHOWUSAGE;
336         ast_mutex_lock(&dblock);
337         if (dbinit()) {
338                 ast_mutex_unlock(&dblock);
339                 ast_cli(fd, "Database unavailable\n");
340                 return RESULT_SUCCESS;  
341         }
342         memset(&key, 0, sizeof(key));
343         memset(&data, 0, sizeof(data));
344         pass = 0;
345         while(!(res = astdb->seq(astdb, &key, &data, pass++ ? R_NEXT : R_FIRST))) {
346                 if (key.size) {
347                         keys = key.data;
348                         keys[key.size - 1] = '\0';
349                 } else
350                         keys = "<bad key>";
351                 if (data.size) {
352                         values = data.data;
353                         values[data.size - 1]='\0';
354                 } else
355                         values = "<bad value>";
356                 if (subkeymatch(keys, suffix)) {
357                                 ast_cli(fd, "%-50s: %-25s\n", keys, values);
358                 }
359         }
360         ast_mutex_unlock(&dblock);
361         return RESULT_SUCCESS;  
362 }
363
364 struct ast_db_entry *ast_db_gettree(const char *family, const char *keytree)
365 {
366         char prefix[256];
367         DBT key, data;
368         char *keys, *values;
369         int res;
370         int pass;
371         struct ast_db_entry *last = NULL;
372         struct ast_db_entry *cur, *ret=NULL;
373
374         if (family && !ast_strlen_zero(family)) {
375                 if (keytree && !ast_strlen_zero(keytree))
376                         /* Family and key tree */
377                         snprintf(prefix, sizeof(prefix), "/%s/%s", family, prefix);
378                 else
379                         /* Family only */
380                         snprintf(prefix, sizeof(prefix), "/%s", family);
381         } else
382                 prefix[0] = '\0';
383         ast_mutex_lock(&dblock);
384         if (dbinit()) {
385                 ast_mutex_unlock(&dblock);
386                 ast_log(LOG_WARNING, "Database unavailable\n");
387                 return NULL;    
388         }
389         memset(&key, 0, sizeof(key));
390         memset(&data, 0, sizeof(data));
391         pass = 0;
392         while(!(res = astdb->seq(astdb, &key, &data, pass++ ? R_NEXT : R_FIRST))) {
393                 if (key.size) {
394                         keys = key.data;
395                         keys[key.size - 1] = '\0';
396                 } else
397                         keys = "<bad key>";
398                 if (data.size) {
399                         values = data.data;
400                         values[data.size - 1]='\0';
401                 } else
402                         values = "<bad value>";
403                 if (keymatch(keys, prefix)) {
404                                 cur = malloc(sizeof(struct ast_db_entry) + strlen(keys) + strlen(values) + 2);
405                                 if (cur) {
406                                         cur->next = NULL;
407                                         cur->key = cur->data + strlen(values) + 1;
408                                         strcpy(cur->data, values);
409                                         strcpy(cur->key, keys);
410                                         if (last)
411                                                 last->next = cur;
412                                         else
413                                                 ret = cur;
414                                         last = cur;
415                                 }
416                 }
417         }
418         ast_mutex_unlock(&dblock);
419         return ret;     
420 }
421
422 void ast_db_freetree(struct ast_db_entry *dbe)
423 {
424         struct ast_db_entry *last;
425         while(dbe) {
426                 last = dbe;
427                 dbe = dbe->next;
428                 free(last);
429         }
430 }
431
432 static char database_show_usage[] =
433 "Usage: database show [family [keytree]]\n"
434 "       Shows Asterisk database contents, optionally restricted\n"
435 "to a given family, or family and keytree.\n";
436
437 static char database_showkey_usage[] =
438 "Usage: database showkey <keytree>\n"
439 "       Shows Asterisk database contents, restricted to a given key.\n";
440
441 static char database_put_usage[] =
442 "Usage: database put <family> <key> <value>\n"
443 "       Adds or updates an entry in the Asterisk database for\n"
444 "a given family, key, and value.\n";
445
446 static char database_get_usage[] =
447 "Usage: database get <family> <key>\n"
448 "       Retrieves an entry in the Asterisk database for a given\n"
449 "family and key.\n";
450
451 static char database_del_usage[] =
452 "Usage: database del <family> <key>\n"
453 "       Deletes an entry in the Asterisk database for a given\n"
454 "family and key.\n";
455
456 static char database_deltree_usage[] =
457 "Usage: database deltree <family> [keytree]\n"
458 "       Deletes a family or specific keytree within a family\n"
459 "in the Asterisk database.\n";
460
461 struct ast_cli_entry cli_database_show =
462 { { "database", "show", NULL }, database_show, "Shows database contents", database_show_usage };
463
464 struct ast_cli_entry cli_database_showkey =
465 { { "database", "showkey", NULL }, database_showkey, "Shows database contents", database_showkey_usage };
466
467 struct ast_cli_entry cli_database_get =
468 { { "database", "get", NULL }, database_get, "Gets database value", database_get_usage };
469
470 struct ast_cli_entry cli_database_put =
471 { { "database", "put", NULL }, database_put, "Adds/updates database value", database_put_usage };
472
473 struct ast_cli_entry cli_database_del =
474 { { "database", "del", NULL }, database_del, "Removes database key/value", database_del_usage };
475
476 struct ast_cli_entry cli_database_deltree =
477 { { "database", "deltree", NULL }, database_deltree, "Removes database keytree/values", database_deltree_usage };
478
479 int astdb_init(void)
480 {
481         dbinit();
482         ast_cli_register(&cli_database_show);
483         ast_cli_register(&cli_database_showkey);
484         ast_cli_register(&cli_database_get);
485         ast_cli_register(&cli_database_put);
486         ast_cli_register(&cli_database_del);
487         ast_cli_register(&cli_database_deltree);
488         return 0;
489 }