Sat Feb 11 06:33:14 2012

Asterisk developer's documentation


db.c

Go to the documentation of this file.
00001 /*
00002  * Asterisk -- An open source telephony toolkit.
00003  *
00004  * Copyright (C) 1999 - 2005, Digium, Inc.
00005  *
00006  * Mark Spencer <markster@digium.com>
00007  *
00008  * See http://www.asterisk.org for more information about
00009  * the Asterisk project. Please do not directly contact
00010  * any of the maintainers of this project for assistance;
00011  * the project provides a web site, mailing lists and IRC
00012  * channels for your use.
00013  *
00014  * This program is free software, distributed under the terms of
00015  * the GNU General Public License Version 2. See the LICENSE file
00016  * at the top of the source tree.
00017  */
00018 
00019 /*! \file
00020  *
00021  * \brief ASTdb Management
00022  *
00023  * \author Mark Spencer <markster@digium.com>
00024  *
00025  * \note DB3 is licensed under Sleepycat Public License and is thus incompatible
00026  * with GPL.  To avoid having to make another exception (and complicate
00027  * licensing even further) we elect to use DB1 which is BSD licensed
00028  */
00029 
00030 #include "asterisk.h"
00031 
00032 ASTERISK_FILE_VERSION(__FILE__, "$Revision: 350979 $")
00033 
00034 #include "asterisk/_private.h"
00035 #include "asterisk/paths.h"   /* use ast_config_AST_DB */
00036 #include <sys/time.h>
00037 #include <sys/types.h>
00038 #include <sys/stat.h>
00039 #include <unistd.h>
00040 #include <signal.h>
00041 #include <dirent.h>
00042 #include <sqlite3.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/manager.h"
00052 
00053 /*** DOCUMENTATION
00054    <manager name="DBGet" language="en_US">
00055       <synopsis>
00056          Get DB Entry.
00057       </synopsis>
00058       <syntax>
00059          <xi:include xpointer="xpointer(/docs/manager[@name='Login']/syntax/parameter[@name='ActionID'])" />
00060          <parameter name="Family" required="true" />
00061          <parameter name="Key" required="true" />
00062       </syntax>
00063       <description>
00064       </description>
00065    </manager>
00066    <manager name="DBPut" language="en_US">
00067       <synopsis>
00068          Put DB entry.
00069       </synopsis>
00070       <syntax>
00071          <xi:include xpointer="xpointer(/docs/manager[@name='Login']/syntax/parameter[@name='ActionID'])" />
00072          <parameter name="Family" required="true" />
00073          <parameter name="Key" required="true" />
00074          <parameter name="Val" />
00075       </syntax>
00076       <description>
00077       </description>
00078    </manager>
00079    <manager name="DBDel" language="en_US">
00080       <synopsis>
00081          Delete DB entry.
00082       </synopsis>
00083       <syntax>
00084          <xi:include xpointer="xpointer(/docs/manager[@name='Login']/syntax/parameter[@name='ActionID'])" />
00085          <parameter name="Family" required="true" />
00086          <parameter name="Key" required="true" />
00087       </syntax>
00088       <description>
00089       </description>
00090    </manager>
00091    <manager name="DBDelTree" language="en_US">
00092       <synopsis>
00093          Delete DB Tree.
00094       </synopsis>
00095       <syntax>
00096          <xi:include xpointer="xpointer(/docs/manager[@name='Login']/syntax/parameter[@name='ActionID'])" />
00097          <parameter name="Family" required="true" />
00098          <parameter name="Key" />
00099       </syntax>
00100       <description>
00101       </description>
00102    </manager>
00103  ***/
00104 
00105 #define MAX_DB_FIELD 256
00106 AST_MUTEX_DEFINE_STATIC(dblock);
00107 static ast_cond_t dbcond;
00108 static sqlite3 *astdb;
00109 static pthread_t syncthread;
00110 static int doexit;
00111 
00112 static void db_sync(void);
00113 
00114 #define DEFINE_SQL_STATEMENT(stmt,sql) static sqlite3_stmt *stmt; \
00115    const char stmt##_sql[] = sql;
00116 
00117 DEFINE_SQL_STATEMENT(put_stmt, "INSERT OR REPLACE INTO astdb (key, value) VALUES (?, ?)")
00118 DEFINE_SQL_STATEMENT(get_stmt, "SELECT value FROM astdb WHERE key=?")
00119 DEFINE_SQL_STATEMENT(del_stmt, "DELETE FROM astdb WHERE key=?")
00120 DEFINE_SQL_STATEMENT(deltree_stmt, "DELETE FROM astdb WHERE key || '/' LIKE ? || '/' || '%'")
00121 DEFINE_SQL_STATEMENT(deltree_all_stmt, "DELETE FROM astdb")
00122 DEFINE_SQL_STATEMENT(gettree_stmt, "SELECT key, value FROM astdb WHERE key || '/' LIKE ? || '/' || '%' ORDER BY key")
00123 DEFINE_SQL_STATEMENT(gettree_all_stmt, "SELECT key, value FROM astdb ORDER BY key")
00124 DEFINE_SQL_STATEMENT(showkey_stmt, "SELECT key, value FROM astdb WHERE key LIKE '%' || '/' || ? ORDER BY key")
00125 DEFINE_SQL_STATEMENT(create_astdb_stmt, "CREATE TABLE IF NOT EXISTS astdb(key VARCHAR(256), value VARCHAR(256), PRIMARY KEY(key))")
00126 
00127 static int init_stmt(sqlite3_stmt **stmt, const char *sql, size_t len)
00128 {
00129    ast_mutex_lock(&dblock);
00130    if (sqlite3_prepare(astdb, sql, len, stmt, NULL) != SQLITE_OK) {
00131       ast_log(LOG_WARNING, "Couldn't prepare statement '%s': %s\n", sql, sqlite3_errmsg(astdb));
00132       ast_mutex_unlock(&dblock);
00133       return -1;
00134    }
00135    ast_mutex_unlock(&dblock);
00136 
00137    return 0;
00138 }
00139 
00140 static int init_statements(void)
00141 {
00142    /* Don't initialize create_astdb_statment here as the astdb table needs to exist
00143     * brefore these statments can be initialized */
00144    return init_stmt(&get_stmt, get_stmt_sql, sizeof(get_stmt_sql))
00145    || init_stmt(&del_stmt, del_stmt_sql, sizeof(del_stmt_sql))
00146    || init_stmt(&deltree_stmt, deltree_stmt_sql, sizeof(deltree_stmt_sql))
00147    || init_stmt(&deltree_all_stmt, deltree_all_stmt_sql, sizeof(deltree_all_stmt_sql))
00148    || init_stmt(&gettree_stmt, gettree_stmt_sql, sizeof(gettree_stmt_sql))
00149    || init_stmt(&gettree_all_stmt, gettree_all_stmt_sql, sizeof(gettree_all_stmt_sql))
00150    || init_stmt(&showkey_stmt, showkey_stmt_sql, sizeof(showkey_stmt_sql))
00151    || init_stmt(&put_stmt, put_stmt_sql, sizeof(put_stmt_sql));
00152 }
00153 
00154 static int convert_bdb_to_sqlite3(void)
00155 {
00156    char *cmd;
00157    int res;
00158 
00159    ast_asprintf(&cmd, "%s/astdb2sqlite3 '%s'\n", ast_config_AST_SBIN_DIR, ast_config_AST_DB);
00160    res = ast_safe_system(cmd);
00161    ast_free(cmd);
00162 
00163    return res;
00164 }
00165 
00166 static int db_create_astdb(void)
00167 {
00168    int res = 0;
00169 
00170    if (!create_astdb_stmt) {
00171       init_stmt(&create_astdb_stmt, create_astdb_stmt_sql, sizeof(create_astdb_stmt_sql));
00172    }
00173 
00174    ast_mutex_lock(&dblock);
00175    if (sqlite3_step(create_astdb_stmt) != SQLITE_DONE) {
00176       ast_log(LOG_WARNING, "Couldn't create astdb table: %s\n", sqlite3_errmsg(astdb));
00177       res = -1;
00178    }
00179    sqlite3_reset(create_astdb_stmt);
00180    db_sync();
00181    ast_mutex_unlock(&dblock);
00182 
00183    return res;
00184 }
00185 
00186 static int db_open(void)
00187 {
00188    char *dbname;
00189    struct stat dont_care;
00190 
00191    if (!(dbname = alloca(strlen(ast_config_AST_DB) + sizeof(".sqlite3")))) {
00192       return -1;
00193    }
00194    strcpy(dbname, ast_config_AST_DB);
00195    strcat(dbname, ".sqlite3");
00196 
00197    if (stat(dbname, &dont_care) && !stat(ast_config_AST_DB, &dont_care)) {
00198       if (convert_bdb_to_sqlite3()) {
00199          ast_log(LOG_ERROR, "*** Database conversion failed!\n");
00200          ast_log(LOG_ERROR, "*** Asterisk now uses SQLite3 for its internal\n");
00201          ast_log(LOG_ERROR, "*** database. Conversion from the old astdb\n");
00202          ast_log(LOG_ERROR, "*** failed. Most likely the astdb2sqlite3 utility\n");
00203          ast_log(LOG_ERROR, "*** was not selected for build. To convert the\n");
00204          ast_log(LOG_ERROR, "*** old astdb, please delete '%s'\n", dbname);
00205          ast_log(LOG_ERROR, "*** and re-run 'make menuselect' and select astdb2sqlite3\n");
00206          ast_log(LOG_ERROR, "*** in the Utilities section, then 'make && make install'.\n");
00207          ast_log(LOG_ERROR, "*** It is also imperative that the user under which\n");
00208          ast_log(LOG_ERROR, "*** Asterisk runs have write permission to the directory\n");
00209          ast_log(LOG_ERROR, "*** where the database resides.\n");
00210          sleep(5);
00211       } else {
00212          ast_log(LOG_NOTICE, "Database conversion succeeded!\n");
00213       }
00214    }
00215 
00216    ast_mutex_lock(&dblock);
00217    if (sqlite3_open(dbname, &astdb) != SQLITE_OK) {
00218       ast_log(LOG_WARNING, "Unable to open Asterisk database '%s': %s\n", dbname, sqlite3_errmsg(astdb));
00219       sqlite3_close(astdb);
00220       ast_mutex_unlock(&dblock);
00221       return -1;
00222    }
00223    ast_mutex_unlock(&dblock);
00224 
00225    return 0;
00226 }
00227 
00228 static int db_init(void)
00229 {
00230    if (astdb) {
00231       return 0;
00232    }
00233 
00234    if (db_open() || db_create_astdb() || init_statements()) {
00235       return -1;
00236    }
00237 
00238    return 0;
00239 }
00240 
00241 /* We purposely don't lock around the sqlite3 call because the transaction
00242  * calls will be called with the database lock held. For any other use, make
00243  * sure to take the dblock yourself. */
00244 static int db_execute_sql(const char *sql, int (*callback)(void *, int, char **, char **), void *arg)
00245 {
00246    char *errmsg = NULL;
00247    int res =0;
00248 
00249    sqlite3_exec(astdb, sql, callback, arg, &errmsg);
00250    if (errmsg) {
00251       ast_log(LOG_WARNING, "Error executing SQL: %s\n", errmsg);
00252       sqlite3_free(errmsg);
00253       res = -1;
00254    }
00255 
00256    return res;
00257 }
00258 
00259 static int ast_db_begin_transaction(void)
00260 {
00261    return db_execute_sql("BEGIN TRANSACTION", NULL, NULL);
00262 }
00263 
00264 static int ast_db_commit_transaction(void)
00265 {
00266    return db_execute_sql("COMMIT", NULL, NULL);
00267 }
00268 
00269 static int ast_db_rollback_transaction(void)
00270 {
00271    return db_execute_sql("ROLLBACK", NULL, NULL);
00272 }
00273 
00274 int ast_db_put(const char *family, const char *key, const char *value)
00275 {
00276    char fullkey[MAX_DB_FIELD];
00277    size_t fullkey_len;
00278    int res = 0;
00279 
00280    if (strlen(family) + strlen(key) + 2 > sizeof(fullkey) - 1) {
00281       ast_log(LOG_WARNING, "Family and key length must be less than %zu bytes\n", sizeof(fullkey) - 3);
00282       return -1;
00283    }
00284 
00285    fullkey_len = snprintf(fullkey, sizeof(fullkey), "/%s/%s", family, key);
00286 
00287    ast_mutex_lock(&dblock);
00288    if (sqlite3_bind_text(put_stmt, 1, fullkey, fullkey_len, SQLITE_STATIC) != SQLITE_OK) {
00289       ast_log(LOG_WARNING, "Couldn't bind key to stmt: %s\n", sqlite3_errmsg(astdb));
00290       res = -1;
00291    } else if (sqlite3_bind_text(put_stmt, 2, value, -1, SQLITE_STATIC) != SQLITE_OK) {
00292       ast_log(LOG_WARNING, "Couldn't bind value to stmt: %s\n", sqlite3_errmsg(astdb));
00293       res = -1;
00294    } else if (sqlite3_step(put_stmt) != SQLITE_DONE) {
00295       ast_log(LOG_WARNING, "Couldn't execute statment: %s\n", sqlite3_errmsg(astdb));
00296       res = -1;
00297    }
00298 
00299    sqlite3_reset(put_stmt);
00300    db_sync();
00301    ast_mutex_unlock(&dblock);
00302 
00303    return res;
00304 }
00305 
00306 int ast_db_get(const char *family, const char *key, char *value, int valuelen)
00307 {
00308    const unsigned char *result;
00309    char fullkey[MAX_DB_FIELD];
00310    size_t fullkey_len;
00311    int res = 0;
00312 
00313    if (strlen(family) + strlen(key) + 2 > sizeof(fullkey) - 1) {
00314       ast_log(LOG_WARNING, "Family and key length must be less than %zu bytes\n", sizeof(fullkey) - 3);
00315       return -1;
00316    }
00317 
00318    fullkey_len = snprintf(fullkey, sizeof(fullkey), "/%s/%s", family, key);
00319 
00320    ast_mutex_lock(&dblock);
00321    if (sqlite3_bind_text(get_stmt, 1, fullkey, fullkey_len, SQLITE_STATIC) != SQLITE_OK) {
00322       ast_log(LOG_WARNING, "Couldn't bind key to stmt: %s\n", sqlite3_errmsg(astdb));
00323       res = -1;
00324    } else if (sqlite3_step(get_stmt) != SQLITE_ROW) {
00325       ast_debug(1, "Unable to find key '%s' in family '%s'\n", key, family);
00326       res = -1;
00327    } else if (!(result = sqlite3_column_text(get_stmt, 0))) {
00328       ast_log(LOG_WARNING, "Couldn't get value\n");
00329       res = -1;
00330    } else {
00331       strncpy(value, (const char *) result, valuelen);
00332    }
00333    sqlite3_reset(get_stmt);
00334    ast_mutex_unlock(&dblock);
00335 
00336    return res;
00337 }
00338 
00339 int ast_db_del(const char *family, const char *key)
00340 {
00341    char fullkey[MAX_DB_FIELD];
00342    size_t fullkey_len;
00343    int res = 0;
00344 
00345    if (strlen(family) + strlen(key) + 2 > sizeof(fullkey) - 1) {
00346       ast_log(LOG_WARNING, "Family and key length must be less than %zu bytes\n", sizeof(fullkey) - 3);
00347       return -1;
00348    }
00349 
00350    fullkey_len = snprintf(fullkey, sizeof(fullkey), "/%s/%s", family, key);
00351 
00352    ast_mutex_lock(&dblock);
00353    if (sqlite3_bind_text(del_stmt, 1, fullkey, fullkey_len, SQLITE_STATIC) != SQLITE_OK) {
00354       ast_log(LOG_WARNING, "Couldn't bind key to stmt: %s\n", sqlite3_errmsg(astdb));
00355       res = -1;
00356    } else if (sqlite3_step(del_stmt) != SQLITE_DONE) {
00357       ast_debug(1, "Unable to find key '%s' in family '%s'\n", key, family);
00358       res = -1;
00359    }
00360    sqlite3_reset(del_stmt);
00361    db_sync();
00362    ast_mutex_unlock(&dblock);
00363 
00364    return res;
00365 }
00366 
00367 int ast_db_deltree(const char *family, const char *keytree)
00368 {
00369    sqlite3_stmt *stmt = deltree_stmt;
00370    char prefix[MAX_DB_FIELD];
00371    int res = 0;
00372 
00373    if (!ast_strlen_zero(family)) {
00374       if (!ast_strlen_zero(keytree)) {
00375          /* Family and key tree */
00376          snprintf(prefix, sizeof(prefix), "/%s/%s", family, keytree);
00377       } else {
00378          /* Family only */
00379          snprintf(prefix, sizeof(prefix), "/%s", family);
00380       }
00381    } else {
00382       prefix[0] = '\0';
00383       stmt = deltree_all_stmt;
00384    }
00385 
00386    ast_mutex_lock(&dblock);
00387    if (!ast_strlen_zero(prefix) && (sqlite3_bind_text(stmt, 1, prefix, -1, SQLITE_STATIC) != SQLITE_OK)) {
00388       ast_log(LOG_WARNING, "Could bind %s to stmt: %s\n", prefix, sqlite3_errmsg(astdb));
00389       res = -1;
00390    } else if (sqlite3_step(stmt) != SQLITE_DONE) {
00391       ast_log(LOG_WARNING, "Couldn't execute stmt: %s\n", sqlite3_errmsg(astdb));
00392       res = -1;
00393    }
00394    res = sqlite3_changes(astdb);
00395    sqlite3_reset(stmt);
00396    db_sync();
00397    ast_mutex_unlock(&dblock);
00398 
00399    return res;
00400 }
00401 
00402 struct ast_db_entry *ast_db_gettree(const char *family, const char *keytree)
00403 {
00404    char prefix[MAX_DB_FIELD];
00405    sqlite3_stmt *stmt = gettree_stmt;
00406    struct ast_db_entry *cur, *last = NULL, *ret = NULL;
00407 
00408    if (!ast_strlen_zero(family)) {
00409       if (!ast_strlen_zero(keytree)) {
00410          /* Family and key tree */
00411          snprintf(prefix, sizeof(prefix), "/%s/%s", family, keytree);
00412       } else {
00413          /* Family only */
00414          snprintf(prefix, sizeof(prefix), "/%s", family);
00415       }
00416    } else {
00417       prefix[0] = '\0';
00418       stmt = gettree_all_stmt;
00419    }
00420 
00421    ast_mutex_lock(&dblock);
00422    if (!ast_strlen_zero(prefix) && (sqlite3_bind_text(stmt, 1, prefix, -1, SQLITE_STATIC) != SQLITE_OK)) {
00423       ast_log(LOG_WARNING, "Could bind %s to stmt: %s\n", prefix, sqlite3_errmsg(astdb));
00424       sqlite3_reset(stmt);
00425       ast_mutex_unlock(&dblock);
00426       return NULL;
00427    }
00428 
00429    while (sqlite3_step(stmt) == SQLITE_ROW) {
00430       const char *key_s, *value_s;
00431       if (!(key_s = (const char *) sqlite3_column_text(stmt, 0))) {
00432          break;
00433       }
00434       if (!(value_s = (const char *) sqlite3_column_text(stmt, 1))) {
00435          break;
00436       }
00437       if (!(cur = ast_malloc(sizeof(*cur) + strlen(key_s) + strlen(value_s) + 2))) {
00438          break;
00439       }
00440       cur->next = NULL;
00441       cur->key = cur->data + strlen(value_s) + 1;
00442       strcpy(cur->data, value_s);
00443       strcpy(cur->key, key_s);
00444       if (last) {
00445          last->next = cur;
00446       } else {
00447          ret = cur;
00448       }
00449       last = cur;
00450    }
00451    sqlite3_reset(stmt);
00452    ast_mutex_unlock(&dblock);
00453 
00454    return ret;
00455 }
00456 
00457 void ast_db_freetree(struct ast_db_entry *dbe)
00458 {
00459    struct ast_db_entry *last;
00460    while (dbe) {
00461       last = dbe;
00462       dbe = dbe->next;
00463       ast_free(last);
00464    }
00465 }
00466 
00467 static char *handle_cli_database_put(struct ast_cli_entry *e, int cmd, struct ast_cli_args *a)
00468 {
00469    int res;
00470 
00471    switch (cmd) {
00472    case CLI_INIT:
00473       e->command = "database put";
00474       e->usage =
00475          "Usage: database put <family> <key> <value>\n"
00476          "       Adds or updates an entry in the Asterisk database for\n"
00477          "       a given family, key, and value.\n";
00478       return NULL;
00479    case CLI_GENERATE:
00480       return NULL;
00481    }
00482 
00483    if (a->argc != 5)
00484       return CLI_SHOWUSAGE;
00485    res = ast_db_put(a->argv[2], a->argv[3], a->argv[4]);
00486    if (res)  {
00487       ast_cli(a->fd, "Failed to update entry\n");
00488    } else {
00489       ast_cli(a->fd, "Updated database successfully\n");
00490    }
00491    return CLI_SUCCESS;
00492 }
00493 
00494 static char *handle_cli_database_get(struct ast_cli_entry *e, int cmd, struct ast_cli_args *a)
00495 {
00496    int res;
00497    char tmp[MAX_DB_FIELD];
00498 
00499    switch (cmd) {
00500    case CLI_INIT:
00501       e->command = "database get";
00502       e->usage =
00503          "Usage: database get <family> <key>\n"
00504          "       Retrieves an entry in the Asterisk database for a given\n"
00505          "       family and key.\n";
00506       return NULL;
00507    case CLI_GENERATE:
00508       return NULL;
00509    }
00510 
00511    if (a->argc != 4)
00512       return CLI_SHOWUSAGE;
00513    res = ast_db_get(a->argv[2], a->argv[3], tmp, sizeof(tmp));
00514    if (res) {
00515       ast_cli(a->fd, "Database entry not found.\n");
00516    } else {
00517       ast_cli(a->fd, "Value: %s\n", tmp);
00518    }
00519    return CLI_SUCCESS;
00520 }
00521 
00522 static char *handle_cli_database_del(struct ast_cli_entry *e, int cmd, struct ast_cli_args *a)
00523 {
00524    int res;
00525 
00526    switch (cmd) {
00527    case CLI_INIT:
00528       e->command = "database del";
00529       e->usage =
00530          "Usage: database del <family> <key>\n"
00531          "       Deletes an entry in the Asterisk database for a given\n"
00532          "       family and key.\n";
00533       return NULL;
00534    case CLI_GENERATE:
00535       return NULL;
00536    }
00537 
00538    if (a->argc != 4)
00539       return CLI_SHOWUSAGE;
00540    res = ast_db_del(a->argv[2], a->argv[3]);
00541    if (res) {
00542       ast_cli(a->fd, "Database entry does not exist.\n");
00543    } else {
00544       ast_cli(a->fd, "Database entry removed.\n");
00545    }
00546    return CLI_SUCCESS;
00547 }
00548 
00549 static char *handle_cli_database_deltree(struct ast_cli_entry *e, int cmd, struct ast_cli_args *a)
00550 {
00551    int res;
00552 
00553    switch (cmd) {
00554    case CLI_INIT:
00555       e->command = "database deltree";
00556       e->usage =
00557          "Usage: database deltree <family> [keytree]\n"
00558          "   OR: database deltree <family>[/keytree]\n"
00559          "       Deletes a family or specific keytree within a family\n"
00560          "       in the Asterisk database.  The two arguments may be\n"
00561          "       separated by either a space or a slash.\n";
00562       return NULL;
00563    case CLI_GENERATE:
00564       return NULL;
00565    }
00566 
00567    if ((a->argc < 3) || (a->argc > 4))
00568       return CLI_SHOWUSAGE;
00569    if (a->argc == 4) {
00570       res = ast_db_deltree(a->argv[2], a->argv[3]);
00571    } else {
00572       res = ast_db_deltree(a->argv[2], NULL);
00573    }
00574    if (res < 0) {
00575       ast_cli(a->fd, "Database entries do not exist.\n");
00576    } else {
00577       ast_cli(a->fd, "%d database entries removed.\n",res);
00578    }
00579    return CLI_SUCCESS;
00580 }
00581 
00582 static char *handle_cli_database_show(struct ast_cli_entry *e, int cmd, struct ast_cli_args *a)
00583 {
00584    char prefix[MAX_DB_FIELD];
00585    int counter = 0;
00586    sqlite3_stmt *stmt = gettree_stmt;
00587 
00588    switch (cmd) {
00589    case CLI_INIT:
00590       e->command = "database show";
00591       e->usage =
00592          "Usage: database show [family [keytree]]\n"
00593          "   OR: database show [family[/keytree]]\n"
00594          "       Shows Asterisk database contents, optionally restricted\n"
00595          "       to a given family, or family and keytree. The two arguments\n"
00596          "       may be separated either by a space or by a slash.\n";
00597       return NULL;
00598    case CLI_GENERATE:
00599       return NULL;
00600    }
00601 
00602    if (a->argc == 4) {
00603       /* Family and key tree */
00604       snprintf(prefix, sizeof(prefix), "/%s/%s", a->argv[2], a->argv[3]);
00605    } else if (a->argc == 3) {
00606       /* Family only */
00607       snprintf(prefix, sizeof(prefix), "/%s", a->argv[2]);
00608    } else if (a->argc == 2) {
00609       /* Neither */
00610       prefix[0] = '\0';
00611       stmt = gettree_all_stmt;
00612 
00613    } else {
00614       return CLI_SHOWUSAGE;
00615    }
00616 
00617    ast_mutex_lock(&dblock);
00618    if (!ast_strlen_zero(prefix) && (sqlite3_bind_text(stmt, 1, prefix, -1, SQLITE_STATIC) != SQLITE_OK)) {
00619       ast_log(LOG_WARNING, "Could bind %s to stmt: %s\n", prefix, sqlite3_errmsg(astdb));
00620       sqlite3_reset(stmt);
00621       ast_mutex_unlock(&dblock);
00622       return NULL;
00623    }
00624 
00625    while (sqlite3_step(stmt) == SQLITE_ROW) {
00626       const char *key_s, *value_s;
00627       if (!(key_s = (const char *) sqlite3_column_text(stmt, 0))) {
00628          ast_log(LOG_WARNING, "Skipping invalid key!\n");
00629          continue;
00630       }
00631       if (!(value_s = (const char *) sqlite3_column_text(stmt, 1))) {
00632          ast_log(LOG_WARNING, "Skipping invalid value!\n");
00633          continue;
00634       }
00635       ++counter;
00636       ast_cli(a->fd, "%-50s: %-25s\n", key_s, value_s);
00637    }
00638 
00639    sqlite3_reset(stmt);
00640    ast_mutex_unlock(&dblock);
00641 
00642    ast_cli(a->fd, "%d results found.\n", counter);
00643    return CLI_SUCCESS;
00644 }
00645 
00646 static char *handle_cli_database_showkey(struct ast_cli_entry *e, int cmd, struct ast_cli_args *a)
00647 {
00648    int counter = 0;
00649 
00650    switch (cmd) {
00651    case CLI_INIT:
00652       e->command = "database showkey";
00653       e->usage =
00654          "Usage: database showkey <keytree>\n"
00655          "       Shows Asterisk database contents, restricted to a given key.\n";
00656       return NULL;
00657    case CLI_GENERATE:
00658       return NULL;
00659    }
00660 
00661    if (a->argc != 3) {
00662       return CLI_SHOWUSAGE;
00663    }
00664 
00665    ast_mutex_lock(&dblock);
00666    if (!ast_strlen_zero(a->argv[2]) && (sqlite3_bind_text(showkey_stmt, 1, a->argv[2], -1, SQLITE_STATIC) != SQLITE_OK)) {
00667       ast_log(LOG_WARNING, "Could bind %s to stmt: %s\n", a->argv[2], sqlite3_errmsg(astdb));
00668       sqlite3_reset(showkey_stmt);
00669       ast_mutex_unlock(&dblock);
00670       return NULL;
00671    }
00672 
00673    while (sqlite3_step(showkey_stmt) == SQLITE_ROW) {
00674       const char *key_s, *value_s;
00675       if (!(key_s = (const char *) sqlite3_column_text(showkey_stmt, 0))) {
00676          break;
00677       }
00678       if (!(value_s = (const char *) sqlite3_column_text(showkey_stmt, 1))) {
00679          break;
00680       }
00681       ++counter;
00682       ast_cli(a->fd, "%-50s: %-25s\n", key_s, value_s);
00683    }
00684    sqlite3_reset(showkey_stmt);
00685    ast_mutex_unlock(&dblock);
00686 
00687    ast_cli(a->fd, "%d results found.\n", counter);
00688    return CLI_SUCCESS;
00689 }
00690 
00691 static int display_results(void *arg, int columns, char **values, char **colnames)
00692 {
00693    struct ast_cli_args *a = arg;
00694    size_t x;
00695 
00696    for (x = 0; x < columns; x++) {
00697       ast_cli(a->fd, "%-5s: %-50s\n", colnames[x], values[x]);
00698    }
00699    ast_cli(a->fd, "\n");
00700 
00701    return 0;
00702 }
00703 
00704 static char *handle_cli_database_query(struct ast_cli_entry *e, int cmd, struct ast_cli_args *a)
00705 {
00706 
00707    switch (cmd) {
00708    case CLI_INIT:
00709       e->command = "database query";
00710       e->usage =
00711          "Usage: database query \"<SQL Statement>\"\n"
00712          "       Run a user-specified SQL query on the database. Be careful.\n";
00713       return NULL;
00714    case CLI_GENERATE:
00715       return NULL;
00716    }
00717 
00718    if (a->argc != 3) {
00719       return CLI_SHOWUSAGE;
00720    }
00721 
00722    ast_mutex_lock(&dblock);
00723    db_execute_sql(a->argv[2], display_results, a);
00724    db_sync(); /* Go ahead and sync the db in case they write */
00725    ast_mutex_unlock(&dblock);
00726 
00727    return CLI_SUCCESS;
00728 }
00729 
00730 static struct ast_cli_entry cli_database[] = {
00731    AST_CLI_DEFINE(handle_cli_database_show,    "Shows database contents"),
00732    AST_CLI_DEFINE(handle_cli_database_showkey, "Shows database contents"),
00733    AST_CLI_DEFINE(handle_cli_database_get,     "Gets database value"),
00734    AST_CLI_DEFINE(handle_cli_database_put,     "Adds/updates database value"),
00735    AST_CLI_DEFINE(handle_cli_database_del,     "Removes database key/value"),
00736    AST_CLI_DEFINE(handle_cli_database_deltree, "Removes database keytree/values"),
00737    AST_CLI_DEFINE(handle_cli_database_query,   "Run a user-specified query on the astdb"),
00738 };
00739 
00740 static int manager_dbput(struct mansession *s, const struct message *m)
00741 {
00742    const char *family = astman_get_header(m, "Family");
00743    const char *key = astman_get_header(m, "Key");
00744    const char *val = astman_get_header(m, "Val");
00745    int res;
00746 
00747    if (ast_strlen_zero(family)) {
00748       astman_send_error(s, m, "No family specified");
00749       return 0;
00750    }
00751    if (ast_strlen_zero(key)) {
00752       astman_send_error(s, m, "No key specified");
00753       return 0;
00754    }
00755 
00756    res = ast_db_put(family, key, S_OR(val, ""));
00757    if (res) {
00758       astman_send_error(s, m, "Failed to update entry");
00759    } else {
00760       astman_send_ack(s, m, "Updated database successfully");
00761    }
00762    return 0;
00763 }
00764 
00765 static int manager_dbget(struct mansession *s, const struct message *m)
00766 {
00767    const char *id = astman_get_header(m,"ActionID");
00768    char idText[256] = "";
00769    const char *family = astman_get_header(m, "Family");
00770    const char *key = astman_get_header(m, "Key");
00771    char tmp[MAX_DB_FIELD];
00772    int res;
00773 
00774    if (ast_strlen_zero(family)) {
00775       astman_send_error(s, m, "No family specified.");
00776       return 0;
00777    }
00778    if (ast_strlen_zero(key)) {
00779       astman_send_error(s, m, "No key specified.");
00780       return 0;
00781    }
00782 
00783    if (!ast_strlen_zero(id))
00784       snprintf(idText, sizeof(idText) ,"ActionID: %s\r\n", id);
00785 
00786    res = ast_db_get(family, key, tmp, sizeof(tmp));
00787    if (res) {
00788       astman_send_error(s, m, "Database entry not found");
00789    } else {
00790       astman_send_ack(s, m, "Result will follow");
00791       astman_append(s, "Event: DBGetResponse\r\n"
00792             "Family: %s\r\n"
00793             "Key: %s\r\n"
00794             "Val: %s\r\n"
00795             "%s"
00796             "\r\n",
00797             family, key, tmp, idText);
00798       astman_append(s, "Event: DBGetComplete\r\n"
00799             "%s"
00800             "\r\n",
00801             idText);
00802    }
00803    return 0;
00804 }
00805 
00806 static int manager_dbdel(struct mansession *s, const struct message *m)
00807 {
00808    const char *family = astman_get_header(m, "Family");
00809    const char *key = astman_get_header(m, "Key");
00810    int res;
00811 
00812    if (ast_strlen_zero(family)) {
00813       astman_send_error(s, m, "No family specified.");
00814       return 0;
00815    }
00816 
00817    if (ast_strlen_zero(key)) {
00818       astman_send_error(s, m, "No key specified.");
00819       return 0;
00820    }
00821 
00822    res = ast_db_del(family, key);
00823    if (res)
00824       astman_send_error(s, m, "Database entry not found");
00825    else
00826       astman_send_ack(s, m, "Key deleted successfully");
00827 
00828    return 0;
00829 }
00830 
00831 static int manager_dbdeltree(struct mansession *s, const struct message *m)
00832 {
00833    const char *family = astman_get_header(m, "Family");
00834    const char *key = astman_get_header(m, "Key");
00835    int res;
00836 
00837    if (ast_strlen_zero(family)) {
00838       astman_send_error(s, m, "No family specified.");
00839       return 0;
00840    }
00841 
00842    if (!ast_strlen_zero(key))
00843       res = ast_db_deltree(family, key);
00844    else
00845       res = ast_db_deltree(family, NULL);
00846 
00847    if (res <= 0)
00848       astman_send_error(s, m, "Database entry not found");
00849    else
00850       astman_send_ack(s, m, "Key tree deleted successfully");
00851 
00852    return 0;
00853 }
00854 
00855 /*!
00856  * \internal
00857  * \brief Signal the astdb sync thread to do its thing.
00858  *
00859  * \note dblock is assumed to be held when calling this function.
00860  */
00861 static void db_sync(void)
00862 {
00863    ast_cond_signal(&dbcond);
00864 }
00865 
00866 /*!
00867  * \internal
00868  * \brief astdb sync thread
00869  *
00870  * This thread is in charge of syncing astdb to disk after a change.
00871  * By pushing it off to this thread to take care of, this I/O bound operation
00872  * will not block other threads from performing other critical processing.
00873  * If changes happen rapidly, this thread will also ensure that the sync
00874  * operations are rate limited.
00875  */
00876 static void *db_sync_thread(void *data)
00877 {
00878    ast_mutex_lock(&dblock);
00879    ast_db_begin_transaction();
00880    for (;;) {
00881       /* We're ok with spurious wakeups, so we don't worry about a predicate */
00882       ast_cond_wait(&dbcond, &dblock);
00883       if (ast_db_commit_transaction()) {
00884          ast_db_rollback_transaction();
00885       }
00886       if (doexit) {
00887          ast_mutex_unlock(&dblock);
00888          break;
00889       }
00890       ast_db_begin_transaction();
00891       ast_mutex_unlock(&dblock);
00892       sleep(1);
00893       ast_mutex_lock(&dblock);
00894       /* Unfortunately, it is possible for signaling to happen
00895        * when we're not waiting: in the bit when we're unlocked
00896        * above. Do the do-exit check here again. (We could do
00897        * it once, but that would impose a forced delay of 1
00898        * second always.) */
00899       if (doexit) {
00900          ast_mutex_unlock(&dblock);
00901          break;
00902       }
00903    }
00904 
00905    return NULL;
00906 }
00907 
00908 static void astdb_atexit(void)
00909 {
00910    /* Set doexit to 1 to kill thread. db_sync must be called with
00911     * mutex held. */
00912    doexit = 1;
00913    ast_mutex_lock(&dblock);
00914    db_sync();
00915    ast_mutex_unlock(&dblock);
00916 
00917    pthread_join(syncthread, NULL);
00918    ast_mutex_lock(&dblock);
00919    sqlite3_close(astdb);
00920    ast_mutex_unlock(&dblock);
00921 }
00922 
00923 int astdb_init(void)
00924 {
00925    if (db_init()) {
00926       return -1;
00927    }
00928 
00929    ast_cond_init(&dbcond, NULL);
00930    if (ast_pthread_create_background(&syncthread, NULL, db_sync_thread, NULL)) {
00931       return -1;
00932    }
00933 
00934    ast_register_atexit(astdb_atexit);
00935    ast_cli_register_multiple(cli_database, ARRAY_LEN(cli_database));
00936    ast_manager_register_xml("DBGet", EVENT_FLAG_SYSTEM | EVENT_FLAG_REPORTING, manager_dbget);
00937    ast_manager_register_xml("DBPut", EVENT_FLAG_SYSTEM, manager_dbput);
00938    ast_manager_register_xml("DBDel", EVENT_FLAG_SYSTEM, manager_dbdel);
00939    ast_manager_register_xml("DBDelTree", EVENT_FLAG_SYSTEM, manager_dbdeltree);
00940    return 0;
00941 }

Generated on Sat Feb 11 06:33:14 2012 for Asterisk - The Open Source Telephony Project by  doxygen 1.5.6