Wed Jan 8 2020 09:49:46

Asterisk developer's documentation


db.c
Go to the documentation of this file.
1 /*
2  * Asterisk -- An open source telephony toolkit.
3  *
4  * Copyright (C) 1999 - 2005, Digium, Inc.
5  *
6  * Mark Spencer <markster@digium.com>
7  *
8  * See http://www.asterisk.org for more information about
9  * the Asterisk project. Please do not directly contact
10  * any of the maintainers of this project for assistance;
11  * the project provides a web site, mailing lists and IRC
12  * channels for your use.
13  *
14  * This program is free software, distributed under the terms of
15  * the GNU General Public License Version 2. See the LICENSE file
16  * at the top of the source tree.
17  */
18 
19 /*! \file
20  *
21  * \brief ASTdb Management
22  *
23  * \author Mark Spencer <markster@digium.com>
24  *
25  * \note DB3 is licensed under Sleepycat Public License and is thus incompatible
26  * with GPL. To avoid having to make another exception (and complicate
27  * licensing even further) we elect to use DB1 which is BSD licensed
28  */
29 
30 /*** MODULEINFO
31  <support_level>core</support_level>
32  ***/
33 
34 #include "asterisk.h"
35 
36 ASTERISK_FILE_VERSION(__FILE__, "$Revision: 377688 $")
37 
38 #include "asterisk/_private.h"
39 #include "asterisk/paths.h" /* use ast_config_AST_DB */
40 #include <sys/time.h>
41 #include <signal.h>
42 #include <dirent.h>
43 
44 #include "asterisk/channel.h"
45 #include "asterisk/file.h"
46 #include "asterisk/app.h"
47 #include "asterisk/dsp.h"
48 #include "asterisk/astdb.h"
49 #include "asterisk/cli.h"
50 #include "asterisk/utils.h"
51 #include "asterisk/lock.h"
52 #include "asterisk/manager.h"
53 #include "db1-ast/include/db.h"
54 
55 /*** DOCUMENTATION
56  <manager name="DBGet" language="en_US">
57  <synopsis>
58  Get DB Entry.
59  </synopsis>
60  <syntax>
61  <xi:include xpointer="xpointer(/docs/manager[@name='Login']/syntax/parameter[@name='ActionID'])" />
62  <parameter name="Family" required="true" />
63  <parameter name="Key" required="true" />
64  </syntax>
65  <description>
66  </description>
67  </manager>
68  <manager name="DBPut" language="en_US">
69  <synopsis>
70  Put DB entry.
71  </synopsis>
72  <syntax>
73  <xi:include xpointer="xpointer(/docs/manager[@name='Login']/syntax/parameter[@name='ActionID'])" />
74  <parameter name="Family" required="true" />
75  <parameter name="Key" required="true" />
76  <parameter name="Val" />
77  </syntax>
78  <description>
79  </description>
80  </manager>
81  <manager name="DBDel" language="en_US">
82  <synopsis>
83  Delete DB entry.
84  </synopsis>
85  <syntax>
86  <xi:include xpointer="xpointer(/docs/manager[@name='Login']/syntax/parameter[@name='ActionID'])" />
87  <parameter name="Family" required="true" />
88  <parameter name="Key" required="true" />
89  </syntax>
90  <description>
91  </description>
92  </manager>
93  <manager name="DBDelTree" language="en_US">
94  <synopsis>
95  Delete DB Tree.
96  </synopsis>
97  <syntax>
98  <xi:include xpointer="xpointer(/docs/manager[@name='Login']/syntax/parameter[@name='ActionID'])" />
99  <parameter name="Family" required="true" />
100  <parameter name="Key" />
101  </syntax>
102  <description>
103  </description>
104  </manager>
105  ***/
106 
107 #define MAX_DB_FIELD 256
108 
109 static DB *astdb;
112 static pthread_t syncthread;
113 static int doexit;
114 typedef int (*process_keys_cb)(DBT *key, DBT *value, const char *filter, void *data);
115 
116 static void db_sync(void);
117 
118 static int dbinit(void)
119 {
120  if (doexit) {
121  return -1;
122  }
123  if (!astdb && !(astdb = dbopen(ast_config_AST_DB, O_CREAT | O_RDWR, AST_FILE_MODE, DB_BTREE, NULL))) {
124  ast_log(LOG_WARNING, "Unable to open Asterisk database '%s': %s\n", ast_config_AST_DB, strerror(errno));
125  return -1;
126  }
127  return 0;
128 }
129 
130 static inline int keymatch(const char *key, const char *prefix)
131 {
132  int preflen = strlen(prefix);
133  if (!preflen)
134  return 1;
135  if (!strcasecmp(key, prefix))
136  return 1;
137  if ((strlen(key) > preflen) && !strncasecmp(key, prefix, preflen)) {
138  if (key[preflen] == '/')
139  return 1;
140  }
141  return 0;
142 }
143 
144 static inline int subkeymatch(const char *key, const char *suffix)
145 {
146  int suffixlen = strlen(suffix);
147  if (suffixlen) {
148  const char *subkey = key + strlen(key) - suffixlen;
149  if (subkey < key)
150  return 0;
151  if (!strcasecmp(subkey, suffix))
152  return 1;
153  }
154  return 0;
155 }
156 
157 static const char *dbt_data2str(DBT *dbt)
158 {
159  char *data = "";
160 
161  if (dbt->size) {
162  data = dbt->data;
163  data[dbt->size - 1] = '\0';
164  }
165 
166  return data;
167 }
168 
169 static inline const char *dbt_data2str_full(DBT *dbt, const char *def)
170 {
171  return S_OR(dbt_data2str(dbt), def);
172 }
173 
174 /*!
175  * \internal
176  * \brief Invoke a callback function on all keys, using given data and filter.
177  *
178  * \param cb Callback function to invoke (itself returns number of keys it affected).
179  * \param data Value to pass to cb's data param.
180  * \param filter Value to pass to cb's filter param.
181  * \param sync If non-zero, call db_sync() when done.
182  * \return Number of keys affected by the callback, or -1 if database is unavailable.
183  */
184 static int process_db_keys(process_keys_cb cb, void *data, const char *filter, int sync)
185 {
186  DBT key = { 0, }, value = { 0, }, last_key = { 0, };
187  int counter = 0;
188  int res, last = 0;
189  char last_key_s[MAX_DB_FIELD];
190 
192  if (dbinit()) {
194  return -1;
195  }
196 
197  /* Somehow, the database can become corrupted such that astdb->seq will continue looping through
198  * the database indefinitely. The pointer to last_key.data ends up getting re-used by the BDB lib
199  * so this specifically queries for the last entry, makes a copy of the key, and then uses it as
200  * a sentinel to avoid repeatedly looping over the list. */
201 
202  if (astdb->seq(astdb, &last_key, &value, R_LAST)) {
203  /* Empty database */
205  return 0;
206  }
207 
208  memcpy(last_key_s, last_key.data, MIN(last_key.size - 1, sizeof(last_key_s)));
209  last_key_s[last_key.size - 1] = '\0';
210  for (res = astdb->seq(astdb, &key, &value, R_FIRST);
211  !res;
212  res = astdb->seq(astdb, &key, &value, R_NEXT)) {
213  /* The callback might delete the key, so we have to check it before calling */
214  last = !strcmp(dbt_data2str_full(&key, "<bad key>"), last_key_s);
215  counter += cb(&key, &value, filter, data);
216  if (last) {
217  break;
218  }
219  }
220 
221  if (sync) {
222  db_sync();
223  }
224 
226 
227  return counter;
228 }
229 
230 static int db_deltree_cb(DBT *key, DBT *value, const char *filter, void *data)
231 {
232  int res = 0;
233 
234  if (keymatch(dbt_data2str_full(key, "<bad key>"), filter)) {
235  astdb->del(astdb, key, 0);
236  res = 1;
237  }
238  return res;
239 }
240 
241 int ast_db_deltree(const char *family, const char *keytree)
242 {
243  char prefix[MAX_DB_FIELD];
244 
245  if (family) {
246  if (keytree) {
247  snprintf(prefix, sizeof(prefix), "/%s/%s", family, keytree);
248  } else {
249  snprintf(prefix, sizeof(prefix), "/%s", family);
250  }
251  } else if (keytree) {
252  return -1;
253  } else {
254  prefix[0] = '\0';
255  }
256 
257  return process_db_keys(db_deltree_cb, NULL, prefix, 1);
258 }
259 
260 int ast_db_put(const char *family, const char *keys, const char *value)
261 {
262  char fullkey[MAX_DB_FIELD];
263  DBT key, data;
264  int res, fullkeylen;
265 
267  if (dbinit()) {
269  return -1;
270  }
271 
272  fullkeylen = snprintf(fullkey, sizeof(fullkey), "/%s/%s", family, keys);
273  memset(&key, 0, sizeof(key));
274  memset(&data, 0, sizeof(data));
275  key.data = fullkey;
276  key.size = fullkeylen + 1;
277  data.data = (char *) value;
278  data.size = strlen(value) + 1;
279  res = astdb->put(astdb, &key, &data, 0);
280  db_sync();
282  if (res)
283  ast_log(LOG_WARNING, "Unable to put value '%s' for key '%s' in family '%s'\n", value, keys, family);
284 
285  return res;
286 }
287 
288 /*!
289  * \internal
290  * \brief Get key value specified by family/key.
291  *
292  * Gets the value associated with the specified \a family and \a keys, and
293  * stores it, either into the fixed sized buffer specified by \a buffer
294  * and \a bufferlen, or as a heap allocated string if \a bufferlen is -1.
295  *
296  * \note If \a bufferlen is -1, \a buffer points to heap allocated memory
297  * and must be freed by calling ast_free().
298  *
299  * \retval -1 An error occurred
300  * \retval 0 Success
301  */
302 static int db_get_common(const char *family, const char *keys, char **buffer, int bufferlen)
303 {
304  char fullkey[MAX_DB_FIELD] = "";
305  DBT key, data;
306  int res, fullkeylen;
307 
309  if (dbinit()) {
311  return -1;
312  }
313 
314  fullkeylen = snprintf(fullkey, sizeof(fullkey), "/%s/%s", family, keys);
315  memset(&key, 0, sizeof(key));
316  memset(&data, 0, sizeof(data));
317  key.data = fullkey;
318  key.size = fullkeylen + 1;
319 
320  res = astdb->get(astdb, &key, &data, 0);
321 
322  /* Be sure to NULL terminate our data either way */
323  if (res) {
324  ast_debug(1, "Unable to find key '%s' in family '%s'\n", keys, family);
325  } else {
326  if (data.size) {
327  ((char *)data.data)[data.size - 1] = '\0';
328 
329  if (bufferlen == -1) {
330  *buffer = ast_strdup(data.data);
331  } else {
332  /* Make sure that we don't write too much to the dst pointer or we don't
333  * read too much from the source pointer */
334  ast_copy_string(*buffer, data.data, bufferlen > data.size ? data.size : bufferlen);
335  }
336  } else {
337  ast_log(LOG_NOTICE, "Strange, empty value for /%s/%s\n", family, keys);
338  }
339  }
340 
341  /* Data is not fully isolated for concurrency, so the lock must be extended
342  * to after the copy to the output buffer. */
344 
345  return res;
346 }
347 
348 int ast_db_get(const char *family, const char *keys, char *value, int valuelen)
349 {
350  ast_assert(value != NULL);
351 
352  /* Make sure we initialize */
353  value[0] = 0;
354 
355  return db_get_common(family, keys, &value, valuelen);
356 }
357 
358 int ast_db_get_allocated(const char *family, const char *keys, char **out)
359 {
360  *out = NULL;
361 
362  return db_get_common(family, keys, out, -1);
363 }
364 
365 int ast_db_del(const char *family, const char *keys)
366 {
367  char fullkey[MAX_DB_FIELD];
368  DBT key;
369  int res, fullkeylen;
370 
372  if (dbinit()) {
374  return -1;
375  }
376 
377  fullkeylen = snprintf(fullkey, sizeof(fullkey), "/%s/%s", family, keys);
378  memset(&key, 0, sizeof(key));
379  key.data = fullkey;
380  key.size = fullkeylen + 1;
381 
382  res = astdb->del(astdb, &key, 0);
383  db_sync();
384 
386 
387  if (res) {
388  ast_debug(1, "Unable to find key '%s' in family '%s'\n", keys, family);
389  }
390  return res;
391 }
392 
393 static char *handle_cli_database_put(struct ast_cli_entry *e, int cmd, struct ast_cli_args *a)
394 {
395  int res;
396 
397  switch (cmd) {
398  case CLI_INIT:
399  e->command = "database put";
400  e->usage =
401  "Usage: database put <family> <key> <value>\n"
402  " Adds or updates an entry in the Asterisk database for\n"
403  " a given family, key, and value.\n";
404  return NULL;
405  case CLI_GENERATE:
406  return NULL;
407  }
408 
409  if (a->argc != 5)
410  return CLI_SHOWUSAGE;
411  res = ast_db_put(a->argv[2], a->argv[3], a->argv[4]);
412  if (res) {
413  ast_cli(a->fd, "Failed to update entry\n");
414  } else {
415  ast_cli(a->fd, "Updated database successfully\n");
416  }
417  return CLI_SUCCESS;
418 }
419 
420 static char *handle_cli_database_get(struct ast_cli_entry *e, int cmd, struct ast_cli_args *a)
421 {
422  int res;
423  char tmp[MAX_DB_FIELD];
424 
425  switch (cmd) {
426  case CLI_INIT:
427  e->command = "database get";
428  e->usage =
429  "Usage: database get <family> <key>\n"
430  " Retrieves an entry in the Asterisk database for a given\n"
431  " family and key.\n";
432  return NULL;
433  case CLI_GENERATE:
434  return NULL;
435  }
436 
437  if (a->argc != 4)
438  return CLI_SHOWUSAGE;
439  res = ast_db_get(a->argv[2], a->argv[3], tmp, sizeof(tmp));
440  if (res) {
441  ast_cli(a->fd, "Database entry not found.\n");
442  } else {
443  ast_cli(a->fd, "Value: %s\n", tmp);
444  }
445  return CLI_SUCCESS;
446 }
447 
448 static char *handle_cli_database_del(struct ast_cli_entry *e, int cmd, struct ast_cli_args *a)
449 {
450  int res;
451 
452  switch (cmd) {
453  case CLI_INIT:
454  e->command = "database del";
455  e->usage =
456  "Usage: database del <family> <key>\n"
457  " Deletes an entry in the Asterisk database for a given\n"
458  " family and key.\n";
459  return NULL;
460  case CLI_GENERATE:
461  return NULL;
462  }
463 
464  if (a->argc != 4)
465  return CLI_SHOWUSAGE;
466  res = ast_db_del(a->argv[2], a->argv[3]);
467  if (res) {
468  ast_cli(a->fd, "Database entry does not exist.\n");
469  } else {
470  ast_cli(a->fd, "Database entry removed.\n");
471  }
472  return CLI_SUCCESS;
473 }
474 
475 static char *handle_cli_database_deltree(struct ast_cli_entry *e, int cmd, struct ast_cli_args *a)
476 {
477  int num_deleted;
478 
479  switch (cmd) {
480  case CLI_INIT:
481  e->command = "database deltree";
482  e->usage =
483  "Usage: database deltree <family> [keytree]\n"
484  " OR: database deltree <family>[/keytree]\n"
485  " Deletes a family or specific keytree within a family\n"
486  " in the Asterisk database. The two arguments may be\n"
487  " separated by either a space or a slash.\n";
488  return NULL;
489  case CLI_GENERATE:
490  return NULL;
491  }
492 
493  if ((a->argc < 3) || (a->argc > 4))
494  return CLI_SHOWUSAGE;
495  if (a->argc == 4) {
496  num_deleted = ast_db_deltree(a->argv[2], a->argv[3]);
497  } else {
498  num_deleted = ast_db_deltree(a->argv[2], NULL);
499  }
500  if (num_deleted < 0) {
501  ast_cli(a->fd, "Database unavailable.\n");
502  } else if (num_deleted == 0) {
503  ast_cli(a->fd, "Database entries do not exist.\n");
504  } else {
505  ast_cli(a->fd, "%d database entries removed.\n",num_deleted);
506  }
507  return CLI_SUCCESS;
508 }
509 
510 static int db_show_cb(DBT *key, DBT *value, const char *filter, void *data)
511 {
512  struct ast_cli_args *a = data;
513  const char *key_s = dbt_data2str_full(key, "<bad key>");
514  const char *value_s = dbt_data2str_full(value, "<bad value>");
515 
516  if (keymatch(key_s, filter)) {
517  ast_cli(a->fd, "%-50s: %-25s\n", key_s, value_s);
518  return 1;
519  }
520 
521  return 0;
522 }
523 
524 static char *handle_cli_database_show(struct ast_cli_entry *e, int cmd, struct ast_cli_args *a)
525 {
526  char prefix[MAX_DB_FIELD];
527  int counter = 0;
528 
529  switch (cmd) {
530  case CLI_INIT:
531  e->command = "database show";
532  e->usage =
533  "Usage: database show [family [keytree]]\n"
534  " OR: database show [family[/keytree]]\n"
535  " Shows Asterisk database contents, optionally restricted\n"
536  " to a given family, or family and keytree. The two arguments\n"
537  " may be separated either by a space or by a slash.\n";
538  return NULL;
539  case CLI_GENERATE:
540  return NULL;
541  }
542 
543  if (a->argc == 4) {
544  /* Family and key tree */
545  snprintf(prefix, sizeof(prefix), "/%s/%s", a->argv[2], a->argv[3]);
546  } else if (a->argc == 3) {
547  /* Family only */
548  snprintf(prefix, sizeof(prefix), "/%s", a->argv[2]);
549  } else if (a->argc == 2) {
550  /* Neither */
551  prefix[0] = '\0';
552  } else {
553  return CLI_SHOWUSAGE;
554  }
555 
556  if((counter = process_db_keys(db_show_cb, a, prefix, 0)) < 0) {
557  ast_cli(a->fd, "Database unavailable\n");
558  return CLI_SUCCESS;
559  }
560 
561  ast_cli(a->fd, "%d results found.\n", counter);
562  return CLI_SUCCESS;
563 }
564 
565 static int db_showkey_cb(DBT *key, DBT *value, const char *filter, void *data)
566 {
567  struct ast_cli_args *a = data;
568  const char *key_s = dbt_data2str_full(key, "<bad key>");
569  const char *value_s = dbt_data2str_full(value, "<bad value>");
570 
571  if (subkeymatch(key_s, filter)) {
572  ast_cli(a->fd, "%-50s: %-25s\n", key_s, value_s);
573  return 1;
574  }
575 
576  return 0;
577 }
578 
579 static char *handle_cli_database_showkey(struct ast_cli_entry *e, int cmd, struct ast_cli_args *a)
580 {
581  char suffix[MAX_DB_FIELD];
582  int counter = 0;
583 
584  switch (cmd) {
585  case CLI_INIT:
586  e->command = "database showkey";
587  e->usage =
588  "Usage: database showkey <keytree>\n"
589  " Shows Asterisk database contents, restricted to a given key.\n";
590  return NULL;
591  case CLI_GENERATE:
592  return NULL;
593  }
594 
595  if (a->argc == 3) {
596  /* Key only */
597  snprintf(suffix, sizeof(suffix), "/%s", a->argv[2]);
598  } else {
599  return CLI_SHOWUSAGE;
600  }
601 
602  if ((counter = process_db_keys(db_showkey_cb, a, suffix, 0)) < 0) {
603  ast_cli(a->fd, "Database unavailable\n");
604  return CLI_SUCCESS;
605  }
606 
607  ast_cli(a->fd, "%d results found.\n", counter);
608  return CLI_SUCCESS;
609 }
610 
611 static int db_gettree_cb(DBT *key, DBT *value, const char *filter, void *data)
612 {
613  struct ast_db_entry **ret = data;
614  struct ast_db_entry *cur;
615  const char *key_s = dbt_data2str_full(key, "<bad key>");
616  const char *value_s = dbt_data2str_full(value, "<bad value>");
617  size_t key_slen = strlen(key_s) + 1, value_slen = strlen(value_s) + 1;
618 
619  if (keymatch(key_s, filter) && (cur = ast_malloc(sizeof(*cur) + key_slen + value_slen))) {
620  cur->next = *ret;
621  cur->key = cur->data + value_slen;
622  strcpy(cur->data, value_s);
623  strcpy(cur->key, key_s);
624  *ret = cur;
625  return 1;
626  }
627 
628  return 0;
629 }
630 
631 struct ast_db_entry *ast_db_gettree(const char *family, const char *keytree)
632 {
633  char prefix[MAX_DB_FIELD];
634  struct ast_db_entry *ret = NULL;
635 
636  if (!ast_strlen_zero(family)) {
637  if (!ast_strlen_zero(keytree)) {
638  /* Family and key tree */
639  snprintf(prefix, sizeof(prefix), "/%s/%s", family, keytree);
640  } else {
641  /* Family only */
642  snprintf(prefix, sizeof(prefix), "/%s", family);
643  }
644  } else {
645  prefix[0] = '\0';
646  }
647 
648  if (process_db_keys(db_gettree_cb, &ret, prefix, 0) < 0) {
649  ast_log(LOG_WARNING, "Database unavailable\n");
650  return NULL;
651  }
652 
653  return ret;
654 }
655 
656 void ast_db_freetree(struct ast_db_entry *dbe)
657 {
658  struct ast_db_entry *last;
659  while (dbe) {
660  last = dbe;
661  dbe = dbe->next;
662  ast_free(last);
663  }
664 }
665 
666 static struct ast_cli_entry cli_database[] = {
667  AST_CLI_DEFINE(handle_cli_database_show, "Shows database contents"),
668  AST_CLI_DEFINE(handle_cli_database_showkey, "Shows database contents"),
669  AST_CLI_DEFINE(handle_cli_database_get, "Gets database value"),
670  AST_CLI_DEFINE(handle_cli_database_put, "Adds/updates database value"),
671  AST_CLI_DEFINE(handle_cli_database_del, "Removes database key/value"),
672  AST_CLI_DEFINE(handle_cli_database_deltree, "Removes database keytree/values")
673 };
674 
675 static int manager_dbput(struct mansession *s, const struct message *m)
676 {
677  const char *family = astman_get_header(m, "Family");
678  const char *key = astman_get_header(m, "Key");
679  const char *val = astman_get_header(m, "Val");
680  int res;
681 
682  if (ast_strlen_zero(family)) {
683  astman_send_error(s, m, "No family specified");
684  return 0;
685  }
686  if (ast_strlen_zero(key)) {
687  astman_send_error(s, m, "No key specified");
688  return 0;
689  }
690 
691  res = ast_db_put(family, key, S_OR(val, ""));
692  if (res) {
693  astman_send_error(s, m, "Failed to update entry");
694  } else {
695  astman_send_ack(s, m, "Updated database successfully");
696  }
697  return 0;
698 }
699 
700 static int manager_dbget(struct mansession *s, const struct message *m)
701 {
702  const char *id = astman_get_header(m,"ActionID");
703  char idText[256] = "";
704  const char *family = astman_get_header(m, "Family");
705  const char *key = astman_get_header(m, "Key");
706  char tmp[MAX_DB_FIELD];
707  int res;
708 
709  if (ast_strlen_zero(family)) {
710  astman_send_error(s, m, "No family specified.");
711  return 0;
712  }
713  if (ast_strlen_zero(key)) {
714  astman_send_error(s, m, "No key specified.");
715  return 0;
716  }
717 
718  if (!ast_strlen_zero(id))
719  snprintf(idText, sizeof(idText) ,"ActionID: %s\r\n", id);
720 
721  res = ast_db_get(family, key, tmp, sizeof(tmp));
722  if (res) {
723  astman_send_error(s, m, "Database entry not found");
724  } else {
725  astman_send_ack(s, m, "Result will follow");
726  astman_append(s, "Event: DBGetResponse\r\n"
727  "Family: %s\r\n"
728  "Key: %s\r\n"
729  "Val: %s\r\n"
730  "%s"
731  "\r\n",
732  family, key, tmp, idText);
733  astman_append(s, "Event: DBGetComplete\r\n"
734  "%s"
735  "\r\n",
736  idText);
737  }
738  return 0;
739 }
740 
741 static int manager_dbdel(struct mansession *s, const struct message *m)
742 {
743  const char *family = astman_get_header(m, "Family");
744  const char *key = astman_get_header(m, "Key");
745  int res;
746 
747  if (ast_strlen_zero(family)) {
748  astman_send_error(s, m, "No family specified.");
749  return 0;
750  }
751 
752  if (ast_strlen_zero(key)) {
753  astman_send_error(s, m, "No key specified.");
754  return 0;
755  }
756 
757  res = ast_db_del(family, key);
758  if (res)
759  astman_send_error(s, m, "Database entry not found");
760  else
761  astman_send_ack(s, m, "Key deleted successfully");
762 
763  return 0;
764 }
765 
766 static int manager_dbdeltree(struct mansession *s, const struct message *m)
767 {
768  const char *family = astman_get_header(m, "Family");
769  const char *key = astman_get_header(m, "Key");
770  int num_deleted;
771 
772  if (ast_strlen_zero(family)) {
773  astman_send_error(s, m, "No family specified.");
774  return 0;
775  }
776 
777  if (!ast_strlen_zero(key)) {
778  num_deleted = ast_db_deltree(family, key);
779  } else {
780  num_deleted = ast_db_deltree(family, NULL);
781  }
782 
783  if (num_deleted < 0) {
784  astman_send_error(s, m, "Database unavailable");
785  } else if (num_deleted == 0) {
786  astman_send_error(s, m, "Database entry not found");
787  } else {
788  astman_send_ack(s, m, "Key tree deleted successfully");
789  }
790 
791  return 0;
792 }
793 
794 /*!
795  * \internal
796  * \brief Signal the astdb sync thread to do its thing.
797  *
798  * \note dblock is assumed to be held when calling this function.
799  */
800 static void db_sync(void)
801 {
802  ast_cond_signal(&dbcond);
803 }
804 
805 /*!
806  * \internal
807  * \brief astdb sync thread
808  *
809  * This thread is in charge of syncing astdb to disk after a change.
810  * By pushing it off to this thread to take care of, this I/O bound operation
811  * will not block other threads from performing other critical processing.
812  * If changes happen rapidly, this thread will also ensure that the sync
813  * operations are rate limited.
814  */
815 static void *db_sync_thread(void *data)
816 {
818  for (;;) {
819  ast_cond_wait(&dbcond, &dblock);
820  if (doexit) {
821  /*
822  * We were likely awakened just to exit. Sync anyway just in
823  * case.
824  */
825  if (astdb) {
826  astdb->sync(astdb, 0);
827  }
829  break;
830  }
831 
833  /*
834  * Sleep so if we have a bunch of db puts in a row, they won't
835  * get written one at a time to the db but in a batch.
836  */
837  sleep(1);
839 
840  /* The db should be successfully opened to get here. */
841  ast_assert(astdb != NULL);
842  astdb->sync(astdb, 0);
843 
844  if (doexit) {
845  /* We were asked to exit while sleeping. */
847  break;
848  }
849  }
850 
851  return NULL;
852 }
853 
854 static void astdb_shutdown(void)
855 {
856  ast_cli_unregister_multiple(cli_database, ARRAY_LEN(cli_database));
857  ast_manager_unregister("DBGet");
858  ast_manager_unregister("DBPut");
859  ast_manager_unregister("DBDel");
860  ast_manager_unregister("DBDelTree");
861 
863  doexit = 1;
864  db_sync();
866 
867  pthread_join(syncthread, NULL);
868 
869 #if defined(DEBUG_FD_LEAKS) && defined(close)
870 /* DEBUG_FD_LEAKS causes conflicting define of close() in asterisk.h */
871 #undef close
872 #endif
873 
874  if (astdb) {
875  astdb->close(astdb);
876  astdb = NULL;
877  }
878 }
879 
880 int astdb_init(void)
881 {
882  ast_cond_init(&dbcond, NULL);
883  if (ast_pthread_create_background(&syncthread, NULL, db_sync_thread, NULL)) {
884  return -1;
885  }
886 
888  /* Ignore check_return warning from Coverity for dbinit below */
889  dbinit();
891 
892  ast_cli_register_multiple(cli_database, ARRAY_LEN(cli_database));
897 
899  return 0;
900 }
#define AST_CLI_DEFINE(fn, txt,...)
Definition: cli.h:191
static struct ast_cli_entry cli_database[]
Definition: db.c:666
Asterisk locking-related definitions:
void astman_append(struct mansession *s, const char *fmt,...)
Definition: manager.c:2068
Asterisk main include file. File version handling, generic pbx functions.
#define ARRAY_LEN(a)
Definition: isdn_lib.c:42
const char * ast_config_AST_DB
Definition: asterisk.c:268
#define ast_strdup(a)
Definition: astmm.h:109
Definition: ast_expr2.c:325
int ast_cli_unregister_multiple(struct ast_cli_entry *e, int len)
Unregister multiple commands.
Definition: cli.c:2177
int ast_db_get(const char *family, const char *key, char *out, int outlen)
Get key value specified by family/key.
Definition: db.c:348
static const char * dbt_data2str_full(DBT *dbt, const char *def)
Definition: db.c:169
Convenient Signal Processing routines.
descriptor for a cli entry.
Definition: cli.h:165
const int argc
Definition: cli.h:154
#define LOG_WARNING
Definition: logger.h:144
void ast_db_freetree(struct ast_db_entry *entry)
Free structure created by ast_db_gettree()
Definition: db.c:656
int(* process_keys_cb)(DBT *key, DBT *value, const char *filter, void *data)
Definition: db.c:114
Definition: cli.h:146
int ast_db_get_allocated(const char *family, const char *key, char **out)
Get key value specified by family/key as a heap allocated string.
Definition: db.c:358
#define ast_cond_wait(cond, mutex)
Definition: lock.h:171
#define ast_cond_init(cond, attr)
Definition: lock.h:167
static int subkeymatch(const char *key, const char *suffix)
Definition: db.c:144
#define ast_assert(a)
Definition: utils.h:738
void astman_send_ack(struct mansession *s, const struct message *m, char *msg)
Send ack in manager transaction.
Definition: manager.c:2135
#define ast_mutex_lock(a)
Definition: lock.h:155
static ast_mutex_t dblock
Definition: db.c:110
Generic File Format Support. Should be included by clients of the file handling routines. File service providers should instead include mod_format.h.
int value
Definition: syslog.c:39
void ast_cli(int fd, const char *fmt,...)
Definition: cli.c:105
static int dbinit(void)
Definition: db.c:118
#define AST_FILE_MODE
Definition: asterisk.h:36
static ast_cond_t dbcond
Definition: db.c:111
#define ast_cond_signal(cond)
Definition: lock.h:169
static int manager_dbget(struct mansession *s, const struct message *m)
Definition: db.c:700
Utility functions.
const char * astman_get_header(const struct message *m, char *var)
Get header from mananger transaction.
Definition: manager.c:1860
pthread_cond_t ast_cond_t
Definition: lock.h:144
#define ast_pthread_create_background(a, b, c, d)
Definition: utils.h:426
static int db_show_cb(DBT *key, DBT *value, const char *filter, void *data)
Definition: db.c:510
#define MIN(a, b)
Definition: utils.h:226
static pthread_t syncthread
Definition: db.c:112
#define EVENT_FLAG_SYSTEM
Definition: manager.h:71
#define ast_debug(level,...)
Log a DEBUG message.
Definition: logger.h:236
struct ast_db_entry * next
Definition: astdb.h:31
static int db_gettree_cb(DBT *key, DBT *value, const char *filter, void *data)
Definition: db.c:611
static int manager_dbdel(struct mansession *s, const struct message *m)
Definition: db.c:741
General Asterisk PBX channel definitions.
Asterisk file paths, configured in asterisk.conf.
const int fd
Definition: cli.h:153
static DB * astdb
Definition: db.c:109
#define ast_manager_register_xml(a, b, c)
Register a manager callback using XML documentation to describe the manager.
Definition: manager.h:172
static int db_get_common(const char *family, const char *keys, char **buffer, int bufferlen)
Definition: db.c:302
static force_inline int attribute_pure ast_strlen_zero(const char *s)
Definition: strings.h:63
struct sla_ringing_trunk * last
Definition: app_meetme.c:965
static int doexit
Definition: db.c:113
int ast_register_atexit(void(*func)(void))
Register a function to be executed before Asterisk exits.
Definition: asterisk.c:998
static char * handle_cli_database_showkey(struct ast_cli_entry *e, int cmd, struct ast_cli_args *a)
Definition: db.c:579
static int process_db_keys(process_keys_cb cb, void *data, const char *filter, int sync)
Definition: db.c:184
const char *const * argv
Definition: cli.h:155
The AMI - Asterisk Manager Interface - is a TCP protocol created to manage Asterisk with third-party ...
static void db_sync(void)
Definition: db.c:800
static char * handle_cli_database_put(struct ast_cli_entry *e, int cmd, struct ast_cli_args *a)
Definition: db.c:393
struct ast_db_entry * ast_db_gettree(const char *family, const char *keytree)
Get a list of values within the astdb tree If family is specified, only those keys will be returned...
Definition: db.c:631
#define CLI_SHOWUSAGE
Definition: cli.h:44
void ast_log(int level, const char *file, int line, const char *function, const char *fmt,...)
Used for sending a log message This is the standard logger function. Probably the only way you will i...
Definition: logger.c:1207
static int db_showkey_cb(DBT *key, DBT *value, const char *filter, void *data)
Definition: db.c:565
#define LOG_NOTICE
Definition: logger.h:133
Definition: astdb.h:30
int errno
char data[0]
Definition: astdb.h:33
#define ast_free(a)
Definition: astmm.h:97
char * command
Definition: cli.h:180
static const char * dbt_data2str(DBT *dbt)
Definition: db.c:157
static void * db_sync_thread(void *data)
Definition: db.c:815
const char * usage
Definition: cli.h:171
static int db_deltree_cb(DBT *key, DBT *value, const char *filter, void *data)
Definition: db.c:230
#define EVENT_FLAG_REPORTING
Definition: manager.h:80
#define CLI_SUCCESS
Definition: cli.h:43
static int manager_dbput(struct mansession *s, const struct message *m)
Definition: db.c:675
Standard Command Line Interface.
int ast_db_del(const char *family, const char *key)
Delete entry in astdb.
Definition: db.c:365
void ast_copy_string(char *dst, const char *src, size_t size)
Size-limited null-terminating string copy.
Definition: strings.h:223
#define S_OR(a, b)
returns the equivalent of logic or for strings: first one if not empty, otherwise second one...
Definition: strings.h:77
static int manager_dbdeltree(struct mansession *s, const struct message *m)
Definition: db.c:766
int ast_cli_register_multiple(struct ast_cli_entry *e, int len)
Register multiple commands.
Definition: cli.c:2167
static char * handle_cli_database_del(struct ast_cli_entry *e, int cmd, struct ast_cli_args *a)
Definition: db.c:448
Application convenience functions, designed to give consistent look and feel to Asterisk apps...
static char * handle_cli_database_get(struct ast_cli_entry *e, int cmd, struct ast_cli_args *a)
Definition: db.c:420
int ast_db_put(const char *family, const char *key, const char *value)
Store value addressed by family/key.
Definition: db.c:260
#define MAX_DB_FIELD
Definition: db.c:107
static int keymatch(const char *key, const char *prefix)
Definition: db.c:130
static int filter(struct ast_channel *chan, const char *cmd, char *parse, char *buf, size_t len)
Definition: func_strings.c:694
static char * handle_cli_database_deltree(struct ast_cli_entry *e, int cmd, struct ast_cli_args *a)
Definition: db.c:475
#define ast_malloc(a)
Definition: astmm.h:91
void astman_send_error(struct mansession *s, const struct message *m, char *error)
Send error in manager transaction.
Definition: manager.c:2130
Persistant data storage (akin to *doze registry)
#define AST_MUTEX_DEFINE_STATIC(mutex)
Definition: lock.h:526
int astdb_init(void)
Definition: db.c:880
int ast_db_deltree(const char *family, const char *keytree)
Delete one or more entries in astdb If both parameters are NULL, the entire database will be purged...
Definition: db.c:241
int ast_manager_unregister(char *action)
Unregister a registered manager command.
Definition: manager.c:5355
#define ASTERISK_FILE_VERSION(file, version)
Register/unregister a source code file with the core.
Definition: asterisk.h:180
#define ast_mutex_unlock(a)
Definition: lock.h:156
char * key
Definition: astdb.h:32
static char * handle_cli_database_show(struct ast_cli_entry *e, int cmd, struct ast_cli_args *a)
Definition: db.c:524
static char prefix[MAX_PREFIX]
Definition: http.c:107
static void astdb_shutdown(void)
Definition: db.c:854