Sat Sep 16 05:47:45 2006

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

Generated on Sat Sep 16 05:47:45 2006 for Asterisk - the Open Source PBX by  doxygen 1.4.7