another bunch of include removals (errno.h and asterisk/logger.h)
[asterisk/asterisk.git] / main / db.c
1 /*
2  * Asterisk -- An open source telephony toolkit.
3  *
4  * Copyright (C) 1999 - 2005, Digium, Inc.
5  *
6  * Mark Spencer <markster@digium.com>
7  *
8  * See http://www.asterisk.org for more information about
9  * the Asterisk project. Please do not directly contact
10  * any of the maintainers of this project for assistance;
11  * the project provides a web site, mailing lists and IRC
12  * channels for your use.
13  *
14  * This program is free software, distributed under the terms of
15  * the GNU General Public License Version 2. See the LICENSE file
16  * at the top of the source tree.
17  */
18
19 /*! \file
20  *
21  * \brief ASTdb Management
22  *
23  * \author Mark Spencer <markster@digium.com> 
24  *
25  * \note DB3 is licensed under Sleepycat Public License and is thus incompatible
26  * with GPL.  To avoid having to make another exception (and complicate 
27  * licensing even further) we elect to use DB1 which is BSD licensed 
28  */
29
30 #include "asterisk.h"
31
32 ASTERISK_FILE_VERSION(__FILE__, "$Revision$")
33
34 #include <sys/time.h>
35 #include <signal.h>
36 #include <dirent.h>
37
38 #include "asterisk/channel.h"
39 #include "asterisk/file.h"
40 #include "asterisk/app.h"
41 #include "asterisk/dsp.h"
42 #include "asterisk/options.h"
43 #include "asterisk/astdb.h"
44 #include "asterisk/cli.h"
45 #include "asterisk/utils.h"
46 #include "asterisk/lock.h"
47 #include "asterisk/manager.h"
48 #include "db1-ast/include/db.h"
49
50 static DB *astdb;
51 AST_MUTEX_DEFINE_STATIC(dblock);
52
53 static int dbinit(void) 
54 {
55         if (!astdb && !(astdb = dbopen((char *)ast_config_AST_DB, O_CREAT | O_RDWR, AST_FILE_MODE, DB_BTREE, NULL))) {
56                 ast_log(LOG_WARNING, "Unable to open Asterisk database '%s': %s\n", ast_config_AST_DB, strerror(errno));
57                 return -1;
58         }
59         return 0;
60 }
61
62
63 static inline int keymatch(const char *key, const char *prefix)
64 {
65         int preflen = strlen(prefix);
66         if (!preflen)
67                 return 1;
68         if (!strcasecmp(key, prefix))
69                 return 1;
70         if ((strlen(key) > preflen) && !strncasecmp(key, prefix, preflen)) {
71                 if (key[preflen] == '/')
72                         return 1;
73         }
74         return 0;
75 }
76
77 static inline int subkeymatch(const char *key, const char *suffix)
78 {
79         int suffixlen = strlen(suffix);
80         if (suffixlen) {
81                 const char *subkey = key + strlen(key) - suffixlen;
82                 if (subkey < key)
83                         return 0;
84                 if (!strcasecmp(subkey, suffix))
85                         return 1;
86         }
87         return 0;
88 }
89
90 int ast_db_deltree(const char *family, const char *keytree)
91 {
92         char prefix[256];
93         DBT key, data;
94         char *keys;
95         int res;
96         int pass;
97         int counter = 0;
98         
99         if (family) {
100                 if (keytree) {
101                         snprintf(prefix, sizeof(prefix), "/%s/%s", family, keytree);
102                 } else {
103                         snprintf(prefix, sizeof(prefix), "/%s", family);
104                 }
105         } else if (keytree) {
106                 return -1;
107         } else {
108                 prefix[0] = '\0';
109         }
110         
111         ast_mutex_lock(&dblock);
112         if (dbinit()) {
113                 ast_mutex_unlock(&dblock);
114                 return -1;
115         }
116         
117         memset(&key, 0, sizeof(key));
118         memset(&data, 0, sizeof(data));
119         pass = 0;
120         while (!(res = astdb->seq(astdb, &key, &data, pass++ ? R_NEXT : R_FIRST))) {
121                 if (key.size) {
122                         keys = key.data;
123                         keys[key.size - 1] = '\0';
124                 } else {
125                         keys = "<bad key>";
126                 }
127                 if (keymatch(keys, prefix)) {
128                         astdb->del(astdb, &key, 0);
129                         counter++;
130                 }
131         }
132         astdb->sync(astdb, 0);
133         ast_mutex_unlock(&dblock);
134         return counter;
135 }
136
137 int ast_db_put(const char *family, const char *keys, const char *value)
138 {
139         char fullkey[256];
140         DBT key, data;
141         int res, fullkeylen;
142
143         ast_mutex_lock(&dblock);
144         if (dbinit()) {
145                 ast_mutex_unlock(&dblock);
146                 return -1;
147         }
148
149         fullkeylen = snprintf(fullkey, sizeof(fullkey), "/%s/%s", family, keys);
150         memset(&key, 0, sizeof(key));
151         memset(&data, 0, sizeof(data));
152         key.data = fullkey;
153         key.size = fullkeylen + 1;
154         data.data = (char *) value;
155         data.size = strlen(value) + 1;
156         res = astdb->put(astdb, &key, &data, 0);
157         astdb->sync(astdb, 0);
158         ast_mutex_unlock(&dblock);
159         if (res)
160                 ast_log(LOG_WARNING, "Unable to put value '%s' for key '%s' in family '%s'\n", value, keys, family);
161         return res;
162 }
163
164 int ast_db_get(const char *family, const char *keys, char *value, int valuelen)
165 {
166         char fullkey[256] = "";
167         DBT key, data;
168         int res, fullkeylen;
169
170         ast_mutex_lock(&dblock);
171         if (dbinit()) {
172                 ast_mutex_unlock(&dblock);
173                 return -1;
174         }
175
176         fullkeylen = snprintf(fullkey, sizeof(fullkey), "/%s/%s", family, keys);
177         memset(&key, 0, sizeof(key));
178         memset(&data, 0, sizeof(data));
179         memset(value, 0, valuelen);
180         key.data = fullkey;
181         key.size = fullkeylen + 1;
182         
183         res = astdb->get(astdb, &key, &data, 0);
184         
185         ast_mutex_unlock(&dblock);
186
187         /* Be sure to NULL terminate our data either way */
188         if (res) {
189                 ast_debug(1, "Unable to find key '%s' in family '%s'\n", keys, family);
190         } else {
191 #if 0
192                 printf("Got value of size %d\n", data.size);
193 #endif
194                 if (data.size) {
195                         ((char *)data.data)[data.size - 1] = '\0';
196                         /* Make sure that we don't write too much to the dst pointer or we don't read too much from the source pointer */
197                         ast_copy_string(value, data.data, (valuelen > data.size) ? data.size : valuelen);
198                 } else {
199                         ast_log(LOG_NOTICE, "Strange, empty value for /%s/%s\n", family, keys);
200                 }
201         }
202         return res;
203 }
204
205 int ast_db_del(const char *family, const char *keys)
206 {
207         char fullkey[256];
208         DBT key;
209         int res, fullkeylen;
210
211         ast_mutex_lock(&dblock);
212         if (dbinit()) {
213                 ast_mutex_unlock(&dblock);
214                 return -1;
215         }
216         
217         fullkeylen = snprintf(fullkey, sizeof(fullkey), "/%s/%s", family, keys);
218         memset(&key, 0, sizeof(key));
219         key.data = fullkey;
220         key.size = fullkeylen + 1;
221         
222         res = astdb->del(astdb, &key, 0);
223         astdb->sync(astdb, 0);
224         
225         ast_mutex_unlock(&dblock);
226
227         if (res) {
228                 ast_debug(1, "Unable to find key '%s' in family '%s'\n", keys, family);
229         }
230         return res;
231 }
232
233 static char *handle_cli_database_put(struct ast_cli_entry *e, int cmd, struct ast_cli_args *a)
234 {
235         int res;
236
237         switch (cmd) {
238         case CLI_INIT:
239                 e->command = "database put";
240                 e->usage =
241                         "Usage: database put <family> <key> <value>\n"
242                         "       Adds or updates an entry in the Asterisk database for\n"
243                         "       a given family, key, and value.\n";
244                 return NULL;
245         case CLI_GENERATE:
246                 return NULL;
247         }
248
249         if (a->argc != 5)
250                 return CLI_SHOWUSAGE;
251         res = ast_db_put(a->argv[2], a->argv[3], a->argv[4]);
252         if (res)  {
253                 ast_cli(a->fd, "Failed to update entry\n");
254         } else {
255                 ast_cli(a->fd, "Updated database successfully\n");
256         }
257         return CLI_SUCCESS;
258 }
259
260 static char *handle_cli_database_get(struct ast_cli_entry *e, int cmd, struct ast_cli_args *a)
261 {
262         int res;
263         char tmp[256];
264
265         switch (cmd) {
266         case CLI_INIT:
267                 e->command = "database get";
268                 e->usage =
269                         "Usage: database get <family> <key>\n"
270                         "       Retrieves an entry in the Asterisk database for a given\n"
271                         "       family and key.\n";
272                 return NULL;
273         case CLI_GENERATE:
274                 return NULL;
275         }
276
277         if (a->argc != 4)
278                 return CLI_SHOWUSAGE;
279         res = ast_db_get(a->argv[2], a->argv[3], tmp, sizeof(tmp));
280         if (res) {
281                 ast_cli(a->fd, "Database entry not found.\n");
282         } else {
283                 ast_cli(a->fd, "Value: %s\n", tmp);
284         }
285         return CLI_SUCCESS;
286 }
287
288 static char *handle_cli_database_del(struct ast_cli_entry *e, int cmd, struct ast_cli_args *a)
289 {
290         int res;
291
292         switch (cmd) {
293         case CLI_INIT:
294                 e->command = "database del";
295                 e->usage =
296                         "Usage: database del <family> <key>\n"
297                         "       Deletes an entry in the Asterisk database for a given\n"
298                         "       family and key.\n";
299                 return NULL;
300         case CLI_GENERATE:
301                 return NULL;
302         }
303
304         if (a->argc != 4)
305                 return CLI_SHOWUSAGE;
306         res = ast_db_del(a->argv[2], a->argv[3]);
307         if (res) {
308                 ast_cli(a->fd, "Database entry does not exist.\n");
309         } else {
310                 ast_cli(a->fd, "Database entry removed.\n");
311         }
312         return CLI_SUCCESS;
313 }
314
315 static char *handle_cli_database_deltree(struct ast_cli_entry *e, int cmd, struct ast_cli_args *a)
316 {
317         int res;
318
319         switch (cmd) {
320         case CLI_INIT:
321                 e->command = "database deltree";
322                 e->usage =
323                         "Usage: database deltree <family> [keytree]\n"
324                         "       Deletes a family or specific keytree within a family\n"
325                         "       in the Asterisk database.\n";
326                 return NULL;
327         case CLI_GENERATE:
328                 return NULL;
329         }
330
331         if ((a->argc < 3) || (a->argc > 4))
332                 return CLI_SHOWUSAGE;
333         if (a->argc == 4) {
334                 res = ast_db_deltree(a->argv[2], a->argv[3]);
335         } else {
336                 res = ast_db_deltree(a->argv[2], NULL);
337         }
338         if (res < 0) {
339                 ast_cli(a->fd, "Database entries do not exist.\n");
340         } else {
341                 ast_cli(a->fd, "%d database entries removed.\n",res);
342         }
343         return CLI_SUCCESS;
344 }
345
346 static char *handle_cli_database_show(struct ast_cli_entry *e, int cmd, struct ast_cli_args *a)
347 {
348         char prefix[256];
349         DBT key, data;
350         char *keys, *values;
351         int res;
352         int pass;
353         int counter = 0;
354
355         switch (cmd) {
356         case CLI_INIT:
357                 e->command = "database show";
358                 e->usage =
359                         "Usage: database show [family [keytree]]\n"
360                         "       Shows Asterisk database contents, optionally restricted\n"
361                         "       to a given family, or family and keytree.\n";
362                 return NULL;
363         case CLI_GENERATE:
364                 return NULL;
365         }
366
367         if (a->argc == 4) {
368                 /* Family and key tree */
369                 snprintf(prefix, sizeof(prefix), "/%s/%s", a->argv[2], a->argv[3]);
370         } else if (a->argc == 3) {
371                 /* Family only */
372                 snprintf(prefix, sizeof(prefix), "/%s", a->argv[2]);
373         } else if (a->argc == 2) {
374                 /* Neither */
375                 prefix[0] = '\0';
376         } else {
377                 return CLI_SHOWUSAGE;
378         }
379         ast_mutex_lock(&dblock);
380         if (dbinit()) {
381                 ast_mutex_unlock(&dblock);
382                 ast_cli(a->fd, "Database unavailable\n");
383                 return CLI_SUCCESS;     
384         }
385         memset(&key, 0, sizeof(key));
386         memset(&data, 0, sizeof(data));
387         pass = 0;
388         while (!(res = astdb->seq(astdb, &key, &data, pass++ ? R_NEXT : R_FIRST))) {
389                 if (key.size) {
390                         keys = key.data;
391                         keys[key.size - 1] = '\0';
392                 } else {
393                         keys = "<bad key>";
394                 }
395                 if (data.size) {
396                         values = data.data;
397                         values[data.size - 1]='\0';
398                 } else {
399                         values = "<bad value>";
400                 }
401                 if (keymatch(keys, prefix)) {
402                         ast_cli(a->fd, "%-50s: %-25s\n", keys, values);
403                         counter++;
404                 }
405         }
406         ast_mutex_unlock(&dblock);
407         ast_cli(a->fd, "%d results found.\n", counter);
408         return CLI_SUCCESS;     
409 }
410
411 static char *handle_cli_database_showkey(struct ast_cli_entry *e, int cmd, struct ast_cli_args *a)
412 {
413         char suffix[256];
414         DBT key, data;
415         char *keys, *values;
416         int res;
417         int pass;
418         int counter = 0;
419
420         switch (cmd) {
421         case CLI_INIT:
422                 e->command = "database showkey";
423                 e->usage =
424                         "Usage: database showkey <keytree>\n"
425                         "       Shows Asterisk database contents, restricted to a given key.\n";
426                 return NULL;
427         case CLI_GENERATE:
428                 return NULL;
429         }
430
431         if (a->argc == 3) {
432                 /* Key only */
433                 snprintf(suffix, sizeof(suffix), "/%s", a->argv[2]);
434         } else {
435                 return CLI_SHOWUSAGE;
436         }
437         ast_mutex_lock(&dblock);
438         if (dbinit()) {
439                 ast_mutex_unlock(&dblock);
440                 ast_cli(a->fd, "Database unavailable\n");
441                 return CLI_SUCCESS;     
442         }
443         memset(&key, 0, sizeof(key));
444         memset(&data, 0, sizeof(data));
445         pass = 0;
446         while (!(res = astdb->seq(astdb, &key, &data, pass++ ? R_NEXT : R_FIRST))) {
447                 if (key.size) {
448                         keys = key.data;
449                         keys[key.size - 1] = '\0';
450                 } else {
451                         keys = "<bad key>";
452                 }
453                 if (data.size) {
454                         values = data.data;
455                         values[data.size - 1]='\0';
456                 } else {
457                         values = "<bad value>";
458                 }
459                 if (subkeymatch(keys, suffix)) {
460                         ast_cli(a->fd, "%-50s: %-25s\n", keys, values);
461                         counter++;
462                 }
463         }
464         ast_mutex_unlock(&dblock);
465         ast_cli(a->fd, "%d results found.\n", counter);
466         return CLI_SUCCESS;     
467 }
468
469 struct ast_db_entry *ast_db_gettree(const char *family, const char *keytree)
470 {
471         char prefix[256];
472         DBT key, data;
473         char *keys, *values;
474         int values_len;
475         int res;
476         int pass;
477         struct ast_db_entry *last = NULL;
478         struct ast_db_entry *cur, *ret=NULL;
479
480         if (!ast_strlen_zero(family)) {
481                 if (!ast_strlen_zero(keytree)) {
482                         /* Family and key tree */
483                         snprintf(prefix, sizeof(prefix), "/%s/%s", family, prefix);
484                 } else {
485                         /* Family only */
486                         snprintf(prefix, sizeof(prefix), "/%s", family);
487                 }
488         } else {
489                 prefix[0] = '\0';
490         }
491         ast_mutex_lock(&dblock);
492         if (dbinit()) {
493                 ast_mutex_unlock(&dblock);
494                 ast_log(LOG_WARNING, "Database unavailable\n");
495                 return NULL;    
496         }
497         memset(&key, 0, sizeof(key));
498         memset(&data, 0, sizeof(data));
499         pass = 0;
500         while (!(res = astdb->seq(astdb, &key, &data, pass++ ? R_NEXT : R_FIRST))) {
501                 if (key.size) {
502                         keys = key.data;
503                         keys[key.size - 1] = '\0';
504                 } else {
505                         keys = "<bad key>";
506                 }
507                 if (data.size) {
508                         values = data.data;
509                         values[data.size - 1] = '\0';
510                 } else {
511                         values = "<bad value>";
512                 }
513                 values_len = strlen(values) + 1;
514                 if (keymatch(keys, prefix) && (cur = ast_malloc(sizeof(*cur) + strlen(keys) + 1 + values_len))) {
515                         cur->next = NULL;
516                         cur->key = cur->data + values_len;
517                         strcpy(cur->data, values);
518                         strcpy(cur->key, keys);
519                         if (last) {
520                                 last->next = cur;
521                         } else {
522                                 ret = cur;
523                         }
524                         last = cur;
525                 }
526         }
527         ast_mutex_unlock(&dblock);
528         return ret;     
529 }
530
531 void ast_db_freetree(struct ast_db_entry *dbe)
532 {
533         struct ast_db_entry *last;
534         while (dbe) {
535                 last = dbe;
536                 dbe = dbe->next;
537                 ast_free(last);
538         }
539 }
540
541 struct ast_cli_entry cli_database[] = {
542         AST_CLI_DEFINE(handle_cli_database_show,    "Shows database contents"),
543         AST_CLI_DEFINE(handle_cli_database_showkey, "Shows database contents"),
544         AST_CLI_DEFINE(handle_cli_database_get,     "Gets database value"),
545         AST_CLI_DEFINE(handle_cli_database_put,     "Adds/updates database value"),
546         AST_CLI_DEFINE(handle_cli_database_del,     "Removes database key/value"),
547         AST_CLI_DEFINE(handle_cli_database_deltree, "Removes database keytree/values")
548 };
549
550 static int manager_dbput(struct mansession *s, const struct message *m)
551 {
552         const char *family = astman_get_header(m, "Family");
553         const char *key = astman_get_header(m, "Key");
554         const char *val = astman_get_header(m, "Val");
555         int res;
556
557         if (ast_strlen_zero(family)) {
558                 astman_send_error(s, m, "No family specified");
559                 return 0;
560         }
561         if (ast_strlen_zero(key)) {
562                 astman_send_error(s, m, "No key specified");
563                 return 0;
564         }
565
566         res = ast_db_put(family, key, S_OR(val, ""));
567         if (res) {
568                 astman_send_error(s, m, "Failed to update entry");
569         } else {
570                 astman_send_ack(s, m, "Updated database successfully");
571         }
572         return 0;
573 }
574
575 static int manager_dbget(struct mansession *s, const struct message *m)
576 {
577         const char *id = astman_get_header(m,"ActionID");
578         char idText[256] = "";
579         const char *family = astman_get_header(m, "Family");
580         const char *key = astman_get_header(m, "Key");
581         char tmp[256];
582         int res;
583
584         if (ast_strlen_zero(family)) {
585                 astman_send_error(s, m, "No family specified.");
586                 return 0;
587         }
588         if (ast_strlen_zero(key)) {
589                 astman_send_error(s, m, "No key specified.");
590                 return 0;
591         }
592
593         if (!ast_strlen_zero(id))
594                 snprintf(idText, sizeof(idText) ,"ActionID: %s\r\n", id);
595
596         res = ast_db_get(family, key, tmp, sizeof(tmp));
597         if (res) {
598                 astman_send_error(s, m, "Database entry not found");
599         } else {
600                 astman_send_ack(s, m, "Result will follow");
601                 astman_append(s, "Event: DBGetResponse\r\n"
602                                 "Family: %s\r\n"
603                                 "Key: %s\r\n"
604                                 "Val: %s\r\n"
605                                 "%s"
606                                 "\r\n",
607                                 family, key, tmp, idText);
608         }
609         return 0;
610 }
611
612 static int manager_dbdel(struct mansession *s, const struct message *m)
613 {
614         const char *family = astman_get_header(m, "Family");
615         const char *key = astman_get_header(m, "Key");
616         int res;
617
618         if (ast_strlen_zero(family)) {
619                 astman_send_error(s, m, "No family specified.");
620                 return 0;
621         }
622
623         if (ast_strlen_zero(key)) {
624                 astman_send_error(s, m, "No key specified.");
625                 return 0;
626         }
627
628         res = ast_db_del(family, key);
629         if (res)
630                 astman_send_error(s, m, "Database entry not found");
631         else
632                 astman_send_ack(s, m, "Key deleted successfully");
633
634         return 0;
635 }
636
637 static int manager_dbdeltree(struct mansession *s, const struct message *m)
638 {
639         const char *family = astman_get_header(m, "Family");
640         const char *key = astman_get_header(m, "Key");
641         int res;
642
643         if (ast_strlen_zero(family)) {
644                 astman_send_error(s, m, "No family specified.");
645                 return 0;
646         }
647
648         if (!ast_strlen_zero(key))
649                 res = ast_db_deltree(family, key);
650         else
651                 res = ast_db_deltree(family, NULL);
652
653         if (res < 0)
654                 astman_send_error(s, m, "Database entry not found");
655         else
656                 astman_send_ack(s, m, "Key tree deleted successfully");
657         
658         return 0;
659 }
660
661 int astdb_init(void)
662 {
663         dbinit();
664         ast_cli_register_multiple(cli_database, sizeof(cli_database) / sizeof(struct ast_cli_entry));
665         ast_manager_register("DBGet", EVENT_FLAG_SYSTEM, manager_dbget, "Get DB Entry");
666         ast_manager_register("DBPut", EVENT_FLAG_SYSTEM, manager_dbput, "Put DB Entry");
667         ast_manager_register("DBDel", EVENT_FLAG_SYSTEM, manager_dbdel, "Delete DB Entry");
668         ast_manager_register("DBDelTree", EVENT_FLAG_SYSTEM, manager_dbdeltree, "Delete DB Tree");
669         return 0;
670 }