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

Generated on Fri Feb 27 12:19:42 2004 for Asterisk by doxygen 1.3.5