Sun Jun 12 16:37:46 2011

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: 85548 $")
00033 
00034 #include <stdio.h>
00035 #include <stdlib.h>
00036 #include <string.h>
00037 #include <sys/time.h>
00038 #include <signal.h>
00039 #include <errno.h>
00040 #include <unistd.h>
00041 #include <dirent.h>
00042 
00043 #include "asterisk/channel.h"
00044 #include "asterisk/file.h"
00045 #include "asterisk/app.h"
00046 #include "asterisk/dsp.h"
00047 #include "asterisk/logger.h"
00048 #include "asterisk/options.h"
00049 #include "asterisk/astdb.h"
00050 #include "asterisk/cli.h"
00051 #include "asterisk/utils.h"
00052 #include "asterisk/lock.h"
00053 #include "asterisk/manager.h"
00054 #include "db1-ast/include/db.h"
00055 
00056 #ifdef __CYGWIN__
00057 #define dbopen __dbopen
00058 #endif
00059 
00060 static DB *astdb;
00061 AST_MUTEX_DEFINE_STATIC(dblock);
00062 
00063 static int dbinit(void) 
00064 {
00065    if (!astdb && !(astdb = dbopen((char *)ast_config_AST_DB, O_CREAT | O_RDWR, 0664, DB_BTREE, NULL))) {
00066       ast_log(LOG_WARNING, "Unable to open Asterisk database '%s': %s\n", ast_config_AST_DB, strerror(errno));
00067       return -1;
00068    }
00069    return 0;
00070 }
00071 
00072 
00073 static inline int keymatch(const char *key, const char *prefix)
00074 {
00075    int preflen = strlen(prefix);
00076    if (!preflen)
00077       return 1;
00078    if (!strcasecmp(key, prefix))
00079       return 1;
00080    if ((strlen(key) > preflen) && !strncasecmp(key, prefix, preflen)) {
00081       if (key[preflen] == '/')
00082          return 1;
00083    }
00084    return 0;
00085 }
00086 
00087 static inline int subkeymatch(const char *key, const char *suffix)
00088 {
00089    int suffixlen = strlen(suffix);
00090    if (suffixlen) {
00091       const char *subkey = key + strlen(key) - suffixlen;
00092       if (subkey < key)
00093          return 0;
00094       if (!strcasecmp(subkey, suffix))
00095          return 1;
00096    }
00097    return 0;
00098 }
00099 
00100 int ast_db_deltree(const char *family, const char *keytree)
00101 {
00102    char prefix[256];
00103    DBT key, data;
00104    char *keys;
00105    int res;
00106    int pass;
00107    
00108    if (family) {
00109       if (keytree) {
00110          snprintf(prefix, sizeof(prefix), "/%s/%s", family, keytree);
00111       } else {
00112          snprintf(prefix, sizeof(prefix), "/%s", family);
00113       }
00114    } else if (keytree) {
00115       return -1;
00116    } else {
00117       prefix[0] = '\0';
00118    }
00119    
00120    ast_mutex_lock(&dblock);
00121    if (dbinit()) {
00122       ast_mutex_unlock(&dblock);
00123       return -1;
00124    }
00125    
00126    memset(&key, 0, sizeof(key));
00127    memset(&data, 0, sizeof(data));
00128    pass = 0;
00129    while (!(res = astdb->seq(astdb, &key, &data, pass++ ? R_NEXT : R_FIRST))) {
00130       if (key.size) {
00131          keys = key.data;
00132          keys[key.size - 1] = '\0';
00133       } else {
00134          keys = "<bad key>";
00135       }
00136       if (keymatch(keys, prefix)) {
00137          astdb->del(astdb, &key, 0);
00138       }
00139    }
00140    astdb->sync(astdb, 0);
00141    ast_mutex_unlock(&dblock);
00142    return 0;
00143 }
00144 
00145 int ast_db_put(const char *family, const char *keys, char *value)
00146 {
00147    char fullkey[256];
00148    DBT key, data;
00149    int res, fullkeylen;
00150 
00151    ast_mutex_lock(&dblock);
00152    if (dbinit()) {
00153       ast_mutex_unlock(&dblock);
00154       return -1;
00155    }
00156 
00157    fullkeylen = snprintf(fullkey, sizeof(fullkey), "/%s/%s", family, keys);
00158    memset(&key, 0, sizeof(key));
00159    memset(&data, 0, sizeof(data));
00160    key.data = fullkey;
00161    key.size = fullkeylen + 1;
00162    data.data = value;
00163    data.size = strlen(value) + 1;
00164    res = astdb->put(astdb, &key, &data, 0);
00165    astdb->sync(astdb, 0);
00166    ast_mutex_unlock(&dblock);
00167    if (res)
00168       ast_log(LOG_WARNING, "Unable to put value '%s' for key '%s' in family '%s'\n", value, keys, family);
00169    return res;
00170 }
00171 
00172 int ast_db_get(const char *family, const char *keys, char *value, int valuelen)
00173 {
00174    char fullkey[256] = "";
00175    DBT key, data;
00176    int res, fullkeylen;
00177 
00178    ast_mutex_lock(&dblock);
00179    if (dbinit()) {
00180       ast_mutex_unlock(&dblock);
00181       return -1;
00182    }
00183 
00184    fullkeylen = snprintf(fullkey, sizeof(fullkey), "/%s/%s", family, keys);
00185    memset(&key, 0, sizeof(key));
00186    memset(&data, 0, sizeof(data));
00187    memset(value, 0, valuelen);
00188    key.data = fullkey;
00189    key.size = fullkeylen + 1;
00190    
00191    res = astdb->get(astdb, &key, &data, 0);
00192    
00193    ast_mutex_unlock(&dblock);
00194 
00195    /* Be sure to NULL terminate our data either way */
00196    if (res) {
00197       if (option_debug)
00198          ast_log(LOG_DEBUG, "Unable to find key '%s' in family '%s'\n", keys, family);
00199    } else {
00200 #if 0
00201       printf("Got value of size %d\n", data.size);
00202 #endif
00203       if (data.size) {
00204          ((char *)data.data)[data.size - 1] = '\0';
00205          /* Make sure that we don't write too much to the dst pointer or we don't read too much from the source pointer */
00206          ast_copy_string(value, data.data, (valuelen > data.size) ? data.size : valuelen);
00207       } else {
00208          ast_log(LOG_NOTICE, "Strange, empty value for /%s/%s\n", family, keys);
00209       }
00210    }
00211    return res;
00212 }
00213 
00214 int ast_db_del(const char *family, const char *keys)
00215 {
00216    char fullkey[256];
00217    DBT key;
00218    int res, fullkeylen;
00219 
00220    ast_mutex_lock(&dblock);
00221    if (dbinit()) {
00222       ast_mutex_unlock(&dblock);
00223       return -1;
00224    }
00225    
00226    fullkeylen = snprintf(fullkey, sizeof(fullkey), "/%s/%s", family, keys);
00227    memset(&key, 0, sizeof(key));
00228    key.data = fullkey;
00229    key.size = fullkeylen + 1;
00230    
00231    res = astdb->del(astdb, &key, 0);
00232    astdb->sync(astdb, 0);
00233    
00234    ast_mutex_unlock(&dblock);
00235 
00236    if (res && option_debug)
00237       ast_log(LOG_DEBUG, "Unable to find key '%s' in family '%s'\n", keys, family);
00238    return res;
00239 }
00240 
00241 static int database_put(int fd, int argc, char *argv[])
00242 {
00243    int res;
00244    if (argc != 5)
00245       return RESULT_SHOWUSAGE;
00246    res = ast_db_put(argv[2], argv[3], argv[4]);
00247    if (res)  {
00248       ast_cli(fd, "Failed to update entry\n");
00249    } else {
00250       ast_cli(fd, "Updated database successfully\n");
00251    }
00252    return RESULT_SUCCESS;
00253 }
00254 
00255 static int database_get(int fd, int argc, char *argv[])
00256 {
00257    int res;
00258    char tmp[256];
00259    if (argc != 4)
00260       return RESULT_SHOWUSAGE;
00261    res = ast_db_get(argv[2], argv[3], tmp, sizeof(tmp));
00262    if (res) {
00263       ast_cli(fd, "Database entry not found.\n");
00264    } else {
00265       ast_cli(fd, "Value: %s\n", tmp);
00266    }
00267    return RESULT_SUCCESS;
00268 }
00269 
00270 static int database_del(int fd, int argc, char *argv[])
00271 {
00272    int res;
00273    if (argc != 4)
00274       return RESULT_SHOWUSAGE;
00275    res = ast_db_del(argv[2], argv[3]);
00276    if (res) {
00277       ast_cli(fd, "Database entry does not exist.\n");
00278    } else {
00279       ast_cli(fd, "Database entry removed.\n");
00280    }
00281    return RESULT_SUCCESS;
00282 }
00283 
00284 static int database_deltree(int fd, int argc, char *argv[])
00285 {
00286    int res;
00287    if ((argc < 3) || (argc > 4))
00288       return RESULT_SHOWUSAGE;
00289    if (argc == 4) {
00290       res = ast_db_deltree(argv[2], argv[3]);
00291    } else {
00292       res = ast_db_deltree(argv[2], NULL);
00293    }
00294    if (res) {
00295       ast_cli(fd, "Database entries do not exist.\n");
00296    } else {
00297       ast_cli(fd, "Database entries removed.\n");
00298    }
00299    return RESULT_SUCCESS;
00300 }
00301 
00302 static int database_show(int fd, int argc, char *argv[])
00303 {
00304    char prefix[256];
00305    DBT key, data;
00306    char *keys, *values;
00307    int res;
00308    int pass;
00309 
00310    if (argc == 4) {
00311       /* Family and key tree */
00312       snprintf(prefix, sizeof(prefix), "/%s/%s", argv[2], argv[3]);
00313    } else if (argc == 3) {
00314       /* Family only */
00315       snprintf(prefix, sizeof(prefix), "/%s", argv[2]);
00316    } else if (argc == 2) {
00317       /* Neither */
00318       prefix[0] = '\0';
00319    } else {
00320       return RESULT_SHOWUSAGE;
00321    }
00322    ast_mutex_lock(&dblock);
00323    if (dbinit()) {
00324       ast_mutex_unlock(&dblock);
00325       ast_cli(fd, "Database unavailable\n");
00326       return RESULT_SUCCESS;  
00327    }
00328    memset(&key, 0, sizeof(key));
00329    memset(&data, 0, sizeof(data));
00330    pass = 0;
00331    while (!(res = astdb->seq(astdb, &key, &data, pass++ ? R_NEXT : R_FIRST))) {
00332       if (key.size) {
00333          keys = key.data;
00334          keys[key.size - 1] = '\0';
00335       } else {
00336          keys = "<bad key>";
00337       }
00338       if (data.size) {
00339          values = data.data;
00340          values[data.size - 1]='\0';
00341       } else {
00342          values = "<bad value>";
00343       }
00344       if (keymatch(keys, prefix)) {
00345             ast_cli(fd, "%-50s: %-25s\n", keys, values);
00346       }
00347    }
00348    ast_mutex_unlock(&dblock);
00349    return RESULT_SUCCESS;  
00350 }
00351 
00352 static int database_showkey(int fd, int argc, char *argv[])
00353 {
00354    char suffix[256];
00355    DBT key, data;
00356    char *keys, *values;
00357    int res;
00358    int pass;
00359 
00360    if (argc == 3) {
00361       /* Key only */
00362       snprintf(suffix, sizeof(suffix), "/%s", argv[2]);
00363    } else {
00364       return RESULT_SHOWUSAGE;
00365    }
00366    ast_mutex_lock(&dblock);
00367    if (dbinit()) {
00368       ast_mutex_unlock(&dblock);
00369       ast_cli(fd, "Database unavailable\n");
00370       return RESULT_SUCCESS;  
00371    }
00372    memset(&key, 0, sizeof(key));
00373    memset(&data, 0, sizeof(data));
00374    pass = 0;
00375    while (!(res = astdb->seq(astdb, &key, &data, pass++ ? R_NEXT : R_FIRST))) {
00376       if (key.size) {
00377          keys = key.data;
00378          keys[key.size - 1] = '\0';
00379       } else {
00380          keys = "<bad key>";
00381       }
00382       if (data.size) {
00383          values = data.data;
00384          values[data.size - 1]='\0';
00385       } else {
00386          values = "<bad value>";
00387       }
00388       if (subkeymatch(keys, suffix)) {
00389             ast_cli(fd, "%-50s: %-25s\n", keys, values);
00390       }
00391    }
00392    ast_mutex_unlock(&dblock);
00393    return RESULT_SUCCESS;  
00394 }
00395 
00396 struct ast_db_entry *ast_db_gettree(const char *family, const char *keytree)
00397 {
00398    char prefix[256];
00399    DBT key, data;
00400    char *keys, *values;
00401    int values_len;
00402    int res;
00403    int pass;
00404    struct ast_db_entry *last = NULL;
00405    struct ast_db_entry *cur, *ret=NULL;
00406 
00407    if (!ast_strlen_zero(family)) {
00408       if (!ast_strlen_zero(keytree)) {
00409          /* Family and key tree */
00410          snprintf(prefix, sizeof(prefix), "/%s/%s", family, prefix);
00411       } else {
00412          /* Family only */
00413          snprintf(prefix, sizeof(prefix), "/%s", family);
00414       }
00415    } else {
00416       prefix[0] = '\0';
00417    }
00418    ast_mutex_lock(&dblock);
00419    if (dbinit()) {
00420       ast_mutex_unlock(&dblock);
00421       ast_log(LOG_WARNING, "Database unavailable\n");
00422       return NULL;   
00423    }
00424    memset(&key, 0, sizeof(key));
00425    memset(&data, 0, sizeof(data));
00426    pass = 0;
00427    while (!(res = astdb->seq(astdb, &key, &data, pass++ ? R_NEXT : R_FIRST))) {
00428       if (key.size) {
00429          keys = key.data;
00430          keys[key.size - 1] = '\0';
00431       } else {
00432          keys = "<bad key>";
00433       }
00434       if (data.size) {
00435          values = data.data;
00436          values[data.size - 1] = '\0';
00437       } else {
00438          values = "<bad value>";
00439       }
00440       values_len = strlen(values) + 1;
00441       if (keymatch(keys, prefix) && (cur = ast_malloc(sizeof(*cur) + strlen(keys) + 1 + values_len))) {
00442          cur->next = NULL;
00443          cur->key = cur->data + values_len;
00444          strcpy(cur->data, values);
00445          strcpy(cur->key, keys);
00446          if (last) {
00447             last->next = cur;
00448          } else {
00449             ret = cur;
00450          }
00451          last = cur;
00452       }
00453    }
00454    ast_mutex_unlock(&dblock);
00455    return ret; 
00456 }
00457 
00458 void ast_db_freetree(struct ast_db_entry *dbe)
00459 {
00460    struct ast_db_entry *last;
00461    while (dbe) {
00462       last = dbe;
00463       dbe = dbe->next;
00464       free(last);
00465    }
00466 }
00467 
00468 static char database_show_usage[] =
00469 "Usage: database show [family [keytree]]\n"
00470 "       Shows Asterisk database contents, optionally restricted\n"
00471 "to a given family, or family and keytree.\n";
00472 
00473 static char database_showkey_usage[] =
00474 "Usage: database showkey <keytree>\n"
00475 "       Shows Asterisk database contents, restricted to a given key.\n";
00476 
00477 static char database_put_usage[] =
00478 "Usage: database put <family> <key> <value>\n"
00479 "       Adds or updates an entry in the Asterisk database for\n"
00480 "a given family, key, and value.\n";
00481 
00482 static char database_get_usage[] =
00483 "Usage: database get <family> <key>\n"
00484 "       Retrieves an entry in the Asterisk database for a given\n"
00485 "family and key.\n";
00486 
00487 static char database_del_usage[] =
00488 "Usage: database del <family> <key>\n"
00489 "       Deletes an entry in the Asterisk database for a given\n"
00490 "family and key.\n";
00491 
00492 static char database_deltree_usage[] =
00493 "Usage: database deltree <family> [keytree]\n"
00494 "       Deletes a family or specific keytree within a family\n"
00495 "in the Asterisk database.\n";
00496 
00497 struct ast_cli_entry cli_database[] = {
00498    { { "database", "show", NULL },
00499    database_show, "Shows database contents",
00500    database_show_usage },
00501 
00502    { { "database", "showkey", NULL },
00503    database_showkey, "Shows database contents",
00504    database_showkey_usage },
00505 
00506    { { "database", "get", NULL },
00507    database_get, "Gets database value",
00508    database_get_usage },
00509 
00510    { { "database", "put", NULL },
00511    database_put, "Adds/updates database value",
00512    database_put_usage },
00513 
00514    { { "database", "del", NULL },
00515    database_del, "Removes database key/value",
00516    database_del_usage },
00517 
00518    { { "database", "deltree", NULL },
00519    database_deltree, "Removes database keytree/values",
00520    database_deltree_usage },
00521 };
00522 
00523 static int manager_dbput(struct mansession *s, const struct message *m)
00524 {
00525    const char *family = astman_get_header(m, "Family");
00526    const char *key = astman_get_header(m, "Key");
00527    const char *val = astman_get_header(m, "Val");
00528    int res;
00529 
00530    if (ast_strlen_zero(family)) {
00531       astman_send_error(s, m, "No family specified");
00532       return 0;
00533    }
00534    if (ast_strlen_zero(key)) {
00535       astman_send_error(s, m, "No key specified");
00536       return 0;
00537    }
00538 
00539    res = ast_db_put(family, key, (char *) S_OR(val, ""));
00540    if (res) {
00541       astman_send_error(s, m, "Failed to update entry");
00542    } else {
00543       astman_send_ack(s, m, "Updated database successfully");
00544    }
00545    return 0;
00546 }
00547 
00548 static int manager_dbget(struct mansession *s, const struct message *m)
00549 {
00550    const char *id = astman_get_header(m,"ActionID");
00551    char idText[256] = "";
00552    const char *family = astman_get_header(m, "Family");
00553    const char *key = astman_get_header(m, "Key");
00554    char tmp[256];
00555    int res;
00556 
00557    if (ast_strlen_zero(family)) {
00558       astman_send_error(s, m, "No family specified.");
00559       return 0;
00560    }
00561    if (ast_strlen_zero(key)) {
00562       astman_send_error(s, m, "No key specified.");
00563       return 0;
00564    }
00565 
00566    if (!ast_strlen_zero(id))
00567       snprintf(idText, sizeof(idText) ,"ActionID: %s\r\n", id);
00568 
00569    res = ast_db_get(family, key, tmp, sizeof(tmp));
00570    if (res) {
00571       astman_send_error(s, m, "Database entry not found");
00572    } else {
00573       astman_send_ack(s, m, "Result will follow");
00574       astman_append(s, "Event: DBGetResponse\r\n"
00575             "Family: %s\r\n"
00576             "Key: %s\r\n"
00577             "Value: %s\r\n"
00578             "%s"
00579             "\r\n",
00580             family, key, tmp, idText);
00581    }
00582    return 0;
00583 }
00584 
00585 static int manager_dbdel(struct mansession *s, const struct message *m)
00586 {
00587         const char *family = astman_get_header(m, "Family");
00588         const char *key = astman_get_header(m, "Key");
00589 
00590    if (!strlen(family)) {
00591       astman_send_error(s, m, "No family specified");
00592       return 0;
00593    }
00594    if (!strlen(key)) {
00595       astman_send_error(s, m, "No key specified");
00596       return 0;
00597    }
00598 
00599    if (ast_db_del(family, key)) {
00600        astman_send_error(s, m, "Failed to delete entry");
00601    } else {
00602        astman_send_ack(s, m, "Deleted entry successfully");
00603    }
00604 
00605    return 0;
00606 }
00607 
00608 int astdb_init(void)
00609 {
00610    dbinit();
00611    ast_cli_register_multiple(cli_database, sizeof(cli_database) / sizeof(struct ast_cli_entry));
00612    ast_manager_register("DBget", EVENT_FLAG_SYSTEM, manager_dbget, "Get DB Entry");
00613    ast_manager_register("DBput", EVENT_FLAG_SYSTEM, manager_dbput, "Put DB Entry");
00614    ast_manager_register("DBdel", EVENT_FLAG_SYSTEM, manager_dbdel, "Delete DB Entry");
00615    return 0;
00616 }

Generated on Sun Jun 12 16:37:46 2011 for Asterisk - the Open Source PBX by  doxygen 1.5.6