00001
00002
00003
00004
00005
00006
00007
00008
00009
00010
00011
00012
00013
00014
00015
00016
00017
00018
00019
00020
00021
00022
00023
00024
00025
00026
00027
00028
00029
00030
00031
00032
00033
00034 #include "asterisk.h"
00035
00036 ASTERISK_FILE_VERSION(__FILE__, "$Revision: 377688 $")
00037
00038 #include "asterisk/_private.h"
00039 #include "asterisk/paths.h"
00040 #include <sys/time.h>
00041 #include <signal.h>
00042 #include <dirent.h>
00043
00044 #include "asterisk/channel.h"
00045 #include "asterisk/file.h"
00046 #include "asterisk/app.h"
00047 #include "asterisk/dsp.h"
00048 #include "asterisk/astdb.h"
00049 #include "asterisk/cli.h"
00050 #include "asterisk/utils.h"
00051 #include "asterisk/lock.h"
00052 #include "asterisk/manager.h"
00053 #include "db1-ast/include/db.h"
00054
00055
00056
00057
00058
00059
00060
00061
00062
00063
00064
00065
00066
00067
00068
00069
00070
00071
00072
00073
00074
00075
00076
00077
00078
00079
00080
00081
00082
00083
00084
00085
00086
00087
00088
00089
00090
00091
00092
00093
00094
00095
00096
00097
00098
00099
00100
00101
00102
00103
00104
00105
00106
00107 #define MAX_DB_FIELD 256
00108
00109 static DB *astdb;
00110 AST_MUTEX_DEFINE_STATIC(dblock);
00111 static ast_cond_t dbcond;
00112 static pthread_t syncthread;
00113 static int doexit;
00114 typedef int (*process_keys_cb)(DBT *key, DBT *value, const char *filter, void *data);
00115
00116 static void db_sync(void);
00117
00118 static int dbinit(void)
00119 {
00120 if (doexit) {
00121 return -1;
00122 }
00123 if (!astdb && !(astdb = dbopen(ast_config_AST_DB, O_CREAT | O_RDWR, AST_FILE_MODE, DB_BTREE, NULL))) {
00124 ast_log(LOG_WARNING, "Unable to open Asterisk database '%s': %s\n", ast_config_AST_DB, strerror(errno));
00125 return -1;
00126 }
00127 return 0;
00128 }
00129
00130 static inline int keymatch(const char *key, const char *prefix)
00131 {
00132 int preflen = strlen(prefix);
00133 if (!preflen)
00134 return 1;
00135 if (!strcasecmp(key, prefix))
00136 return 1;
00137 if ((strlen(key) > preflen) && !strncasecmp(key, prefix, preflen)) {
00138 if (key[preflen] == '/')
00139 return 1;
00140 }
00141 return 0;
00142 }
00143
00144 static inline int subkeymatch(const char *key, const char *suffix)
00145 {
00146 int suffixlen = strlen(suffix);
00147 if (suffixlen) {
00148 const char *subkey = key + strlen(key) - suffixlen;
00149 if (subkey < key)
00150 return 0;
00151 if (!strcasecmp(subkey, suffix))
00152 return 1;
00153 }
00154 return 0;
00155 }
00156
00157 static const char *dbt_data2str(DBT *dbt)
00158 {
00159 char *data = "";
00160
00161 if (dbt->size) {
00162 data = dbt->data;
00163 data[dbt->size - 1] = '\0';
00164 }
00165
00166 return data;
00167 }
00168
00169 static inline const char *dbt_data2str_full(DBT *dbt, const char *def)
00170 {
00171 return S_OR(dbt_data2str(dbt), def);
00172 }
00173
00174
00175
00176
00177
00178
00179
00180
00181
00182
00183
00184 static int process_db_keys(process_keys_cb cb, void *data, const char *filter, int sync)
00185 {
00186 DBT key = { 0, }, value = { 0, }, last_key = { 0, };
00187 int counter = 0;
00188 int res, last = 0;
00189 char last_key_s[MAX_DB_FIELD];
00190
00191 ast_mutex_lock(&dblock);
00192 if (dbinit()) {
00193 ast_mutex_unlock(&dblock);
00194 return -1;
00195 }
00196
00197
00198
00199
00200
00201
00202 if (astdb->seq(astdb, &last_key, &value, R_LAST)) {
00203
00204 ast_mutex_unlock(&dblock);
00205 return 0;
00206 }
00207
00208 memcpy(last_key_s, last_key.data, MIN(last_key.size - 1, sizeof(last_key_s)));
00209 last_key_s[last_key.size - 1] = '\0';
00210 for (res = astdb->seq(astdb, &key, &value, R_FIRST);
00211 !res;
00212 res = astdb->seq(astdb, &key, &value, R_NEXT)) {
00213
00214 last = !strcmp(dbt_data2str_full(&key, "<bad key>"), last_key_s);
00215 counter += cb(&key, &value, filter, data);
00216 if (last) {
00217 break;
00218 }
00219 }
00220
00221 if (sync) {
00222 db_sync();
00223 }
00224
00225 ast_mutex_unlock(&dblock);
00226
00227 return counter;
00228 }
00229
00230 static int db_deltree_cb(DBT *key, DBT *value, const char *filter, void *data)
00231 {
00232 int res = 0;
00233
00234 if (keymatch(dbt_data2str_full(key, "<bad key>"), filter)) {
00235 astdb->del(astdb, key, 0);
00236 res = 1;
00237 }
00238 return res;
00239 }
00240
00241 int ast_db_deltree(const char *family, const char *keytree)
00242 {
00243 char prefix[MAX_DB_FIELD];
00244
00245 if (family) {
00246 if (keytree) {
00247 snprintf(prefix, sizeof(prefix), "/%s/%s", family, keytree);
00248 } else {
00249 snprintf(prefix, sizeof(prefix), "/%s", family);
00250 }
00251 } else if (keytree) {
00252 return -1;
00253 } else {
00254 prefix[0] = '\0';
00255 }
00256
00257 return process_db_keys(db_deltree_cb, NULL, prefix, 1);
00258 }
00259
00260 int ast_db_put(const char *family, const char *keys, const char *value)
00261 {
00262 char fullkey[MAX_DB_FIELD];
00263 DBT key, data;
00264 int res, fullkeylen;
00265
00266 ast_mutex_lock(&dblock);
00267 if (dbinit()) {
00268 ast_mutex_unlock(&dblock);
00269 return -1;
00270 }
00271
00272 fullkeylen = snprintf(fullkey, sizeof(fullkey), "/%s/%s", family, keys);
00273 memset(&key, 0, sizeof(key));
00274 memset(&data, 0, sizeof(data));
00275 key.data = fullkey;
00276 key.size = fullkeylen + 1;
00277 data.data = (char *) value;
00278 data.size = strlen(value) + 1;
00279 res = astdb->put(astdb, &key, &data, 0);
00280 db_sync();
00281 ast_mutex_unlock(&dblock);
00282 if (res)
00283 ast_log(LOG_WARNING, "Unable to put value '%s' for key '%s' in family '%s'\n", value, keys, family);
00284
00285 return res;
00286 }
00287
00288
00289
00290
00291
00292
00293
00294
00295
00296
00297
00298
00299
00300
00301
00302 static int db_get_common(const char *family, const char *keys, char **buffer, int bufferlen)
00303 {
00304 char fullkey[MAX_DB_FIELD] = "";
00305 DBT key, data;
00306 int res, fullkeylen;
00307
00308 ast_mutex_lock(&dblock);
00309 if (dbinit()) {
00310 ast_mutex_unlock(&dblock);
00311 return -1;
00312 }
00313
00314 fullkeylen = snprintf(fullkey, sizeof(fullkey), "/%s/%s", family, keys);
00315 memset(&key, 0, sizeof(key));
00316 memset(&data, 0, sizeof(data));
00317 key.data = fullkey;
00318 key.size = fullkeylen + 1;
00319
00320 res = astdb->get(astdb, &key, &data, 0);
00321
00322
00323 if (res) {
00324 ast_debug(1, "Unable to find key '%s' in family '%s'\n", keys, family);
00325 } else {
00326 if (data.size) {
00327 ((char *)data.data)[data.size - 1] = '\0';
00328
00329 if (bufferlen == -1) {
00330 *buffer = ast_strdup(data.data);
00331 } else {
00332
00333
00334 ast_copy_string(*buffer, data.data, bufferlen > data.size ? data.size : bufferlen);
00335 }
00336 } else {
00337 ast_log(LOG_NOTICE, "Strange, empty value for /%s/%s\n", family, keys);
00338 }
00339 }
00340
00341
00342
00343 ast_mutex_unlock(&dblock);
00344
00345 return res;
00346 }
00347
00348 int ast_db_get(const char *family, const char *keys, char *value, int valuelen)
00349 {
00350 ast_assert(value != NULL);
00351
00352
00353 value[0] = 0;
00354
00355 return db_get_common(family, keys, &value, valuelen);
00356 }
00357
00358 int ast_db_get_allocated(const char *family, const char *keys, char **out)
00359 {
00360 *out = NULL;
00361
00362 return db_get_common(family, keys, out, -1);
00363 }
00364
00365 int ast_db_del(const char *family, const char *keys)
00366 {
00367 char fullkey[MAX_DB_FIELD];
00368 DBT key;
00369 int res, fullkeylen;
00370
00371 ast_mutex_lock(&dblock);
00372 if (dbinit()) {
00373 ast_mutex_unlock(&dblock);
00374 return -1;
00375 }
00376
00377 fullkeylen = snprintf(fullkey, sizeof(fullkey), "/%s/%s", family, keys);
00378 memset(&key, 0, sizeof(key));
00379 key.data = fullkey;
00380 key.size = fullkeylen + 1;
00381
00382 res = astdb->del(astdb, &key, 0);
00383 db_sync();
00384
00385 ast_mutex_unlock(&dblock);
00386
00387 if (res) {
00388 ast_debug(1, "Unable to find key '%s' in family '%s'\n", keys, family);
00389 }
00390 return res;
00391 }
00392
00393 static char *handle_cli_database_put(struct ast_cli_entry *e, int cmd, struct ast_cli_args *a)
00394 {
00395 int res;
00396
00397 switch (cmd) {
00398 case CLI_INIT:
00399 e->command = "database put";
00400 e->usage =
00401 "Usage: database put <family> <key> <value>\n"
00402 " Adds or updates an entry in the Asterisk database for\n"
00403 " a given family, key, and value.\n";
00404 return NULL;
00405 case CLI_GENERATE:
00406 return NULL;
00407 }
00408
00409 if (a->argc != 5)
00410 return CLI_SHOWUSAGE;
00411 res = ast_db_put(a->argv[2], a->argv[3], a->argv[4]);
00412 if (res) {
00413 ast_cli(a->fd, "Failed to update entry\n");
00414 } else {
00415 ast_cli(a->fd, "Updated database successfully\n");
00416 }
00417 return CLI_SUCCESS;
00418 }
00419
00420 static char *handle_cli_database_get(struct ast_cli_entry *e, int cmd, struct ast_cli_args *a)
00421 {
00422 int res;
00423 char tmp[MAX_DB_FIELD];
00424
00425 switch (cmd) {
00426 case CLI_INIT:
00427 e->command = "database get";
00428 e->usage =
00429 "Usage: database get <family> <key>\n"
00430 " Retrieves an entry in the Asterisk database for a given\n"
00431 " family and key.\n";
00432 return NULL;
00433 case CLI_GENERATE:
00434 return NULL;
00435 }
00436
00437 if (a->argc != 4)
00438 return CLI_SHOWUSAGE;
00439 res = ast_db_get(a->argv[2], a->argv[3], tmp, sizeof(tmp));
00440 if (res) {
00441 ast_cli(a->fd, "Database entry not found.\n");
00442 } else {
00443 ast_cli(a->fd, "Value: %s\n", tmp);
00444 }
00445 return CLI_SUCCESS;
00446 }
00447
00448 static char *handle_cli_database_del(struct ast_cli_entry *e, int cmd, struct ast_cli_args *a)
00449 {
00450 int res;
00451
00452 switch (cmd) {
00453 case CLI_INIT:
00454 e->command = "database del";
00455 e->usage =
00456 "Usage: database del <family> <key>\n"
00457 " Deletes an entry in the Asterisk database for a given\n"
00458 " family and key.\n";
00459 return NULL;
00460 case CLI_GENERATE:
00461 return NULL;
00462 }
00463
00464 if (a->argc != 4)
00465 return CLI_SHOWUSAGE;
00466 res = ast_db_del(a->argv[2], a->argv[3]);
00467 if (res) {
00468 ast_cli(a->fd, "Database entry does not exist.\n");
00469 } else {
00470 ast_cli(a->fd, "Database entry removed.\n");
00471 }
00472 return CLI_SUCCESS;
00473 }
00474
00475 static char *handle_cli_database_deltree(struct ast_cli_entry *e, int cmd, struct ast_cli_args *a)
00476 {
00477 int num_deleted;
00478
00479 switch (cmd) {
00480 case CLI_INIT:
00481 e->command = "database deltree";
00482 e->usage =
00483 "Usage: database deltree <family> [keytree]\n"
00484 " OR: database deltree <family>[/keytree]\n"
00485 " Deletes a family or specific keytree within a family\n"
00486 " in the Asterisk database. The two arguments may be\n"
00487 " separated by either a space or a slash.\n";
00488 return NULL;
00489 case CLI_GENERATE:
00490 return NULL;
00491 }
00492
00493 if ((a->argc < 3) || (a->argc > 4))
00494 return CLI_SHOWUSAGE;
00495 if (a->argc == 4) {
00496 num_deleted = ast_db_deltree(a->argv[2], a->argv[3]);
00497 } else {
00498 num_deleted = ast_db_deltree(a->argv[2], NULL);
00499 }
00500 if (num_deleted < 0) {
00501 ast_cli(a->fd, "Database unavailable.\n");
00502 } else if (num_deleted == 0) {
00503 ast_cli(a->fd, "Database entries do not exist.\n");
00504 } else {
00505 ast_cli(a->fd, "%d database entries removed.\n",num_deleted);
00506 }
00507 return CLI_SUCCESS;
00508 }
00509
00510 static int db_show_cb(DBT *key, DBT *value, const char *filter, void *data)
00511 {
00512 struct ast_cli_args *a = data;
00513 const char *key_s = dbt_data2str_full(key, "<bad key>");
00514 const char *value_s = dbt_data2str_full(value, "<bad value>");
00515
00516 if (keymatch(key_s, filter)) {
00517 ast_cli(a->fd, "%-50s: %-25s\n", key_s, value_s);
00518 return 1;
00519 }
00520
00521 return 0;
00522 }
00523
00524 static char *handle_cli_database_show(struct ast_cli_entry *e, int cmd, struct ast_cli_args *a)
00525 {
00526 char prefix[MAX_DB_FIELD];
00527 int counter = 0;
00528
00529 switch (cmd) {
00530 case CLI_INIT:
00531 e->command = "database show";
00532 e->usage =
00533 "Usage: database show [family [keytree]]\n"
00534 " OR: database show [family[/keytree]]\n"
00535 " Shows Asterisk database contents, optionally restricted\n"
00536 " to a given family, or family and keytree. The two arguments\n"
00537 " may be separated either by a space or by a slash.\n";
00538 return NULL;
00539 case CLI_GENERATE:
00540 return NULL;
00541 }
00542
00543 if (a->argc == 4) {
00544
00545 snprintf(prefix, sizeof(prefix), "/%s/%s", a->argv[2], a->argv[3]);
00546 } else if (a->argc == 3) {
00547
00548 snprintf(prefix, sizeof(prefix), "/%s", a->argv[2]);
00549 } else if (a->argc == 2) {
00550
00551 prefix[0] = '\0';
00552 } else {
00553 return CLI_SHOWUSAGE;
00554 }
00555
00556 if((counter = process_db_keys(db_show_cb, a, prefix, 0)) < 0) {
00557 ast_cli(a->fd, "Database unavailable\n");
00558 return CLI_SUCCESS;
00559 }
00560
00561 ast_cli(a->fd, "%d results found.\n", counter);
00562 return CLI_SUCCESS;
00563 }
00564
00565 static int db_showkey_cb(DBT *key, DBT *value, const char *filter, void *data)
00566 {
00567 struct ast_cli_args *a = data;
00568 const char *key_s = dbt_data2str_full(key, "<bad key>");
00569 const char *value_s = dbt_data2str_full(value, "<bad value>");
00570
00571 if (subkeymatch(key_s, filter)) {
00572 ast_cli(a->fd, "%-50s: %-25s\n", key_s, value_s);
00573 return 1;
00574 }
00575
00576 return 0;
00577 }
00578
00579 static char *handle_cli_database_showkey(struct ast_cli_entry *e, int cmd, struct ast_cli_args *a)
00580 {
00581 char suffix[MAX_DB_FIELD];
00582 int counter = 0;
00583
00584 switch (cmd) {
00585 case CLI_INIT:
00586 e->command = "database showkey";
00587 e->usage =
00588 "Usage: database showkey <keytree>\n"
00589 " Shows Asterisk database contents, restricted to a given key.\n";
00590 return NULL;
00591 case CLI_GENERATE:
00592 return NULL;
00593 }
00594
00595 if (a->argc == 3) {
00596
00597 snprintf(suffix, sizeof(suffix), "/%s", a->argv[2]);
00598 } else {
00599 return CLI_SHOWUSAGE;
00600 }
00601
00602 if ((counter = process_db_keys(db_showkey_cb, a, suffix, 0)) < 0) {
00603 ast_cli(a->fd, "Database unavailable\n");
00604 return CLI_SUCCESS;
00605 }
00606
00607 ast_cli(a->fd, "%d results found.\n", counter);
00608 return CLI_SUCCESS;
00609 }
00610
00611 static int db_gettree_cb(DBT *key, DBT *value, const char *filter, void *data)
00612 {
00613 struct ast_db_entry **ret = data;
00614 struct ast_db_entry *cur;
00615 const char *key_s = dbt_data2str_full(key, "<bad key>");
00616 const char *value_s = dbt_data2str_full(value, "<bad value>");
00617 size_t key_slen = strlen(key_s) + 1, value_slen = strlen(value_s) + 1;
00618
00619 if (keymatch(key_s, filter) && (cur = ast_malloc(sizeof(*cur) + key_slen + value_slen))) {
00620 cur->next = *ret;
00621 cur->key = cur->data + value_slen;
00622 strcpy(cur->data, value_s);
00623 strcpy(cur->key, key_s);
00624 *ret = cur;
00625 return 1;
00626 }
00627
00628 return 0;
00629 }
00630
00631 struct ast_db_entry *ast_db_gettree(const char *family, const char *keytree)
00632 {
00633 char prefix[MAX_DB_FIELD];
00634 struct ast_db_entry *ret = NULL;
00635
00636 if (!ast_strlen_zero(family)) {
00637 if (!ast_strlen_zero(keytree)) {
00638
00639 snprintf(prefix, sizeof(prefix), "/%s/%s", family, keytree);
00640 } else {
00641
00642 snprintf(prefix, sizeof(prefix), "/%s", family);
00643 }
00644 } else {
00645 prefix[0] = '\0';
00646 }
00647
00648 if (process_db_keys(db_gettree_cb, &ret, prefix, 0) < 0) {
00649 ast_log(LOG_WARNING, "Database unavailable\n");
00650 return NULL;
00651 }
00652
00653 return ret;
00654 }
00655
00656 void ast_db_freetree(struct ast_db_entry *dbe)
00657 {
00658 struct ast_db_entry *last;
00659 while (dbe) {
00660 last = dbe;
00661 dbe = dbe->next;
00662 ast_free(last);
00663 }
00664 }
00665
00666 static struct ast_cli_entry cli_database[] = {
00667 AST_CLI_DEFINE(handle_cli_database_show, "Shows database contents"),
00668 AST_CLI_DEFINE(handle_cli_database_showkey, "Shows database contents"),
00669 AST_CLI_DEFINE(handle_cli_database_get, "Gets database value"),
00670 AST_CLI_DEFINE(handle_cli_database_put, "Adds/updates database value"),
00671 AST_CLI_DEFINE(handle_cli_database_del, "Removes database key/value"),
00672 AST_CLI_DEFINE(handle_cli_database_deltree, "Removes database keytree/values")
00673 };
00674
00675 static int manager_dbput(struct mansession *s, const struct message *m)
00676 {
00677 const char *family = astman_get_header(m, "Family");
00678 const char *key = astman_get_header(m, "Key");
00679 const char *val = astman_get_header(m, "Val");
00680 int res;
00681
00682 if (ast_strlen_zero(family)) {
00683 astman_send_error(s, m, "No family specified");
00684 return 0;
00685 }
00686 if (ast_strlen_zero(key)) {
00687 astman_send_error(s, m, "No key specified");
00688 return 0;
00689 }
00690
00691 res = ast_db_put(family, key, S_OR(val, ""));
00692 if (res) {
00693 astman_send_error(s, m, "Failed to update entry");
00694 } else {
00695 astman_send_ack(s, m, "Updated database successfully");
00696 }
00697 return 0;
00698 }
00699
00700 static int manager_dbget(struct mansession *s, const struct message *m)
00701 {
00702 const char *id = astman_get_header(m,"ActionID");
00703 char idText[256] = "";
00704 const char *family = astman_get_header(m, "Family");
00705 const char *key = astman_get_header(m, "Key");
00706 char tmp[MAX_DB_FIELD];
00707 int res;
00708
00709 if (ast_strlen_zero(family)) {
00710 astman_send_error(s, m, "No family specified.");
00711 return 0;
00712 }
00713 if (ast_strlen_zero(key)) {
00714 astman_send_error(s, m, "No key specified.");
00715 return 0;
00716 }
00717
00718 if (!ast_strlen_zero(id))
00719 snprintf(idText, sizeof(idText) ,"ActionID: %s\r\n", id);
00720
00721 res = ast_db_get(family, key, tmp, sizeof(tmp));
00722 if (res) {
00723 astman_send_error(s, m, "Database entry not found");
00724 } else {
00725 astman_send_ack(s, m, "Result will follow");
00726 astman_append(s, "Event: DBGetResponse\r\n"
00727 "Family: %s\r\n"
00728 "Key: %s\r\n"
00729 "Val: %s\r\n"
00730 "%s"
00731 "\r\n",
00732 family, key, tmp, idText);
00733 astman_append(s, "Event: DBGetComplete\r\n"
00734 "%s"
00735 "\r\n",
00736 idText);
00737 }
00738 return 0;
00739 }
00740
00741 static int manager_dbdel(struct mansession *s, const struct message *m)
00742 {
00743 const char *family = astman_get_header(m, "Family");
00744 const char *key = astman_get_header(m, "Key");
00745 int res;
00746
00747 if (ast_strlen_zero(family)) {
00748 astman_send_error(s, m, "No family specified.");
00749 return 0;
00750 }
00751
00752 if (ast_strlen_zero(key)) {
00753 astman_send_error(s, m, "No key specified.");
00754 return 0;
00755 }
00756
00757 res = ast_db_del(family, key);
00758 if (res)
00759 astman_send_error(s, m, "Database entry not found");
00760 else
00761 astman_send_ack(s, m, "Key deleted successfully");
00762
00763 return 0;
00764 }
00765
00766 static int manager_dbdeltree(struct mansession *s, const struct message *m)
00767 {
00768 const char *family = astman_get_header(m, "Family");
00769 const char *key = astman_get_header(m, "Key");
00770 int num_deleted;
00771
00772 if (ast_strlen_zero(family)) {
00773 astman_send_error(s, m, "No family specified.");
00774 return 0;
00775 }
00776
00777 if (!ast_strlen_zero(key)) {
00778 num_deleted = ast_db_deltree(family, key);
00779 } else {
00780 num_deleted = ast_db_deltree(family, NULL);
00781 }
00782
00783 if (num_deleted < 0) {
00784 astman_send_error(s, m, "Database unavailable");
00785 } else if (num_deleted == 0) {
00786 astman_send_error(s, m, "Database entry not found");
00787 } else {
00788 astman_send_ack(s, m, "Key tree deleted successfully");
00789 }
00790
00791 return 0;
00792 }
00793
00794
00795
00796
00797
00798
00799
00800 static void db_sync(void)
00801 {
00802 ast_cond_signal(&dbcond);
00803 }
00804
00805
00806
00807
00808
00809
00810
00811
00812
00813
00814
00815 static void *db_sync_thread(void *data)
00816 {
00817 ast_mutex_lock(&dblock);
00818 for (;;) {
00819 ast_cond_wait(&dbcond, &dblock);
00820 if (doexit) {
00821
00822
00823
00824
00825 if (astdb) {
00826 astdb->sync(astdb, 0);
00827 }
00828 ast_mutex_unlock(&dblock);
00829 break;
00830 }
00831
00832 ast_mutex_unlock(&dblock);
00833
00834
00835
00836
00837 sleep(1);
00838 ast_mutex_lock(&dblock);
00839
00840
00841 ast_assert(astdb != NULL);
00842 astdb->sync(astdb, 0);
00843
00844 if (doexit) {
00845
00846 ast_mutex_unlock(&dblock);
00847 break;
00848 }
00849 }
00850
00851 return NULL;
00852 }
00853
00854 static void astdb_shutdown(void)
00855 {
00856 ast_cli_unregister_multiple(cli_database, ARRAY_LEN(cli_database));
00857 ast_manager_unregister("DBGet");
00858 ast_manager_unregister("DBPut");
00859 ast_manager_unregister("DBDel");
00860 ast_manager_unregister("DBDelTree");
00861
00862 ast_mutex_lock(&dblock);
00863 doexit = 1;
00864 db_sync();
00865 ast_mutex_unlock(&dblock);
00866
00867 pthread_join(syncthread, NULL);
00868
00869 #if defined(DEBUG_FD_LEAKS) && defined(close)
00870
00871 #undef close
00872 #endif
00873
00874 if (astdb) {
00875 astdb->close(astdb);
00876 astdb = NULL;
00877 }
00878 }
00879
00880 int astdb_init(void)
00881 {
00882 ast_cond_init(&dbcond, NULL);
00883 if (ast_pthread_create_background(&syncthread, NULL, db_sync_thread, NULL)) {
00884 return -1;
00885 }
00886
00887 ast_mutex_lock(&dblock);
00888
00889 dbinit();
00890 ast_mutex_unlock(&dblock);
00891
00892 ast_cli_register_multiple(cli_database, ARRAY_LEN(cli_database));
00893 ast_manager_register_xml("DBGet", EVENT_FLAG_SYSTEM | EVENT_FLAG_REPORTING, manager_dbget);
00894 ast_manager_register_xml("DBPut", EVENT_FLAG_SYSTEM, manager_dbput);
00895 ast_manager_register_xml("DBDel", EVENT_FLAG_SYSTEM, manager_dbdel);
00896 ast_manager_register_xml("DBDelTree", EVENT_FLAG_SYSTEM, manager_dbdeltree);
00897
00898 ast_register_atexit(astdb_shutdown);
00899 return 0;
00900 }