Mon May 14 04:42:55 2007

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$")
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/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\n");
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       ast_log(LOG_DEBUG, "Unable to find key '%s' in family '%s'\n", keys, family);
00198    } else {
00199 #if 0
00200       printf("Got value of size %d\n", data.size);
00201 #endif
00202       if (data.size) {
00203          ((char *)data.data)[data.size - 1] = '\0';
00204          /* Make sure that we don't write too much to the dst pointer or we don't read too much from the source pointer */
00205          ast_copy_string(value, data.data, (valuelen > data.size) ? data.size : valuelen);
00206       } else {
00207          ast_log(LOG_NOTICE, "Strange, empty value for /%s/%s\n", family, keys);
00208       }
00209    }
00210    return res;
00211 }
00212 
00213 int ast_db_del(const char *family, const char *keys)
00214 {
00215    char fullkey[256];
00216    DBT key;
00217    int res, fullkeylen;
00218 
00219    ast_mutex_lock(&dblock);
00220    if (dbinit()) {
00221       ast_mutex_unlock(&dblock);
00222       return -1;
00223    }
00224    
00225    fullkeylen = snprintf(fullkey, sizeof(fullkey), "/%s/%s", family, keys);
00226    memset(&key, 0, sizeof(key));
00227    key.data = fullkey;
00228    key.size = fullkeylen + 1;
00229    
00230    res = astdb->del(astdb, &key, 0);
00231    astdb->sync(astdb, 0);
00232    
00233    ast_mutex_unlock(&dblock);
00234 
00235    if (res) 
00236       ast_log(LOG_DEBUG, "Unable to find key '%s' in family '%s'\n", keys, family);
00237    return res;
00238 }
00239 
00240 static int database_put(int fd, int argc, char *argv[])
00241 {
00242    int res;
00243    if (argc != 5)
00244       return RESULT_SHOWUSAGE;
00245    res = ast_db_put(argv[2], argv[3], argv[4]);
00246    if (res)  {
00247       ast_cli(fd, "Failed to update entry\n");
00248    } else {
00249       ast_cli(fd, "Updated database successfully\n");
00250    }
00251    return RESULT_SUCCESS;
00252 }
00253 
00254 static int database_get(int fd, int argc, char *argv[])
00255 {
00256    int res;
00257    char tmp[256];
00258    if (argc != 4)
00259       return RESULT_SHOWUSAGE;
00260    res = ast_db_get(argv[2], argv[3], tmp, sizeof(tmp));
00261    if (res) {
00262       ast_cli(fd, "Database entry not found.\n");
00263    } else {
00264       ast_cli(fd, "Value: %s\n", tmp);
00265    }
00266    return RESULT_SUCCESS;
00267 }
00268 
00269 static int database_del(int fd, int argc, char *argv[])
00270 {
00271    int res;
00272    if (argc != 4)
00273       return RESULT_SHOWUSAGE;
00274    res = ast_db_del(argv[2], argv[3]);
00275    if (res) {
00276       ast_cli(fd, "Database entry does not exist.\n");
00277    } else {
00278       ast_cli(fd, "Database entry removed.\n");
00279    }
00280    return RESULT_SUCCESS;
00281 }
00282 
00283 static int database_deltree(int fd, int argc, char *argv[])
00284 {
00285    int res;
00286    if ((argc < 3) || (argc > 4))
00287       return RESULT_SHOWUSAGE;
00288    if (argc == 4) {
00289       res = ast_db_deltree(argv[2], argv[3]);
00290    } else {
00291       res = ast_db_deltree(argv[2], NULL);
00292    }
00293    if (res) {
00294       ast_cli(fd, "Database entries do not exist.\n");
00295    } else {
00296       ast_cli(fd, "Database entries removed.\n");
00297    }
00298    return RESULT_SUCCESS;
00299 }
00300 
00301 static int database_show(int fd, int argc, char *argv[])
00302 {
00303    char prefix[256];
00304    DBT key, data;
00305    char *keys, *values;
00306    int res;
00307    int pass;
00308 
00309    if (argc == 4) {
00310       /* Family and key tree */
00311       snprintf(prefix, sizeof(prefix), "/%s/%s", argv[2], argv[3]);
00312    } else if (argc == 3) {
00313       /* Family only */
00314       snprintf(prefix, sizeof(prefix), "/%s", argv[2]);
00315    } else if (argc == 2) {
00316       /* Neither */
00317       prefix[0] = '\0';
00318    } else {
00319       return RESULT_SHOWUSAGE;
00320    }
00321    ast_mutex_lock(&dblock);
00322    if (dbinit()) {
00323       ast_mutex_unlock(&dblock);
00324       ast_cli(fd, "Database unavailable\n");
00325       return RESULT_SUCCESS;  
00326    }
00327    memset(&key, 0, sizeof(key));
00328    memset(&data, 0, sizeof(data));
00329    pass = 0;
00330    while (!(res = astdb->seq(astdb, &key, &data, pass++ ? R_NEXT : R_FIRST))) {
00331       if (key.size) {
00332          keys = key.data;
00333          keys[key.size - 1] = '\0';
00334       } else {
00335          keys = "<bad key>";
00336       }
00337       if (data.size) {
00338          values = data.data;
00339          values[data.size - 1]='\0';
00340       } else {
00341          values = "<bad value>";
00342       }
00343       if (keymatch(keys, prefix)) {
00344             ast_cli(fd, "%-50s: %-25s\n", keys, values);
00345       }
00346    }
00347    ast_mutex_unlock(&dblock);
00348    return RESULT_SUCCESS;  
00349 }
00350 
00351 static int database_showkey(int fd, int argc, char *argv[])
00352 {
00353    char suffix[256];
00354    DBT key, data;
00355    char *keys, *values;
00356    int res;
00357    int pass;
00358 
00359    if (argc == 3) {
00360       /* Key only */
00361       snprintf(suffix, sizeof(suffix), "/%s", argv[2]);
00362    } else {
00363       return RESULT_SHOWUSAGE;
00364    }
00365    ast_mutex_lock(&dblock);
00366    if (dbinit()) {
00367       ast_mutex_unlock(&dblock);
00368       ast_cli(fd, "Database unavailable\n");
00369       return RESULT_SUCCESS;  
00370    }
00371    memset(&key, 0, sizeof(key));
00372    memset(&data, 0, sizeof(data));
00373    pass = 0;
00374    while (!(res = astdb->seq(astdb, &key, &data, pass++ ? R_NEXT : R_FIRST))) {
00375       if (key.size) {
00376          keys = key.data;
00377          keys[key.size - 1] = '\0';
00378       } else {
00379          keys = "<bad key>";
00380       }
00381       if (data.size) {
00382          values = data.data;
00383          values[data.size - 1]='\0';
00384       } else {
00385          values = "<bad value>";
00386       }
00387       if (subkeymatch(keys, suffix)) {
00388             ast_cli(fd, "%-50s: %-25s\n", keys, values);
00389       }
00390    }
00391    ast_mutex_unlock(&dblock);
00392    return RESULT_SUCCESS;  
00393 }
00394 
00395 struct ast_db_entry *ast_db_gettree(const char *family, const char *keytree)
00396 {
00397    char prefix[256];
00398    DBT key, data;
00399    char *keys, *values;
00400    int values_len;
00401    int res;
00402    int pass;
00403    struct ast_db_entry *last = NULL;
00404    struct ast_db_entry *cur, *ret=NULL;
00405 
00406    if (!ast_strlen_zero(family)) {
00407       if (!ast_strlen_zero(keytree)) {
00408          /* Family and key tree */
00409          snprintf(prefix, sizeof(prefix), "/%s/%s", family, prefix);
00410       } else {
00411          /* Family only */
00412          snprintf(prefix, sizeof(prefix), "/%s", family);
00413       }
00414    } else {
00415       prefix[0] = '\0';
00416    }
00417    ast_mutex_lock(&dblock);
00418    if (dbinit()) {
00419       ast_mutex_unlock(&dblock);
00420       ast_log(LOG_WARNING, "Database unavailable\n");
00421       return NULL;   
00422    }
00423    memset(&key, 0, sizeof(key));
00424    memset(&data, 0, sizeof(data));
00425    pass = 0;
00426    while (!(res = astdb->seq(astdb, &key, &data, pass++ ? R_NEXT : R_FIRST))) {
00427       if (key.size) {
00428          keys = key.data;
00429          keys[key.size - 1] = '\0';
00430       } else {
00431          keys = "<bad key>";
00432       }
00433       if (data.size) {
00434          values = data.data;
00435          values[data.size - 1] = '\0';
00436       } else {
00437          values = "<bad value>";
00438       }
00439       values_len = strlen(values) + 1;
00440       if (keymatch(keys, prefix) && (cur = ast_malloc(sizeof(*cur) + strlen(keys) + 1 + values_len))) {
00441          cur->next = NULL;
00442          cur->key = cur->data + values_len;
00443          strcpy(cur->data, values);
00444          strcpy(cur->key, keys);
00445          if (last) {
00446             last->next = cur;
00447          } else {
00448             ret = cur;
00449          }
00450          last = cur;
00451       }
00452    }
00453    ast_mutex_unlock(&dblock);
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       free(last);
00464    }
00465 }
00466 
00467 static char database_show_usage[] =
00468 "Usage: database show [family [keytree]]\n"
00469 "       Shows Asterisk database contents, optionally restricted\n"
00470 "to a given family, or family and keytree.\n";
00471 
00472 static char database_showkey_usage[] =
00473 "Usage: database showkey <keytree>\n"
00474 "       Shows Asterisk database contents, restricted to a given key.\n";
00475 
00476 static char database_put_usage[] =
00477 "Usage: database put <family> <key> <value>\n"
00478 "       Adds or updates an entry in the Asterisk database for\n"
00479 "a given family, key, and value.\n";
00480 
00481 static char database_get_usage[] =
00482 "Usage: database get <family> <key>\n"
00483 "       Retrieves an entry in the Asterisk database for a given\n"
00484 "family and key.\n";
00485 
00486 static char database_del_usage[] =
00487 "Usage: database del <family> <key>\n"
00488 "       Deletes an entry in the Asterisk database for a given\n"
00489 "family and key.\n";
00490 
00491 static char database_deltree_usage[] =
00492 "Usage: database deltree <family> [keytree]\n"
00493 "       Deletes a family or specific keytree within a family\n"
00494 "in the Asterisk database.\n";
00495 
00496 struct ast_cli_entry cli_database[] = {
00497    { { "database", "show", NULL },
00498    database_show, "Shows database contents",
00499    database_show_usage },
00500 
00501    { { "database", "showkey", NULL },
00502    database_showkey, "Shows database contents",
00503    database_showkey_usage },
00504 
00505    { { "database", "get", NULL },
00506    database_get, "Gets database value",
00507    database_get_usage },
00508 
00509    { { "database", "put", NULL },
00510    database_put, "Adds/updates database value",
00511    database_put_usage },
00512 
00513    { { "database", "del", NULL },
00514    database_del, "Removes database key/value",
00515    database_del_usage },
00516 
00517    { { "database", "deltree", NULL },
00518    database_deltree, "Removes database keytree/values",
00519    database_deltree_usage },
00520 };
00521 
00522 static int manager_dbput(struct mansession *s, const struct message *m)
00523 {
00524    const char *family = astman_get_header(m, "Family");
00525    const char *key = astman_get_header(m, "Key");
00526    const char *val = astman_get_header(m, "Val");
00527    int res;
00528 
00529    if (ast_strlen_zero(family)) {
00530       astman_send_error(s, m, "No family specified");
00531       return 0;
00532    }
00533    if (ast_strlen_zero(key)) {
00534       astman_send_error(s, m, "No key specified");
00535       return 0;
00536    }
00537    if (ast_strlen_zero(val)) {
00538       astman_send_error(s, m, "No val specified");
00539       return 0;
00540    }
00541 
00542    res = ast_db_put(family, key, (char *) val);
00543    if (res) {
00544       astman_send_error(s, m, "Failed to update entry");
00545    } else {
00546       astman_send_ack(s, m, "Updated database successfully");
00547    }
00548    return 0;
00549 }
00550 
00551 static int manager_dbget(struct mansession *s, const struct message *m)
00552 {
00553    const char *id = astman_get_header(m,"ActionID");
00554    char idText[256] = "";
00555    const char *family = astman_get_header(m, "Family");
00556    const char *key = astman_get_header(m, "Key");
00557    char tmp[256];
00558    int res;
00559 
00560    if (ast_strlen_zero(family)) {
00561       astman_send_error(s, m, "No family specified.");
00562       return 0;
00563    }
00564    if (ast_strlen_zero(key)) {
00565       astman_send_error(s, m, "No key specified.");
00566       return 0;
00567    }
00568 
00569    if (!ast_strlen_zero(id))
00570       snprintf(idText, sizeof(idText) ,"ActionID: %s\r\n", id);
00571 
00572    res = ast_db_get(family, key, tmp, sizeof(tmp));
00573    if (res) {
00574       astman_send_error(s, m, "Database entry not found");
00575    } else {
00576       astman_send_ack(s, m, "Result will follow");
00577       astman_append(s, "Event: DBGetResponse\r\n"
00578             "Family: %s\r\n"
00579             "Key: %s\r\n"
00580             "Val: %s\r\n"
00581             "%s"
00582             "\r\n",
00583             family, key, tmp, idText);
00584    }
00585    return 0;
00586 }
00587 
00588 int astdb_init(void)
00589 {
00590    dbinit();
00591    ast_cli_register_multiple(cli_database, sizeof(cli_database) / sizeof(struct ast_cli_entry));
00592    ast_manager_register("DBGet", EVENT_FLAG_SYSTEM, manager_dbget, "Get DB Entry");
00593    ast_manager_register("DBPut", EVENT_FLAG_SYSTEM, manager_dbput, "Put DB Entry");
00594    return 0;
00595 }

Generated on Mon May 14 04:42:55 2007 for Asterisk - the Open Source PBX by  doxygen 1.5.1