2 * Asterisk -- An open source telephony toolkit.
4 * Copyright (C) 1999 - 2005, Digium, Inc.
6 * Mark Spencer <markster@digium.com>
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.
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.
21 * \brief ASTdb Management
23 * \author Mark Spencer <markster@digium.com>
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
32 ASTERISK_FILE_VERSION(__FILE__
, "$Revision$")
34 #include "asterisk/_private.h"
35 #include "asterisk/paths.h" /* use ast_config_AST_DB */
40 #include "asterisk/channel.h"
41 #include "asterisk/file.h"
42 #include "asterisk/app.h"
43 #include "asterisk/dsp.h"
44 #include "asterisk/astdb.h"
45 #include "asterisk/cli.h"
46 #include "asterisk/utils.h"
47 #include "asterisk/lock.h"
48 #include "asterisk/manager.h"
49 #include "db1-ast/include/db.h"
52 AST_MUTEX_DEFINE_STATIC(dblock
);
54 static int dbinit(void)
56 if (!astdb
&& !(astdb
= dbopen(ast_config_AST_DB
, O_CREAT
| O_RDWR
, AST_FILE_MODE
, DB_BTREE
, NULL
))) {
57 ast_log(LOG_WARNING
, "Unable to open Asterisk database '%s': %s\n", ast_config_AST_DB
, strerror(errno
));
64 static inline int keymatch(const char *key
, const char *prefix
)
66 int preflen
= strlen(prefix
);
69 if (!strcasecmp(key
, prefix
))
71 if ((strlen(key
) > preflen
) && !strncasecmp(key
, prefix
, preflen
)) {
72 if (key
[preflen
] == '/')
78 static inline int subkeymatch(const char *key
, const char *suffix
)
80 int suffixlen
= strlen(suffix
);
82 const char *subkey
= key
+ strlen(key
) - suffixlen
;
85 if (!strcasecmp(subkey
, suffix
))
91 int ast_db_deltree(const char *family
, const char *keytree
)
102 snprintf(prefix
, sizeof(prefix
), "/%s/%s", family
, keytree
);
104 snprintf(prefix
, sizeof(prefix
), "/%s", family
);
106 } else if (keytree
) {
112 ast_mutex_lock(&dblock
);
114 ast_mutex_unlock(&dblock
);
118 memset(&key
, 0, sizeof(key
));
119 memset(&data
, 0, sizeof(data
));
121 while (!(res
= astdb
->seq(astdb
, &key
, &data
, pass
++ ? R_NEXT
: R_FIRST
))) {
124 keys
[key
.size
- 1] = '\0';
128 if (keymatch(keys
, prefix
)) {
129 astdb
->del(astdb
, &key
, 0);
133 astdb
->sync(astdb
, 0);
134 ast_mutex_unlock(&dblock
);
138 int ast_db_put(const char *family
, const char *keys
, const char *value
)
144 ast_mutex_lock(&dblock
);
146 ast_mutex_unlock(&dblock
);
150 fullkeylen
= snprintf(fullkey
, sizeof(fullkey
), "/%s/%s", family
, keys
);
151 memset(&key
, 0, sizeof(key
));
152 memset(&data
, 0, sizeof(data
));
154 key
.size
= fullkeylen
+ 1;
155 data
.data
= (char *) value
;
156 data
.size
= strlen(value
) + 1;
157 res
= astdb
->put(astdb
, &key
, &data
, 0);
158 astdb
->sync(astdb
, 0);
159 ast_mutex_unlock(&dblock
);
161 ast_log(LOG_WARNING
, "Unable to put value '%s' for key '%s' in family '%s'\n", value
, keys
, family
);
165 int ast_db_get(const char *family
, const char *keys
, char *value
, int valuelen
)
167 char fullkey
[256] = "";
171 ast_mutex_lock(&dblock
);
173 ast_mutex_unlock(&dblock
);
177 fullkeylen
= snprintf(fullkey
, sizeof(fullkey
), "/%s/%s", family
, keys
);
178 memset(&key
, 0, sizeof(key
));
179 memset(&data
, 0, sizeof(data
));
180 memset(value
, 0, valuelen
);
182 key
.size
= fullkeylen
+ 1;
184 res
= astdb
->get(astdb
, &key
, &data
, 0);
186 ast_mutex_unlock(&dblock
);
188 /* Be sure to NULL terminate our data either way */
190 ast_debug(1, "Unable to find key '%s' in family '%s'\n", keys
, family
);
193 printf("Got value of size %d\n", data
.size
);
196 ((char *)data
.data
)[data
.size
- 1] = '\0';
197 /* Make sure that we don't write too much to the dst pointer or we don't read too much from the source pointer */
198 ast_copy_string(value
, data
.data
, (valuelen
> data
.size
) ? data
.size
: valuelen
);
200 ast_log(LOG_NOTICE
, "Strange, empty value for /%s/%s\n", family
, keys
);
206 int ast_db_del(const char *family
, const char *keys
)
212 ast_mutex_lock(&dblock
);
214 ast_mutex_unlock(&dblock
);
218 fullkeylen
= snprintf(fullkey
, sizeof(fullkey
), "/%s/%s", family
, keys
);
219 memset(&key
, 0, sizeof(key
));
221 key
.size
= fullkeylen
+ 1;
223 res
= astdb
->del(astdb
, &key
, 0);
224 astdb
->sync(astdb
, 0);
226 ast_mutex_unlock(&dblock
);
229 ast_debug(1, "Unable to find key '%s' in family '%s'\n", keys
, family
);
234 static char *handle_cli_database_put(struct ast_cli_entry
*e
, int cmd
, struct ast_cli_args
*a
)
240 e
->command
= "database put";
242 "Usage: database put <family> <key> <value>\n"
243 " Adds or updates an entry in the Asterisk database for\n"
244 " a given family, key, and value.\n";
251 return CLI_SHOWUSAGE
;
252 res
= ast_db_put(a
->argv
[2], a
->argv
[3], a
->argv
[4]);
254 ast_cli(a
->fd
, "Failed to update entry\n");
256 ast_cli(a
->fd
, "Updated database successfully\n");
261 static char *handle_cli_database_get(struct ast_cli_entry
*e
, int cmd
, struct ast_cli_args
*a
)
268 e
->command
= "database get";
270 "Usage: database get <family> <key>\n"
271 " Retrieves an entry in the Asterisk database for a given\n"
272 " family and key.\n";
279 return CLI_SHOWUSAGE
;
280 res
= ast_db_get(a
->argv
[2], a
->argv
[3], tmp
, sizeof(tmp
));
282 ast_cli(a
->fd
, "Database entry not found.\n");
284 ast_cli(a
->fd
, "Value: %s\n", tmp
);
289 static char *handle_cli_database_del(struct ast_cli_entry
*e
, int cmd
, struct ast_cli_args
*a
)
295 e
->command
= "database del";
297 "Usage: database del <family> <key>\n"
298 " Deletes an entry in the Asterisk database for a given\n"
299 " family and key.\n";
306 return CLI_SHOWUSAGE
;
307 res
= ast_db_del(a
->argv
[2], a
->argv
[3]);
309 ast_cli(a
->fd
, "Database entry does not exist.\n");
311 ast_cli(a
->fd
, "Database entry removed.\n");
316 static char *handle_cli_database_deltree(struct ast_cli_entry
*e
, int cmd
, struct ast_cli_args
*a
)
322 e
->command
= "database deltree";
324 "Usage: database deltree <family> [keytree]\n"
325 " Deletes a family or specific keytree within a family\n"
326 " in the Asterisk database.\n";
332 if ((a
->argc
< 3) || (a
->argc
> 4))
333 return CLI_SHOWUSAGE
;
335 res
= ast_db_deltree(a
->argv
[2], a
->argv
[3]);
337 res
= ast_db_deltree(a
->argv
[2], NULL
);
340 ast_cli(a
->fd
, "Database entries do not exist.\n");
342 ast_cli(a
->fd
, "%d database entries removed.\n",res
);
347 static char *handle_cli_database_show(struct ast_cli_entry
*e
, int cmd
, struct ast_cli_args
*a
)
358 e
->command
= "database show";
360 "Usage: database show [family [keytree]]\n"
361 " Shows Asterisk database contents, optionally restricted\n"
362 " to a given family, or family and keytree.\n";
369 /* Family and key tree */
370 snprintf(prefix
, sizeof(prefix
), "/%s/%s", a
->argv
[2], a
->argv
[3]);
371 } else if (a
->argc
== 3) {
373 snprintf(prefix
, sizeof(prefix
), "/%s", a
->argv
[2]);
374 } else if (a
->argc
== 2) {
378 return CLI_SHOWUSAGE
;
380 ast_mutex_lock(&dblock
);
382 ast_mutex_unlock(&dblock
);
383 ast_cli(a
->fd
, "Database unavailable\n");
386 memset(&key
, 0, sizeof(key
));
387 memset(&data
, 0, sizeof(data
));
389 while (!(res
= astdb
->seq(astdb
, &key
, &data
, pass
++ ? R_NEXT
: R_FIRST
))) {
392 keys
[key
.size
- 1] = '\0';
398 values
[data
.size
- 1]='\0';
400 values
= "<bad value>";
402 if (keymatch(keys
, prefix
)) {
403 ast_cli(a
->fd
, "%-50s: %-25s\n", keys
, values
);
407 ast_mutex_unlock(&dblock
);
408 ast_cli(a
->fd
, "%d results found.\n", counter
);
412 static char *handle_cli_database_showkey(struct ast_cli_entry
*e
, int cmd
, struct ast_cli_args
*a
)
423 e
->command
= "database showkey";
425 "Usage: database showkey <keytree>\n"
426 " Shows Asterisk database contents, restricted to a given key.\n";
434 snprintf(suffix
, sizeof(suffix
), "/%s", a
->argv
[2]);
436 return CLI_SHOWUSAGE
;
438 ast_mutex_lock(&dblock
);
440 ast_mutex_unlock(&dblock
);
441 ast_cli(a
->fd
, "Database unavailable\n");
444 memset(&key
, 0, sizeof(key
));
445 memset(&data
, 0, sizeof(data
));
447 while (!(res
= astdb
->seq(astdb
, &key
, &data
, pass
++ ? R_NEXT
: R_FIRST
))) {
450 keys
[key
.size
- 1] = '\0';
456 values
[data
.size
- 1]='\0';
458 values
= "<bad value>";
460 if (subkeymatch(keys
, suffix
)) {
461 ast_cli(a
->fd
, "%-50s: %-25s\n", keys
, values
);
465 ast_mutex_unlock(&dblock
);
466 ast_cli(a
->fd
, "%d results found.\n", counter
);
470 struct ast_db_entry
*ast_db_gettree(const char *family
, const char *keytree
)
478 struct ast_db_entry
*last
= NULL
;
479 struct ast_db_entry
*cur
, *ret
=NULL
;
481 if (!ast_strlen_zero(family
)) {
482 if (!ast_strlen_zero(keytree
)) {
483 /* Family and key tree */
484 snprintf(prefix
, sizeof(prefix
), "/%s/%s", family
, prefix
);
487 snprintf(prefix
, sizeof(prefix
), "/%s", family
);
492 ast_mutex_lock(&dblock
);
494 ast_mutex_unlock(&dblock
);
495 ast_log(LOG_WARNING
, "Database unavailable\n");
498 memset(&key
, 0, sizeof(key
));
499 memset(&data
, 0, sizeof(data
));
501 while (!(res
= astdb
->seq(astdb
, &key
, &data
, pass
++ ? R_NEXT
: R_FIRST
))) {
504 keys
[key
.size
- 1] = '\0';
510 values
[data
.size
- 1] = '\0';
512 values
= "<bad value>";
514 values_len
= strlen(values
) + 1;
515 if (keymatch(keys
, prefix
) && (cur
= ast_malloc(sizeof(*cur
) + strlen(keys
) + 1 + values_len
))) {
517 cur
->key
= cur
->data
+ values_len
;
518 strcpy(cur
->data
, values
);
519 strcpy(cur
->key
, keys
);
528 ast_mutex_unlock(&dblock
);
532 void ast_db_freetree(struct ast_db_entry
*dbe
)
534 struct ast_db_entry
*last
;
542 struct ast_cli_entry cli_database
[] = {
543 AST_CLI_DEFINE(handle_cli_database_show
, "Shows database contents"),
544 AST_CLI_DEFINE(handle_cli_database_showkey
, "Shows database contents"),
545 AST_CLI_DEFINE(handle_cli_database_get
, "Gets database value"),
546 AST_CLI_DEFINE(handle_cli_database_put
, "Adds/updates database value"),
547 AST_CLI_DEFINE(handle_cli_database_del
, "Removes database key/value"),
548 AST_CLI_DEFINE(handle_cli_database_deltree
, "Removes database keytree/values")
551 static int manager_dbput(struct mansession
*s
, const struct message
*m
)
553 const char *family
= astman_get_header(m
, "Family");
554 const char *key
= astman_get_header(m
, "Key");
555 const char *val
= astman_get_header(m
, "Val");
558 if (ast_strlen_zero(family
)) {
559 astman_send_error(s
, m
, "No family specified");
562 if (ast_strlen_zero(key
)) {
563 astman_send_error(s
, m
, "No key specified");
567 res
= ast_db_put(family
, key
, S_OR(val
, ""));
569 astman_send_error(s
, m
, "Failed to update entry");
571 astman_send_ack(s
, m
, "Updated database successfully");
576 static int manager_dbget(struct mansession
*s
, const struct message
*m
)
578 const char *id
= astman_get_header(m
,"ActionID");
579 char idText
[256] = "";
580 const char *family
= astman_get_header(m
, "Family");
581 const char *key
= astman_get_header(m
, "Key");
585 if (ast_strlen_zero(family
)) {
586 astman_send_error(s
, m
, "No family specified.");
589 if (ast_strlen_zero(key
)) {
590 astman_send_error(s
, m
, "No key specified.");
594 if (!ast_strlen_zero(id
))
595 snprintf(idText
, sizeof(idText
) ,"ActionID: %s\r\n", id
);
597 res
= ast_db_get(family
, key
, tmp
, sizeof(tmp
));
599 astman_send_error(s
, m
, "Database entry not found");
601 astman_send_ack(s
, m
, "Result will follow");
602 astman_append(s
, "Event: DBGetResponse\r\n"
608 family
, key
, tmp
, idText
);
613 static int manager_dbdel(struct mansession
*s
, const struct message
*m
)
615 const char *family
= astman_get_header(m
, "Family");
616 const char *key
= astman_get_header(m
, "Key");
619 if (ast_strlen_zero(family
)) {
620 astman_send_error(s
, m
, "No family specified.");
624 if (ast_strlen_zero(key
)) {
625 astman_send_error(s
, m
, "No key specified.");
629 res
= ast_db_del(family
, key
);
631 astman_send_error(s
, m
, "Database entry not found");
633 astman_send_ack(s
, m
, "Key deleted successfully");
638 static int manager_dbdeltree(struct mansession
*s
, const struct message
*m
)
640 const char *family
= astman_get_header(m
, "Family");
641 const char *key
= astman_get_header(m
, "Key");
644 if (ast_strlen_zero(family
)) {
645 astman_send_error(s
, m
, "No family specified.");
649 if (!ast_strlen_zero(key
))
650 res
= ast_db_deltree(family
, key
);
652 res
= ast_db_deltree(family
, NULL
);
655 astman_send_error(s
, m
, "Database entry not found");
657 astman_send_ack(s
, m
, "Key tree deleted successfully");
665 ast_cli_register_multiple(cli_database
, sizeof(cli_database
) / sizeof(struct ast_cli_entry
));
666 ast_manager_register("DBGet", EVENT_FLAG_SYSTEM
| EVENT_FLAG_REPORTING
, manager_dbget
, "Get DB Entry");
667 ast_manager_register("DBPut", EVENT_FLAG_SYSTEM
, manager_dbput
, "Put DB Entry");
668 ast_manager_register("DBDel", EVENT_FLAG_SYSTEM
, manager_dbdel
, "Delete DB Entry");
669 ast_manager_register("DBDelTree", EVENT_FLAG_SYSTEM
, manager_dbdeltree
, "Delete DB Tree");