header ordering fixes for FreeBSD (pending a global merge into asterisk.h) (bug ...
[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
27 #include "asterisk.h"
28
29 ASTERISK_FILE_VERSION(__FILE__, "$Revision$")
30
31 #include "asterisk/channel.h"
32 #include "asterisk/file.h"
33 #include "asterisk/app.h"
34 #include "asterisk/dsp.h"
35 #include "asterisk/logger.h"
36 #include "asterisk/options.h"
37 #include "asterisk/astdb.h"
38 #include "asterisk/cli.h"
39 #include "asterisk/utils.h"
40 #include "asterisk/lock.h"
41 #include "asterisk/manager.h"
42 #include "db1-ast/include/db.h"
43
44 static DB *astdb;
45 AST_MUTEX_DEFINE_STATIC(dblock);
46
47 static int dbinit(void) 
48 {
49         if (!astdb) {
50                 if (!(astdb = dbopen((char *)ast_config_AST_DB, O_CREAT | O_RDWR, 0664, DB_BTREE, NULL))) {
51                         ast_log(LOG_WARNING, "Unable to open Asterisk database\n");
52                 }
53         }
54         if (astdb)
55                 return 0;
56         return -1;
57 }
58
59
60 static inline int keymatch(const char *key, const char *prefix)
61 {
62         int preflen = strlen(prefix);
63         if (!preflen)
64                 return 1;
65         if (!strcasecmp(key, prefix))
66                 return 1;
67         if ((strlen(key) > preflen) &&
68                 !strncasecmp(key, prefix, preflen)) {
69                 if (key[preflen] == '/')
70                         return 1;
71         }
72         return 0;
73 }
74
75 static inline int subkeymatch(const char *key, const char *suffix)
76 {
77         int suffixlen = strlen(suffix);
78         if (suffixlen) {
79                 const char *subkey = key + strlen(key) - suffixlen;
80                 if (subkey < key)
81                         return 0;
82                 if (!strcasecmp(subkey, suffix))
83                         return 1;
84         }
85         return 0;
86 }
87
88 int ast_db_deltree(const char *family, const char *keytree)
89 {
90         char prefix[256];
91         DBT key, data;
92         char *keys;
93         int res;
94         int pass;
95         
96         if (family) {
97                 if (keytree)
98                         snprintf(prefix, sizeof(prefix), "/%s/%s", family, keytree);
99                 else
100                         snprintf(prefix, sizeof(prefix), "/%s", family);
101         } else if (keytree)
102                 return -1;
103         else
104                 prefix[0] = '\0';
105         
106         ast_mutex_lock(&dblock);
107         if (dbinit()) 
108                 return -1;
109         
110         memset(&key, 0, sizeof(key));
111         memset(&data, 0, sizeof(data));
112         pass = 0;
113         while(!(res = astdb->seq(astdb, &key, &data, pass++ ? R_NEXT : R_FIRST))) {
114                 if (key.size) {
115                         keys = key.data;
116                         keys[key.size - 1] = '\0';
117                 } else
118                         keys = "<bad key>";
119                 if (keymatch(keys, prefix)) {
120                         astdb->del(astdb, &key, 0);
121                 }
122         }
123         astdb->sync(astdb, 0);
124         ast_mutex_unlock(&dblock);
125         return 0;
126 }
127
128 int ast_db_put(const char *family, const char *keys, char *value)
129 {
130         char fullkey[256];
131         DBT key, data;
132         int res, fullkeylen;
133
134         ast_mutex_lock(&dblock);
135         if (dbinit()) {
136                 ast_mutex_unlock(&dblock);
137                 return -1;
138         }
139
140         fullkeylen = snprintf(fullkey, sizeof(fullkey), "/%s/%s", family, keys);
141         memset(&key, 0, sizeof(key));
142         memset(&data, 0, sizeof(data));
143         key.data = fullkey;
144         key.size = fullkeylen + 1;
145         data.data = value;
146         data.size = strlen(value) + 1;
147         res = astdb->put(astdb, &key, &data, 0);
148         astdb->sync(astdb, 0);
149         ast_mutex_unlock(&dblock);
150         if (res)
151                 ast_log(LOG_WARNING, "Unable to put value '%s' for key '%s' in family '%s'\n", value, keys, family);
152         return res;
153 }
154
155 int ast_db_get(const char *family, const char *keys, char *value, int valuelen)
156 {
157         char fullkey[256]="";
158         DBT key, data;
159         int res, fullkeylen;
160
161         ast_mutex_lock(&dblock);
162         if (dbinit()) {
163                 ast_mutex_unlock(&dblock);
164                 return -1;
165         }
166
167         fullkeylen = snprintf(fullkey, sizeof(fullkey), "/%s/%s", family, keys);
168         memset(&key, 0, sizeof(key));
169         memset(&data, 0, sizeof(data));
170         memset(value, 0, valuelen);
171         key.data = fullkey;
172         key.size = fullkeylen + 1;
173         
174         res = astdb->get(astdb, &key, &data, 0);
175         
176         ast_mutex_unlock(&dblock);
177
178         /* Be sure to NULL terminate our data either way */
179         if (res) {
180                 ast_log(LOG_DEBUG, "Unable to find key '%s' in family '%s'\n", keys, family);
181         } else {
182 #if 0
183                 printf("Got value of size %d\n", data.size);
184 #endif
185                 if (data.size) {
186                         ((char *)data.data)[data.size - 1] = '\0';
187                         /* Make sure that we don't write too much to the dst pointer or we don't read too much from the source pointer */
188                         strncpy(value, data.data, (valuelen > data.size) ? data.size : valuelen);
189                         value[valuelen - 1] = '\0';
190                 } else {
191                         ast_log(LOG_NOTICE, "Strange, empty value for /%s/%s\n", family, keys);
192                 }
193         }
194         return res;
195 }
196
197 int ast_db_del(const char *family, const char *keys)
198 {
199         char fullkey[256];
200         DBT key;
201         int res, fullkeylen;
202
203         ast_mutex_lock(&dblock);
204         if (dbinit()) {
205                 ast_mutex_unlock(&dblock);
206                 return -1;
207         }
208         
209         fullkeylen = snprintf(fullkey, sizeof(fullkey), "/%s/%s", family, keys);
210         memset(&key, 0, sizeof(key));
211         key.data = fullkey;
212         key.size = fullkeylen + 1;
213         
214         res = astdb->del(astdb, &key, 0);
215         astdb->sync(astdb, 0);
216         
217         ast_mutex_unlock(&dblock);
218
219         if (res) 
220                 ast_log(LOG_DEBUG, "Unable to find key '%s' in family '%s'\n", keys, family);
221         return res;
222 }
223
224 static int database_put(int fd, int argc, char *argv[])
225 {
226         int res;
227         if (argc != 5)
228                 return RESULT_SHOWUSAGE;
229         res = ast_db_put(argv[2], argv[3], argv[4]);
230         if (res) 
231                 ast_cli(fd, "Failed to update entry\n");
232         else
233                 ast_cli(fd, "Updated database successfully\n");
234         return RESULT_SUCCESS;
235 }
236
237 static int database_get(int fd, int argc, char *argv[])
238 {
239         int res;
240         char tmp[256];
241         if (argc != 4)
242                 return RESULT_SHOWUSAGE;
243         res = ast_db_get(argv[2], argv[3], tmp, sizeof(tmp));
244         if (res) 
245                 ast_cli(fd, "Database entry not found.\n");
246         else
247                 ast_cli(fd, "Value: %s\n", tmp);
248         return RESULT_SUCCESS;
249 }
250
251 static int database_del(int fd, int argc, char *argv[])
252 {
253         int res;
254         if (argc != 4)
255                 return RESULT_SHOWUSAGE;
256         res = ast_db_del(argv[2], argv[3]);
257         if (res) 
258                 ast_cli(fd, "Database entry does not exist.\n");
259         else
260                 ast_cli(fd, "Database entry removed.\n");
261         return RESULT_SUCCESS;
262 }
263
264 static int database_deltree(int fd, int argc, char *argv[])
265 {
266         int res;
267         if ((argc < 3) || (argc > 4))
268                 return RESULT_SHOWUSAGE;
269         if (argc == 4)
270                 res = ast_db_deltree(argv[2], argv[3]);
271         else
272                 res = ast_db_deltree(argv[2], NULL);
273         if (res) 
274                 ast_cli(fd, "Database entries do not exist.\n");
275         else
276                 ast_cli(fd, "Database entries removed.\n");
277         return RESULT_SUCCESS;
278 }
279
280 static int database_show(int fd, int argc, char *argv[])
281 {
282         char prefix[256];
283         DBT key, data;
284         char *keys, *values;
285         int res;
286         int pass;
287
288         if (argc == 4) {
289                 /* Family and key tree */
290                 snprintf(prefix, sizeof(prefix), "/%s/%s", argv[2], argv[3]);
291         } else if (argc == 3) {
292                 /* Family only */
293                 snprintf(prefix, sizeof(prefix), "/%s", argv[2]);
294         } else if (argc == 2) {
295                 /* Neither */
296                 prefix[0] = '\0';
297         } else
298                 return RESULT_SHOWUSAGE;
299         ast_mutex_lock(&dblock);
300         if (dbinit()) {
301                 ast_mutex_unlock(&dblock);
302                 ast_cli(fd, "Database unavailable\n");
303                 return RESULT_SUCCESS;  
304         }
305         memset(&key, 0, sizeof(key));
306         memset(&data, 0, sizeof(data));
307         pass = 0;
308         while(!(res = astdb->seq(astdb, &key, &data, pass++ ? R_NEXT : R_FIRST))) {
309                 if (key.size) {
310                         keys = key.data;
311                         keys[key.size - 1] = '\0';
312                 } else
313                         keys = "<bad key>";
314                 if (data.size) {
315                         values = data.data;
316                         values[data.size - 1]='\0';
317                 } else
318                         values = "<bad value>";
319                 if (keymatch(keys, prefix)) {
320                                 ast_cli(fd, "%-50s: %-25s\n", keys, values);
321                 }
322         }
323         ast_mutex_unlock(&dblock);
324         return RESULT_SUCCESS;  
325 }
326
327 static int database_showkey(int fd, int argc, char *argv[])
328 {
329         char suffix[256];
330         DBT key, data;
331         char *keys, *values;
332         int res;
333         int pass;
334
335         if (argc == 3) {
336                 /* Key only */
337                 snprintf(suffix, sizeof(suffix), "/%s", argv[2]);
338         } else
339                 return RESULT_SHOWUSAGE;
340         ast_mutex_lock(&dblock);
341         if (dbinit()) {
342                 ast_mutex_unlock(&dblock);
343                 ast_cli(fd, "Database unavailable\n");
344                 return RESULT_SUCCESS;  
345         }
346         memset(&key, 0, sizeof(key));
347         memset(&data, 0, sizeof(data));
348         pass = 0;
349         while(!(res = astdb->seq(astdb, &key, &data, pass++ ? R_NEXT : R_FIRST))) {
350                 if (key.size) {
351                         keys = key.data;
352                         keys[key.size - 1] = '\0';
353                 } else
354                         keys = "<bad key>";
355                 if (data.size) {
356                         values = data.data;
357                         values[data.size - 1]='\0';
358                 } else
359                         values = "<bad value>";
360                 if (subkeymatch(keys, suffix)) {
361                                 ast_cli(fd, "%-50s: %-25s\n", keys, values);
362                 }
363         }
364         ast_mutex_unlock(&dblock);
365         return RESULT_SUCCESS;  
366 }
367
368 struct ast_db_entry *ast_db_gettree(const char *family, const char *keytree)
369 {
370         char prefix[256];
371         DBT key, data;
372         char *keys, *values;
373         int res;
374         int pass;
375         struct ast_db_entry *last = NULL;
376         struct ast_db_entry *cur, *ret=NULL;
377
378         if (family && !ast_strlen_zero(family)) {
379                 if (keytree && !ast_strlen_zero(keytree))
380                         /* Family and key tree */
381                         snprintf(prefix, sizeof(prefix), "/%s/%s", family, prefix);
382                 else
383                         /* Family only */
384                         snprintf(prefix, sizeof(prefix), "/%s", family);
385         } else
386                 prefix[0] = '\0';
387         ast_mutex_lock(&dblock);
388         if (dbinit()) {
389                 ast_mutex_unlock(&dblock);
390                 ast_log(LOG_WARNING, "Database unavailable\n");
391                 return NULL;    
392         }
393         memset(&key, 0, sizeof(key));
394         memset(&data, 0, sizeof(data));
395         pass = 0;
396         while(!(res = astdb->seq(astdb, &key, &data, pass++ ? R_NEXT : R_FIRST))) {
397                 if (key.size) {
398                         keys = key.data;
399                         keys[key.size - 1] = '\0';
400                 } else
401                         keys = "<bad key>";
402                 if (data.size) {
403                         values = data.data;
404                         values[data.size - 1]='\0';
405                 } else
406                         values = "<bad value>";
407                 if (keymatch(keys, prefix)) {
408                                 cur = malloc(sizeof(struct ast_db_entry) + strlen(keys) + strlen(values) + 2);
409                                 if (cur) {
410                                         cur->next = NULL;
411                                         cur->key = cur->data + strlen(values) + 1;
412                                         strcpy(cur->data, values);
413                                         strcpy(cur->key, keys);
414                                         if (last)
415                                                 last->next = cur;
416                                         else
417                                                 ret = cur;
418                                         last = cur;
419                                 }
420                 }
421         }
422         ast_mutex_unlock(&dblock);
423         return ret;     
424 }
425
426 void ast_db_freetree(struct ast_db_entry *dbe)
427 {
428         struct ast_db_entry *last;
429         while(dbe) {
430                 last = dbe;
431                 dbe = dbe->next;
432                 free(last);
433         }
434 }
435
436 static char database_show_usage[] =
437 "Usage: database show [family [keytree]]\n"
438 "       Shows Asterisk database contents, optionally restricted\n"
439 "to a given family, or family and keytree.\n";
440
441 static char database_showkey_usage[] =
442 "Usage: database showkey <keytree>\n"
443 "       Shows Asterisk database contents, restricted to a given key.\n";
444
445 static char database_put_usage[] =
446 "Usage: database put <family> <key> <value>\n"
447 "       Adds or updates an entry in the Asterisk database for\n"
448 "a given family, key, and value.\n";
449
450 static char database_get_usage[] =
451 "Usage: database get <family> <key>\n"
452 "       Retrieves an entry in the Asterisk database for a given\n"
453 "family and key.\n";
454
455 static char database_del_usage[] =
456 "Usage: database del <family> <key>\n"
457 "       Deletes an entry in the Asterisk database for a given\n"
458 "family and key.\n";
459
460 static char database_deltree_usage[] =
461 "Usage: database deltree <family> [keytree]\n"
462 "       Deletes a family or specific keytree within a family\n"
463 "in the Asterisk database.\n";
464
465 struct ast_cli_entry cli_database_show =
466 { { "database", "show", NULL }, database_show, "Shows database contents", database_show_usage };
467
468 struct ast_cli_entry cli_database_showkey =
469 { { "database", "showkey", NULL }, database_showkey, "Shows database contents", database_showkey_usage };
470
471 struct ast_cli_entry cli_database_get =
472 { { "database", "get", NULL }, database_get, "Gets database value", database_get_usage };
473
474 struct ast_cli_entry cli_database_put =
475 { { "database", "put", NULL }, database_put, "Adds/updates database value", database_put_usage };
476
477 struct ast_cli_entry cli_database_del =
478 { { "database", "del", NULL }, database_del, "Removes database key/value", database_del_usage };
479
480 struct ast_cli_entry cli_database_deltree =
481 { { "database", "deltree", NULL }, database_deltree, "Removes database keytree/values", database_deltree_usage };
482
483 static int manager_dbput(struct mansession *s, struct message *m)
484 {
485         char *family = astman_get_header(m, "Family");
486         char *key = astman_get_header(m, "Key");
487         char *val = astman_get_header(m, "Val");
488         int res;
489
490         if (!strlen(family)) {
491                 astman_send_error(s, m, "No family specified");
492                 return 0;
493         }
494         if (!strlen(key)) {
495                 astman_send_error(s, m, "No key specified");
496                 return 0;
497         }
498         if (!strlen(val)) {
499                 astman_send_error(s, m, "No val specified");
500                 return 0;
501         }
502
503         res = ast_db_put(family, key, val);
504         if (res)
505                 astman_send_error(s, m, "Failed to update entry");
506         else 
507                 astman_send_ack(s, m, "Updated database successfully");
508         return 0;
509 }
510
511 static int manager_dbget(struct mansession *s, struct message *m)
512 {
513         char *family = astman_get_header(m, "Family");
514         char *key = astman_get_header(m, "Key");
515         char tmp[256];
516         int res;
517
518         if (!strlen(family)) {
519                 astman_send_error(s, m, "No family specified.");
520                 return 0;
521         }
522         if (!strlen(key)) {
523                 astman_send_error(s, m, "No key specified.");
524                 return 0;
525         }
526
527         res = ast_db_get(family, key, tmp, sizeof(tmp));
528         if (res)
529                 astman_send_error(s, m, "Database entry not found");
530         else {
531                 astman_send_ack(s, m, "Result will follow");
532                 ast_cli(s->fd, "Event: DBGetResponse\r\n"
533                                 "Family: %s\r\n"
534                                 "Key: %s\r\n"
535                                 "Val: %s\r\n\r\n",
536                                 family, key, tmp);
537         }
538         return 0;
539 }
540
541 int astdb_init(void)
542 {
543         dbinit();
544         ast_cli_register(&cli_database_show);
545         ast_cli_register(&cli_database_showkey);
546         ast_cli_register(&cli_database_get);
547         ast_cli_register(&cli_database_put);
548         ast_cli_register(&cli_database_del);
549         ast_cli_register(&cli_database_deltree);
550         ast_manager_register("DBGet", EVENT_FLAG_SYSTEM, manager_dbget, "Get DB Entry");
551         ast_manager_register("DBPut", EVENT_FLAG_SYSTEM, manager_dbput, "Put DB Entry");
552         return 0;
553 }