x86-64 compile fixes and cleanups
[asterisk/asterisk.git] / db.c
1 /*
2  * Asterisk -- A telephony toolkit for Linux.
3  *
4  * Channel Management
5  * 
6  * Copyright (C) 1999, Mark Spencer
7  *
8  * Mark Spencer <markster@linux-support.net>
9  *
10  * This program is free software, distributed under the terms of
11  * the GNU General Public License
12  */
13
14 /* DB3 is licensed under Sleepycat Public License and is thus incompatible
15    with GPL.  To avoid having to make another exception (and complicate 
16    licensing even further) we elect to use DB1 which is BSD licensed */
17
18 #include <stdio.h>
19 #include <stdlib.h>
20 #include <pthread.h>
21 #include <string.h>
22 #include <sys/time.h>
23 #include <signal.h>
24 #include <errno.h>
25 #include <unistd.h>
26 #include <dirent.h>
27 #include <asterisk/channel.h>
28 #include <asterisk/file.h>
29 #include <asterisk/app.h>
30 #include <asterisk/dsp.h>
31 #include <asterisk/logger.h>
32 #include <asterisk/options.h>
33 #include <asterisk/astdb.h>
34 #include <asterisk/cli.h>
35 #include <asterisk/utils.h>
36 #include "db1-ast/include/db.h"
37 #include "asterisk.h"
38 #include "astconf.h"
39
40 static DB *astdb;
41 AST_MUTEX_DEFINE_STATIC(dblock);
42
43 static int dbinit(void) 
44 {
45         if (!astdb) {
46                 if (!(astdb = dbopen((char *)ast_config_AST_DB, O_CREAT | O_RDWR, 0664, DB_BTREE, NULL))) {
47                         ast_log(LOG_WARNING, "Unable to open Asterisk database\n");
48                 }
49         }
50         if (astdb)
51                 return 0;
52         return -1;
53 }
54
55
56 static inline int keymatch(const char *key, const char *prefix)
57 {
58         int preflen = strlen(prefix);
59         if (!preflen)
60                 return 1;
61         if (!strcasecmp(key, prefix))
62                 return 1;
63         if ((strlen(key) > preflen) &&
64                 !strncasecmp(key, prefix, preflen)) {
65                 if (key[preflen] == '/')
66                         return 1;
67         }
68         return 0;
69 }
70
71 int ast_db_deltree(const char *family, const char *keytree)
72 {
73         char prefix[256];
74         DBT key, data;
75         char *keys;
76         int res;
77         int pass;
78         
79         if (family) {
80                 if (keytree)
81                         snprintf(prefix, sizeof(prefix), "/%s/%s", family, keytree);
82                 else
83                         snprintf(prefix, sizeof(prefix), "/%s", family);
84         } else if (keytree)
85                 return -1;
86         else
87                 strcpy(prefix, "");
88         
89         ast_mutex_lock(&dblock);
90         if (dbinit()) 
91                 return -1;
92         
93         memset(&key, 0, sizeof(key));
94         memset(&data, 0, sizeof(data));
95         pass = 0;
96         while(!(res = astdb->seq(astdb, &key, &data, pass++ ? R_NEXT : R_FIRST))) {
97                 if (key.size) {
98                         keys = key.data;
99                         keys[key.size - 1] = '\0';
100                 } else
101                         keys = "<bad key>";
102                 if (keymatch(keys, prefix)) {
103                         astdb->del(astdb, &key, 0);
104                 }
105         }
106         astdb->sync(astdb, 0);
107         ast_mutex_unlock(&dblock);
108         return 0;
109 }
110
111 int ast_db_put(const char *family, const char *keys, char *value)
112 {
113         char fullkey[256];
114         DBT key, data;
115         int res, fullkeylen;
116
117         ast_mutex_lock(&dblock);
118         if (dbinit()) {
119                 ast_mutex_unlock(&dblock);
120                 return -1;
121         }
122
123         fullkeylen = snprintf(fullkey, sizeof(fullkey), "/%s/%s", family, keys);
124         memset(&key, 0, sizeof(key));
125         memset(&data, 0, sizeof(data));
126         key.data = fullkey;
127         key.size = fullkeylen + 1;
128         data.data = value;
129         data.size = strlen(value) + 1;
130         res = astdb->put(astdb, &key, &data, 0);
131         astdb->sync(astdb, 0);
132         ast_mutex_unlock(&dblock);
133         if (res)
134                 ast_log(LOG_WARNING, "Unable to put value '%s' for key '%s' in family '%s'\n", value, keys, family);
135         return res;
136 }
137
138 int ast_db_get(const char *family, const char *keys, char *value, int valuelen)
139 {
140         char fullkey[256]="";
141         DBT key, data;
142         int res, fullkeylen;
143
144         ast_mutex_lock(&dblock);
145         if (dbinit()) {
146                 ast_mutex_unlock(&dblock);
147                 return -1;
148         }
149
150         fullkeylen = snprintf(fullkey, sizeof(fullkey), "/%s/%s", family, keys);
151         memset(&key, 0, sizeof(key));
152         memset(&data, 0, sizeof(data));
153         memset(value, 0, valuelen);
154         key.data = fullkey;
155         key.size = fullkeylen + 1;
156         
157         res = astdb->get(astdb, &key, &data, 0);
158         
159         ast_mutex_unlock(&dblock);
160
161         /* Be sure to NULL terminate our data either way */
162         if (res) {
163                 ast_log(LOG_DEBUG, "Unable to find key '%s' in family '%s'\n", keys, family);
164         } else {
165 #if 0
166                 printf("Got value of size %d\n", data.size);
167 #endif
168                 if (data.size) {
169                         ((char *)data.data)[data.size - 1] = '\0';
170                         /* Make sure that we don't write too much to the dst pointer or we don't read too much from the source pointer */
171                         strncpy(value, data.data, (valuelen > data.size) ? data.size : valuelen);
172                 } else {
173                         ast_log(LOG_NOTICE, "Strange, empty value for /%s/%s\n", family, keys);
174                 }
175         }
176         return res;
177 }
178
179 int ast_db_del(const char *family, const char *keys)
180 {
181         char fullkey[256];
182         DBT key;
183         int res, fullkeylen;
184
185         ast_mutex_lock(&dblock);
186         if (dbinit()) {
187                 ast_mutex_unlock(&dblock);
188                 return -1;
189         }
190         
191         fullkeylen = snprintf(fullkey, sizeof(fullkey), "/%s/%s", family, keys);
192         memset(&key, 0, sizeof(key));
193         key.data = fullkey;
194         key.size = fullkeylen + 1;
195         
196         res = astdb->del(astdb, &key, 0);
197         astdb->sync(astdb, 0);
198         
199         ast_mutex_unlock(&dblock);
200
201         if (res) 
202                 ast_log(LOG_DEBUG, "Unable to find key '%s' in family '%s'\n", keys, family);
203         return res;
204 }
205
206 static int database_put(int fd, int argc, char *argv[])
207 {
208         int res;
209         if (argc != 5)
210                 return RESULT_SHOWUSAGE;
211         res = ast_db_put(argv[2], argv[3], argv[4]);
212         if (res) 
213                 ast_cli(fd, "Failed to update entry\n");
214         else
215                 ast_cli(fd, "Updated database successfully\n");
216         return RESULT_SUCCESS;
217 }
218
219 static int database_get(int fd, int argc, char *argv[])
220 {
221         int res;
222         char tmp[256];
223         if (argc != 4)
224                 return RESULT_SHOWUSAGE;
225         res = ast_db_get(argv[2], argv[3], tmp, sizeof(tmp));
226         if (res) 
227                 ast_cli(fd, "Database entry not found.\n");
228         else
229                 ast_cli(fd, "Value: %s\n", tmp);
230         return RESULT_SUCCESS;
231 }
232
233 static int database_del(int fd, int argc, char *argv[])
234 {
235         int res;
236         if (argc != 4)
237                 return RESULT_SHOWUSAGE;
238         res = ast_db_del(argv[2], argv[3]);
239         if (res) 
240                 ast_cli(fd, "Database entry does not exist.\n");
241         else
242                 ast_cli(fd, "Database entry removed.\n");
243         return RESULT_SUCCESS;
244 }
245
246 static int database_deltree(int fd, int argc, char *argv[])
247 {
248         int res;
249         if ((argc < 3) || (argc > 4))
250                 return RESULT_SHOWUSAGE;
251         if (argc == 4)
252                 res = ast_db_deltree(argv[2], argv[3]);
253         else
254                 res = ast_db_deltree(argv[2], NULL);
255         if (res) 
256                 ast_cli(fd, "Database entries do not exist.\n");
257         else
258                 ast_cli(fd, "Database entries removed.\n");
259         return RESULT_SUCCESS;
260 }
261
262 static int database_show(int fd, int argc, char *argv[])
263 {
264         char prefix[256];
265         DBT key, data;
266         char *keys, *values;
267         int res;
268         int pass;
269
270         if (argc == 4) {
271                 /* Family and key tree */
272                 snprintf(prefix, sizeof(prefix), "/%s/%s", argv[2], argv[3]);
273         } else if (argc == 3) {
274                 /* Family only */
275                 snprintf(prefix, sizeof(prefix), "/%s", argv[2]);
276         } else if (argc == 2) {
277                 /* Neither */
278                 strcpy(prefix, "");
279         } else
280                 return RESULT_SHOWUSAGE;
281         ast_mutex_lock(&dblock);
282         if (dbinit()) {
283                 ast_mutex_unlock(&dblock);
284                 ast_cli(fd, "Database unavailable\n");
285                 return RESULT_SUCCESS;  
286         }
287         memset(&key, 0, sizeof(key));
288         memset(&data, 0, sizeof(data));
289         pass = 0;
290         while(!(res = astdb->seq(astdb, &key, &data, pass++ ? R_NEXT : R_FIRST))) {
291                 if (key.size) {
292                         keys = key.data;
293                         keys[key.size - 1] = '\0';
294                 } else
295                         keys = "<bad key>";
296                 if (data.size) {
297                         values = data.data;
298                         values[data.size - 1]='\0';
299                 } else
300                         values = "<bad value>";
301                 if (keymatch(keys, prefix)) {
302                                 ast_cli(fd, "%-50s: %-25s\n", keys, values);
303                 }
304         }
305         ast_mutex_unlock(&dblock);
306         return RESULT_SUCCESS;  
307 }
308
309 struct ast_db_entry *ast_db_gettree(const char *family, const char *keytree)
310 {
311         char prefix[256];
312         DBT key, data;
313         char *keys, *values;
314         int res;
315         int pass;
316         struct ast_db_entry *last = NULL;
317         struct ast_db_entry *cur, *ret=NULL;
318
319         if (family && !ast_strlen_zero(family)) {
320                 if (keytree && !ast_strlen_zero(keytree))
321                         /* Family and key tree */
322                         snprintf(prefix, sizeof(prefix), "/%s/%s", family, prefix);
323                 else
324                         /* Family only */
325                         snprintf(prefix, sizeof(prefix), "/%s", family);
326         } else
327                 strcpy(prefix, "");
328         ast_mutex_lock(&dblock);
329         if (dbinit()) {
330                 ast_mutex_unlock(&dblock);
331                 ast_log(LOG_WARNING, "Database unavailable\n");
332                 return NULL;    
333         }
334         memset(&key, 0, sizeof(key));
335         memset(&data, 0, sizeof(data));
336         pass = 0;
337         while(!(res = astdb->seq(astdb, &key, &data, pass++ ? R_NEXT : R_FIRST))) {
338                 if (key.size) {
339                         keys = key.data;
340                         keys[key.size - 1] = '\0';
341                 } else
342                         keys = "<bad key>";
343                 if (data.size) {
344                         values = data.data;
345                         values[data.size - 1]='\0';
346                 } else
347                         values = "<bad value>";
348                 if (keymatch(keys, prefix)) {
349                                 cur = malloc(sizeof(struct ast_db_entry) + strlen(keys) + strlen(values) + 2);
350                                 if (cur) {
351                                         cur->next = NULL;
352                                         cur->key = cur->data + strlen(values) + 1;
353                                         strcpy(cur->data, values);
354                                         strcpy(cur->key, keys);
355                                         if (last)
356                                                 last->next = cur;
357                                         else
358                                                 ret = cur;
359                                         last = cur;
360                                 }
361                 }
362         }
363         ast_mutex_unlock(&dblock);
364         return ret;     
365 }
366
367 void ast_db_freetree(struct ast_db_entry *dbe)
368 {
369         struct ast_db_entry *last;
370         while(dbe) {
371                 last = dbe;
372                 dbe = dbe->next;
373                 free(last);
374         }
375 }
376
377 static char database_show_usage[] =
378 "Usage: database show [family [keytree]]\n"
379 "       Shows Asterisk database contents, optionally restricted\n"
380 "to a given family, or family and keytree.\n";
381
382 static char database_put_usage[] =
383 "Usage: database put <family> <key> <value>\n"
384 "       Adds or updates an entry in the Asterisk database for\n"
385 "a given family, key, and value.\n";
386
387 static char database_get_usage[] =
388 "Usage: database get <family> <key>\n"
389 "       Retrieves an entry in the Asterisk database for a given\n"
390 "family and key.\n";
391
392 static char database_del_usage[] =
393 "Usage: database del <family> <key>\n"
394 "       Deletes an entry in the Asterisk database for a given\n"
395 "family and key.\n";
396
397 static char database_deltree_usage[] =
398 "Usage: database deltree <family> [keytree]\n"
399 "       Deletes a family or specific keytree within a family\n"
400 "in the Asterisk database.\n";
401
402 struct ast_cli_entry cli_database_show =
403 { { "database", "show", NULL }, database_show, "Shows database contents", database_show_usage };
404
405 struct ast_cli_entry cli_database_get =
406 { { "database", "get", NULL }, database_get, "Gets database value", database_get_usage };
407
408 struct ast_cli_entry cli_database_put =
409 { { "database", "put", NULL }, database_put, "Adds/updates database value", database_put_usage };
410
411 struct ast_cli_entry cli_database_del =
412 { { "database", "del", NULL }, database_del, "Removes database key/value", database_del_usage };
413
414 struct ast_cli_entry cli_database_deltree =
415 { { "database", "deltree", NULL }, database_deltree, "Removes database keytree/values", database_deltree_usage };
416
417 int astdb_init(void)
418 {
419         dbinit();
420         ast_cli_register(&cli_database_show);
421         ast_cli_register(&cli_database_get);
422         ast_cli_register(&cli_database_put);
423         ast_cli_register(&cli_database_del);
424         ast_cli_register(&cli_database_deltree);
425         return 0;
426 }