Main Page | Alphabetical List | Data Structures | Directories | File List | Data Fields | Globals

db.c

Go to the documentation of this file.
00001 /*
00002  * Asterisk -- A telephony toolkit for Linux.
00003  *
00004  * Channel Management
00005  * 
00006  * Copyright (C) 1999, Mark Spencer
00007  *
00008  * Mark Spencer <markster@linux-support.net>
00009  *
00010  * This program is free software, distributed under the terms of
00011  * the GNU General Public License
00012  */
00013 
00014 /* DB3 is licensed under Sleepycat Public License and is thus incompatible
00015    with GPL.  To avoid having to make another exception (and complicate 
00016    licensing even further) we elect to use DB1 which is BSD licensed */
00017 
00018 #include <stdio.h>
00019 #include <stdlib.h>
00020 #include <string.h>
00021 #include <sys/time.h>
00022 #include <signal.h>
00023 #include <errno.h>
00024 #include <unistd.h>
00025 #include <dirent.h>
00026 #include <asterisk/channel.h>
00027 #include <asterisk/file.h>
00028 #include <asterisk/app.h>
00029 #include <asterisk/dsp.h>
00030 #include <asterisk/logger.h>
00031 #include <asterisk/options.h>
00032 #include <asterisk/astdb.h>
00033 #include <asterisk/cli.h>
00034 #include <asterisk/utils.h>
00035 #include <asterisk/lock.h>
00036 #include "db1-ast/include/db.h"
00037 #include "asterisk.h"
00038 #include "astconf.h"
00039 
00040 static DB *astdb;
00041 AST_MUTEX_DEFINE_STATIC(dblock);
00042 
00043 static int dbinit(void) 
00044 {
00045    if (!astdb) {
00046       if (!(astdb = dbopen((char *)ast_config_AST_DB, O_CREAT | O_RDWR, 0664, DB_BTREE, NULL))) {
00047          ast_log(LOG_WARNING, "Unable to open Asterisk database\n");
00048       }
00049    }
00050    if (astdb)
00051       return 0;
00052    return -1;
00053 }
00054 
00055 
00056 static inline int keymatch(const char *key, const char *prefix)
00057 {
00058    int preflen = strlen(prefix);
00059    if (!preflen)
00060       return 1;
00061    if (!strcasecmp(key, prefix))
00062       return 1;
00063    if ((strlen(key) > preflen) &&
00064       !strncasecmp(key, prefix, preflen)) {
00065       if (key[preflen] == '/')
00066          return 1;
00067    }
00068    return 0;
00069 }
00070 
00071 int ast_db_deltree(const char *family, const char *keytree)
00072 {
00073    char prefix[256];
00074    DBT key, data;
00075    char *keys;
00076    int res;
00077    int pass;
00078    
00079    if (family) {
00080       if (keytree)
00081          snprintf(prefix, sizeof(prefix), "/%s/%s", family, keytree);
00082       else
00083          snprintf(prefix, sizeof(prefix), "/%s", family);
00084    } else if (keytree)
00085       return -1;
00086    else
00087       prefix[0] = '\0';
00088    
00089    ast_mutex_lock(&dblock);
00090    if (dbinit()) 
00091       return -1;
00092    
00093    memset(&key, 0, sizeof(key));
00094    memset(&data, 0, sizeof(data));
00095    pass = 0;
00096    while(!(res = astdb->seq(astdb, &key, &data, pass++ ? R_NEXT : R_FIRST))) {
00097       if (key.size) {
00098          keys = key.data;
00099          keys[key.size - 1] = '\0';
00100       } else
00101          keys = "<bad key>";
00102       if (keymatch(keys, prefix)) {
00103          astdb->del(astdb, &key, 0);
00104       }
00105    }
00106    astdb->sync(astdb, 0);
00107    ast_mutex_unlock(&dblock);
00108    return 0;
00109 }
00110 
00111 int ast_db_put(const char *family, const char *keys, char *value)
00112 {
00113    char fullkey[256];
00114    DBT key, data;
00115    int res, fullkeylen;
00116 
00117    ast_mutex_lock(&dblock);
00118    if (dbinit()) {
00119       ast_mutex_unlock(&dblock);
00120       return -1;
00121    }
00122 
00123    fullkeylen = snprintf(fullkey, sizeof(fullkey), "/%s/%s", family, keys);
00124    memset(&key, 0, sizeof(key));
00125    memset(&data, 0, sizeof(data));
00126    key.data = fullkey;
00127    key.size = fullkeylen + 1;
00128    data.data = value;
00129    data.size = strlen(value) + 1;
00130    res = astdb->put(astdb, &key, &data, 0);
00131    astdb->sync(astdb, 0);
00132    ast_mutex_unlock(&dblock);
00133    if (res)
00134       ast_log(LOG_WARNING, "Unable to put value '%s' for key '%s' in family '%s'\n", value, keys, family);
00135    return res;
00136 }
00137 
00138 int ast_db_get(const char *family, const char *keys, char *value, int valuelen)
00139 {
00140    char fullkey[256]="";
00141    DBT key, data;
00142    int res, fullkeylen;
00143 
00144    ast_mutex_lock(&dblock);
00145    if (dbinit()) {
00146       ast_mutex_unlock(&dblock);
00147       return -1;
00148    }
00149 
00150    fullkeylen = snprintf(fullkey, sizeof(fullkey), "/%s/%s", family, keys);
00151    memset(&key, 0, sizeof(key));
00152    memset(&data, 0, sizeof(data));
00153    memset(value, 0, valuelen);
00154    key.data = fullkey;
00155    key.size = fullkeylen + 1;
00156    
00157    res = astdb->get(astdb, &key, &data, 0);
00158    
00159    ast_mutex_unlock(&dblock);
00160 
00161    /* Be sure to NULL terminate our data either way */
00162    if (res) {
00163       ast_log(LOG_DEBUG, "Unable to find key '%s' in family '%s'\n", keys, family);
00164    } else {
00165 #if 0
00166       printf("Got value of size %d\n", data.size);
00167 #endif
00168       if (data.size) {
00169          ((char *)data.data)[data.size - 1] = '\0';
00170          /* Make sure that we don't write too much to the dst pointer or we don't read too much from the source pointer */
00171          strncpy(value, data.data, (valuelen > data.size) ? data.size : valuelen);
00172          value[valuelen - 1] = '\0';
00173       } else {
00174          ast_log(LOG_NOTICE, "Strange, empty value for /%s/%s\n", family, keys);
00175       }
00176    }
00177    return res;
00178 }
00179 
00180 int ast_db_del(const char *family, const char *keys)
00181 {
00182    char fullkey[256];
00183    DBT key;
00184    int res, fullkeylen;
00185 
00186    ast_mutex_lock(&dblock);
00187    if (dbinit()) {
00188       ast_mutex_unlock(&dblock);
00189       return -1;
00190    }
00191    
00192    fullkeylen = snprintf(fullkey, sizeof(fullkey), "/%s/%s", family, keys);
00193    memset(&key, 0, sizeof(key));
00194    key.data = fullkey;
00195    key.size = fullkeylen + 1;
00196    
00197    res = astdb->del(astdb, &key, 0);
00198    astdb->sync(astdb, 0);
00199    
00200    ast_mutex_unlock(&dblock);
00201 
00202    if (res) 
00203       ast_log(LOG_DEBUG, "Unable to find key '%s' in family '%s'\n", keys, family);
00204    return res;
00205 }
00206 
00207 static int database_put(int fd, int argc, char *argv[])
00208 {
00209    int res;
00210    if (argc != 5)
00211       return RESULT_SHOWUSAGE;
00212    res = ast_db_put(argv[2], argv[3], argv[4]);
00213    if (res) 
00214       ast_cli(fd, "Failed to update entry\n");
00215    else
00216       ast_cli(fd, "Updated database successfully\n");
00217    return RESULT_SUCCESS;
00218 }
00219 
00220 static int database_get(int fd, int argc, char *argv[])
00221 {
00222    int res;
00223    char tmp[256];
00224    if (argc != 4)
00225       return RESULT_SHOWUSAGE;
00226    res = ast_db_get(argv[2], argv[3], tmp, sizeof(tmp));
00227    if (res) 
00228       ast_cli(fd, "Database entry not found.\n");
00229    else
00230       ast_cli(fd, "Value: %s\n", tmp);
00231    return RESULT_SUCCESS;
00232 }
00233 
00234 static int database_del(int fd, int argc, char *argv[])
00235 {
00236    int res;
00237    if (argc != 4)
00238       return RESULT_SHOWUSAGE;
00239    res = ast_db_del(argv[2], argv[3]);
00240    if (res) 
00241       ast_cli(fd, "Database entry does not exist.\n");
00242    else
00243       ast_cli(fd, "Database entry removed.\n");
00244    return RESULT_SUCCESS;
00245 }
00246 
00247 static int database_deltree(int fd, int argc, char *argv[])
00248 {
00249    int res;
00250    if ((argc < 3) || (argc > 4))
00251       return RESULT_SHOWUSAGE;
00252    if (argc == 4)
00253       res = ast_db_deltree(argv[2], argv[3]);
00254    else
00255       res = ast_db_deltree(argv[2], NULL);
00256    if (res) 
00257       ast_cli(fd, "Database entries do not exist.\n");
00258    else
00259       ast_cli(fd, "Database entries removed.\n");
00260    return RESULT_SUCCESS;
00261 }
00262 
00263 static int database_show(int fd, int argc, char *argv[])
00264 {
00265    char prefix[256];
00266    DBT key, data;
00267    char *keys, *values;
00268    int res;
00269    int pass;
00270 
00271    if (argc == 4) {
00272       /* Family and key tree */
00273       snprintf(prefix, sizeof(prefix), "/%s/%s", argv[2], argv[3]);
00274    } else if (argc == 3) {
00275       /* Family only */
00276       snprintf(prefix, sizeof(prefix), "/%s", argv[2]);
00277    } else if (argc == 2) {
00278       /* Neither */
00279       prefix[0] = '\0';
00280    } else
00281       return RESULT_SHOWUSAGE;
00282    ast_mutex_lock(&dblock);
00283    if (dbinit()) {
00284       ast_mutex_unlock(&dblock);
00285       ast_cli(fd, "Database unavailable\n");
00286       return RESULT_SUCCESS;  
00287    }
00288    memset(&key, 0, sizeof(key));
00289    memset(&data, 0, sizeof(data));
00290    pass = 0;
00291    while(!(res = astdb->seq(astdb, &key, &data, pass++ ? R_NEXT : R_FIRST))) {
00292       if (key.size) {
00293          keys = key.data;
00294          keys[key.size - 1] = '\0';
00295       } else
00296          keys = "<bad key>";
00297       if (data.size) {
00298          values = data.data;
00299          values[data.size - 1]='\0';
00300       } else
00301          values = "<bad value>";
00302       if (keymatch(keys, prefix)) {
00303             ast_cli(fd, "%-50s: %-25s\n", keys, values);
00304       }
00305    }
00306    ast_mutex_unlock(&dblock);
00307    return RESULT_SUCCESS;  
00308 }
00309 
00310 struct ast_db_entry *ast_db_gettree(const char *family, const char *keytree)
00311 {
00312    char prefix[256];
00313    DBT key, data;
00314    char *keys, *values;
00315    int res;
00316    int pass;
00317    struct ast_db_entry *last = NULL;
00318    struct ast_db_entry *cur, *ret=NULL;
00319 
00320    if (family && !ast_strlen_zero(family)) {
00321       if (keytree && !ast_strlen_zero(keytree))
00322          /* Family and key tree */
00323          snprintf(prefix, sizeof(prefix), "/%s/%s", family, prefix);
00324       else
00325          /* Family only */
00326          snprintf(prefix, sizeof(prefix), "/%s", family);
00327    } else
00328       prefix[0] = '\0';
00329    ast_mutex_lock(&dblock);
00330    if (dbinit()) {
00331       ast_mutex_unlock(&dblock);
00332       ast_log(LOG_WARNING, "Database unavailable\n");
00333       return NULL;   
00334    }
00335    memset(&key, 0, sizeof(key));
00336    memset(&data, 0, sizeof(data));
00337    pass = 0;
00338    while(!(res = astdb->seq(astdb, &key, &data, pass++ ? R_NEXT : R_FIRST))) {
00339       if (key.size) {
00340          keys = key.data;
00341          keys[key.size - 1] = '\0';
00342       } else
00343          keys = "<bad key>";
00344       if (data.size) {
00345          values = data.data;
00346          values[data.size - 1]='\0';
00347       } else
00348          values = "<bad value>";
00349       if (keymatch(keys, prefix)) {
00350             cur = malloc(sizeof(struct ast_db_entry) + strlen(keys) + strlen(values) + 2);
00351             if (cur) {
00352                cur->next = NULL;
00353                cur->key = cur->data + strlen(values) + 1;
00354                strcpy(cur->data, values);
00355                strcpy(cur->key, keys);
00356                if (last)
00357                   last->next = cur;
00358                else
00359                   ret = cur;
00360                last = cur;
00361             }
00362       }
00363    }
00364    ast_mutex_unlock(&dblock);
00365    return ret; 
00366 }
00367 
00368 void ast_db_freetree(struct ast_db_entry *dbe)
00369 {
00370    struct ast_db_entry *last;
00371    while(dbe) {
00372       last = dbe;
00373       dbe = dbe->next;
00374       free(last);
00375    }
00376 }
00377 
00378 static char database_show_usage[] =
00379 "Usage: database show [family [keytree]]\n"
00380 "       Shows Asterisk database contents, optionally restricted\n"
00381 "to a given family, or family and keytree.\n";
00382 
00383 static char database_put_usage[] =
00384 "Usage: database put <family> <key> <value>\n"
00385 "       Adds or updates an entry in the Asterisk database for\n"
00386 "a given family, key, and value.\n";
00387 
00388 static char database_get_usage[] =
00389 "Usage: database get <family> <key>\n"
00390 "       Retrieves an entry in the Asterisk database for a given\n"
00391 "family and key.\n";
00392 
00393 static char database_del_usage[] =
00394 "Usage: database del <family> <key>\n"
00395 "       Deletes an entry in the Asterisk database for a given\n"
00396 "family and key.\n";
00397 
00398 static char database_deltree_usage[] =
00399 "Usage: database deltree <family> [keytree]\n"
00400 "       Deletes a family or specific keytree within a family\n"
00401 "in the Asterisk database.\n";
00402 
00403 struct ast_cli_entry cli_database_show =
00404 { { "database", "show", NULL }, database_show, "Shows database contents", database_show_usage };
00405 
00406 struct ast_cli_entry cli_database_get =
00407 { { "database", "get", NULL }, database_get, "Gets database value", database_get_usage };
00408 
00409 struct ast_cli_entry cli_database_put =
00410 { { "database", "put", NULL }, database_put, "Adds/updates database value", database_put_usage };
00411 
00412 struct ast_cli_entry cli_database_del =
00413 { { "database", "del", NULL }, database_del, "Removes database key/value", database_del_usage };
00414 
00415 struct ast_cli_entry cli_database_deltree =
00416 { { "database", "deltree", NULL }, database_deltree, "Removes database keytree/values", database_deltree_usage };
00417 
00418 int astdb_init(void)
00419 {
00420    dbinit();
00421    ast_cli_register(&cli_database_show);
00422    ast_cli_register(&cli_database_get);
00423    ast_cli_register(&cli_database_put);
00424    ast_cli_register(&cli_database_del);
00425    ast_cli_register(&cli_database_deltree);
00426    return 0;
00427 }

Generated on Sat Nov 25 19:09:35 2006 for Asterisk by  doxygen 1.4.2