Asterisk - The Open Source Telephony Project  21.4.1
main/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 #include "asterisk/_private.h"
37 #include "asterisk/paths.h" /* use ast_config_AST_DB */
38 #include <sys/time.h>
39 #include <sys/types.h>
40 #include <sys/stat.h>
41 #include <unistd.h>
42 #include <signal.h>
43 #include <dirent.h>
44 #include <sqlite3.h>
45 
46 #include "asterisk/channel.h"
47 #include "asterisk/file.h"
48 #include "asterisk/app.h"
49 #include "asterisk/dsp.h"
50 #include "asterisk/astdb.h"
51 #include "asterisk/cli.h"
52 #include "asterisk/utils.h"
53 #include "asterisk/manager.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="DBGetTree" language="en_US">
69  <synopsis>
70  Get DB entries, optionally at a particular family/key
71  </synopsis>
72  <syntax>
73  <xi:include xpointer="xpointer(/docs/manager[@name='Login']/syntax/parameter[@name='ActionID'])" />
74  <parameter name="Family" required="false" />
75  <parameter name="Key" required="false" />
76  </syntax>
77  <description>
78  </description>
79  </manager>
80  <manager name="DBPut" language="en_US">
81  <synopsis>
82  Put DB entry.
83  </synopsis>
84  <syntax>
85  <xi:include xpointer="xpointer(/docs/manager[@name='Login']/syntax/parameter[@name='ActionID'])" />
86  <parameter name="Family" required="true" />
87  <parameter name="Key" required="true" />
88  <parameter name="Val" />
89  </syntax>
90  <description>
91  </description>
92  </manager>
93  <manager name="DBDel" language="en_US">
94  <synopsis>
95  Delete DB entry.
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" required="true" />
101  </syntax>
102  <description>
103  </description>
104  </manager>
105  <manager name="DBDelTree" language="en_US">
106  <synopsis>
107  Delete DB Tree.
108  </synopsis>
109  <syntax>
110  <xi:include xpointer="xpointer(/docs/manager[@name='Login']/syntax/parameter[@name='ActionID'])" />
111  <parameter name="Family" required="true" />
112  <parameter name="Key" />
113  </syntax>
114  <description>
115  </description>
116  </manager>
117  ***/
118 
119 #define MAX_DB_FIELD 256
120 AST_MUTEX_DEFINE_STATIC(dblock);
121 static ast_cond_t dbcond;
122 static sqlite3 *astdb;
123 static pthread_t syncthread;
124 static int doexit;
125 static int dosync;
126 
127 static void db_sync(void);
128 
129 #define DEFINE_SQL_STATEMENT(stmt,sql) static sqlite3_stmt *stmt; \
130  const char stmt##_sql[] = sql;
131 
132 DEFINE_SQL_STATEMENT(put_stmt, "INSERT OR REPLACE INTO astdb (key, value) VALUES (?, ?)")
133 DEFINE_SQL_STATEMENT(get_stmt, "SELECT value FROM astdb WHERE key=?")
134 DEFINE_SQL_STATEMENT(exists_stmt, "SELECT CAST(COUNT(1) AS INTEGER) AS 'exists' FROM astdb WHERE key=?")
135 DEFINE_SQL_STATEMENT(del_stmt, "DELETE FROM astdb WHERE key=?")
136 DEFINE_SQL_STATEMENT(deltree_stmt, "DELETE FROM astdb WHERE key || '/' LIKE ? || '/' || '%'")
137 DEFINE_SQL_STATEMENT(deltree_all_stmt, "DELETE FROM astdb")
138 DEFINE_SQL_STATEMENT(gettree_stmt, "SELECT key, value FROM astdb WHERE key || '/' LIKE ? || '/' || '%' ORDER BY key")
139 DEFINE_SQL_STATEMENT(gettree_all_stmt, "SELECT key, value FROM astdb ORDER BY key")
140 DEFINE_SQL_STATEMENT(showkey_stmt, "SELECT key, value FROM astdb WHERE key LIKE '%' || '/' || ? ORDER BY key")
141 DEFINE_SQL_STATEMENT(create_astdb_stmt, "CREATE TABLE IF NOT EXISTS astdb(key VARCHAR(256), value VARCHAR(256), PRIMARY KEY(key))")
142 
143 /* This query begs an explanation:
144  *
145  * First, the parameter binding syntax used here is slightly different than the other
146  * queries in that we use a numbered parameter so that we can bind once and get the same
147  * value substituted multiple times within the executed query.
148  *
149  * Second, the key comparison is being used to find all keys that are lexicographically
150  * greater than the provided key, but less than the provided key with a high (but
151  * invalid) Unicode codepoint appended to it. This will give us all keys in the database
152  * that have 'key' as a prefix and performs much better than the equivalent "LIKE key ||
153  * '%'" operation.
154  */
155 DEFINE_SQL_STATEMENT(gettree_prefix_stmt, "SELECT key, value FROM astdb WHERE key > ?1 AND key <= ?1 || X'ffff'")
156 
157 static int init_stmt(sqlite3_stmt **stmt, const char *sql, size_t len)
158 {
159  ast_mutex_lock(&dblock);
160  if (sqlite3_prepare(astdb, sql, len, stmt, NULL) != SQLITE_OK) {
161  ast_log(LOG_WARNING, "Couldn't prepare statement '%s': %s\n", sql, sqlite3_errmsg(astdb));
162  ast_mutex_unlock(&dblock);
163  return -1;
164  }
165  ast_mutex_unlock(&dblock);
166 
167  return 0;
168 }
169 
170 /*! \internal
171  * \brief Clean up the prepared SQLite3 statement
172  * \note dblock should already be locked prior to calling this method
173  */
174 static int clean_stmt(sqlite3_stmt **stmt, const char *sql)
175 {
176  if (sqlite3_finalize(*stmt) != SQLITE_OK) {
177  ast_log(LOG_WARNING, "Couldn't finalize statement '%s': %s\n", sql, sqlite3_errmsg(astdb));
178  *stmt = NULL;
179  return -1;
180  }
181  *stmt = NULL;
182  return 0;
183 }
184 
185 /*! \internal
186  * \brief Clean up all prepared SQLite3 statements
187  * \note dblock should already be locked prior to calling this method
188  */
189 static void clean_statements(void)
190 {
191  clean_stmt(&get_stmt, get_stmt_sql);
192  clean_stmt(&exists_stmt, exists_stmt_sql);
193  clean_stmt(&del_stmt, del_stmt_sql);
194  clean_stmt(&deltree_stmt, deltree_stmt_sql);
195  clean_stmt(&deltree_all_stmt, deltree_all_stmt_sql);
196  clean_stmt(&gettree_stmt, gettree_stmt_sql);
197  clean_stmt(&gettree_all_stmt, gettree_all_stmt_sql);
198  clean_stmt(&gettree_prefix_stmt, gettree_prefix_stmt_sql);
199  clean_stmt(&showkey_stmt, showkey_stmt_sql);
200  clean_stmt(&put_stmt, put_stmt_sql);
201  clean_stmt(&create_astdb_stmt, create_astdb_stmt_sql);
202 }
203 
204 static int init_statements(void)
205 {
206  /* Don't initialize create_astdb_statement here as the astdb table needs to exist
207  * brefore these statements can be initialized */
208  return init_stmt(&get_stmt, get_stmt_sql, sizeof(get_stmt_sql))
209  || init_stmt(&exists_stmt, exists_stmt_sql, sizeof(exists_stmt_sql))
210  || init_stmt(&del_stmt, del_stmt_sql, sizeof(del_stmt_sql))
211  || init_stmt(&deltree_stmt, deltree_stmt_sql, sizeof(deltree_stmt_sql))
212  || init_stmt(&deltree_all_stmt, deltree_all_stmt_sql, sizeof(deltree_all_stmt_sql))
213  || init_stmt(&gettree_stmt, gettree_stmt_sql, sizeof(gettree_stmt_sql))
214  || init_stmt(&gettree_all_stmt, gettree_all_stmt_sql, sizeof(gettree_all_stmt_sql))
215  || init_stmt(&gettree_prefix_stmt, gettree_prefix_stmt_sql, sizeof(gettree_prefix_stmt_sql))
216  || init_stmt(&showkey_stmt, showkey_stmt_sql, sizeof(showkey_stmt_sql))
217  || init_stmt(&put_stmt, put_stmt_sql, sizeof(put_stmt_sql));
218 }
219 
220 static int convert_bdb_to_sqlite3(void)
221 {
222  char *cmd;
223  int res;
224 
225  res = ast_asprintf(&cmd, "%s/astdb2sqlite3 '%s'\n", ast_config_AST_SBIN_DIR, ast_config_AST_DB);
226  if (0 <= res) {
227  res = ast_safe_system(cmd);
228  ast_free(cmd);
229  }
230 
231  return res;
232 }
233 
234 static int db_create_astdb(void)
235 {
236  int res = 0;
237 
238  if (!create_astdb_stmt) {
239  init_stmt(&create_astdb_stmt, create_astdb_stmt_sql, sizeof(create_astdb_stmt_sql));
240  }
241 
242  ast_mutex_lock(&dblock);
243  if (sqlite3_step(create_astdb_stmt) != SQLITE_DONE) {
244  ast_log(LOG_WARNING, "Couldn't create astdb table: %s\n", sqlite3_errmsg(astdb));
245  res = -1;
246  }
247  sqlite3_reset(create_astdb_stmt);
248  db_sync();
249  ast_mutex_unlock(&dblock);
250 
251  return res;
252 }
253 
254 static int db_open(void)
255 {
256  char *dbname;
257  struct stat dont_care;
258 
259  if (!(dbname = ast_alloca(strlen(ast_config_AST_DB) + sizeof(".sqlite3")))) {
260  return -1;
261  }
262  strcpy(dbname, ast_config_AST_DB);
263  strcat(dbname, ".sqlite3");
264 
265  if (stat(dbname, &dont_care) && !stat(ast_config_AST_DB, &dont_care)) {
266  if (convert_bdb_to_sqlite3()) {
267  ast_log(LOG_ERROR, "*** Database conversion failed!\n");
268  ast_log(LOG_ERROR, "*** Asterisk now uses SQLite3 for its internal\n");
269  ast_log(LOG_ERROR, "*** database. Conversion from the old astdb\n");
270  ast_log(LOG_ERROR, "*** failed. Most likely the astdb2sqlite3 utility\n");
271  ast_log(LOG_ERROR, "*** was not selected for build. To convert the\n");
272  ast_log(LOG_ERROR, "*** old astdb, please delete '%s'\n", dbname);
273  ast_log(LOG_ERROR, "*** and re-run 'make menuselect' and select astdb2sqlite3\n");
274  ast_log(LOG_ERROR, "*** in the Utilities section, then 'make && make install'.\n");
275  ast_log(LOG_ERROR, "*** It is also imperative that the user under which\n");
276  ast_log(LOG_ERROR, "*** Asterisk runs have write permission to the directory\n");
277  ast_log(LOG_ERROR, "*** where the database resides.\n");
278  sleep(5);
279  } else {
280  ast_log(LOG_NOTICE, "Database conversion succeeded!\n");
281  }
282  }
283 
284  ast_mutex_lock(&dblock);
285  if (sqlite3_open(dbname, &astdb) != SQLITE_OK) {
286  ast_log(LOG_WARNING, "Unable to open Asterisk database '%s': %s\n", dbname, sqlite3_errmsg(astdb));
287  sqlite3_close(astdb);
288  ast_mutex_unlock(&dblock);
289  return -1;
290  }
291 
292  ast_mutex_unlock(&dblock);
293 
294  return 0;
295 }
296 
297 static int db_init(void)
298 {
299  if (astdb) {
300  return 0;
301  }
302 
303  if (db_open() || db_create_astdb() || init_statements()) {
304  return -1;
305  }
306 
307  return 0;
308 }
309 
310 /* We purposely don't lock around the sqlite3 call because the transaction
311  * calls will be called with the database lock held. For any other use, make
312  * sure to take the dblock yourself. */
313 static int db_execute_sql(const char *sql, int (*callback)(void *, int, char **, char **), void *arg)
314 {
315  char *errmsg = NULL;
316  int res =0;
317 
318  if (sqlite3_exec(astdb, sql, callback, arg, &errmsg) != SQLITE_OK) {
319  ast_log(LOG_WARNING, "Error executing SQL (%s): %s\n", sql, errmsg);
320  sqlite3_free(errmsg);
321  res = -1;
322  }
323 
324  return res;
325 }
326 
327 static int ast_db_begin_transaction(void)
328 {
329  return db_execute_sql("BEGIN TRANSACTION", NULL, NULL);
330 }
331 
332 static int ast_db_commit_transaction(void)
333 {
334  return db_execute_sql("COMMIT", NULL, NULL);
335 }
336 
337 static int ast_db_rollback_transaction(void)
338 {
339  return db_execute_sql("ROLLBACK", NULL, NULL);
340 }
341 
342 int ast_db_put(const char *family, const char *key, const char *value)
343 {
344  char fullkey[MAX_DB_FIELD];
345  size_t fullkey_len;
346  int res = 0;
347 
348  if (strlen(family) + strlen(key) + 2 > sizeof(fullkey) - 1) {
349  ast_log(LOG_WARNING, "Family and key length must be less than %zu bytes\n", sizeof(fullkey) - 3);
350  return -1;
351  }
352 
353  fullkey_len = snprintf(fullkey, sizeof(fullkey), "/%s/%s", family, key);
354 
355  ast_mutex_lock(&dblock);
356  if (sqlite3_bind_text(put_stmt, 1, fullkey, fullkey_len, SQLITE_STATIC) != SQLITE_OK) {
357  ast_log(LOG_WARNING, "Couldn't bind key to stmt: %s\n", sqlite3_errmsg(astdb));
358  res = -1;
359  } else if (sqlite3_bind_text(put_stmt, 2, value, -1, SQLITE_STATIC) != SQLITE_OK) {
360  ast_log(LOG_WARNING, "Couldn't bind value to stmt: %s\n", sqlite3_errmsg(astdb));
361  res = -1;
362  } else if (sqlite3_step(put_stmt) != SQLITE_DONE) {
363  ast_log(LOG_WARNING, "Couldn't execute statement: %s\n", sqlite3_errmsg(astdb));
364  res = -1;
365  }
366 
367  sqlite3_reset(put_stmt);
368  db_sync();
369  ast_mutex_unlock(&dblock);
370 
371  return res;
372 }
373 
374 /*!
375  * \internal
376  * \brief Get key value specified by family/key.
377  *
378  * Gets the value associated with the specified \a family and \a key, and
379  * stores it, either into the fixed sized buffer specified by \a buffer
380  * and \a bufferlen, or as a heap allocated string if \a bufferlen is -1.
381  *
382  * \note If \a bufferlen is -1, \a buffer points to heap allocated memory
383  * and must be freed by calling ast_free().
384  *
385  * \retval -1 An error occurred
386  * \retval 0 Success
387  */
388 static int db_get_common(const char *family, const char *key, char **buffer, int bufferlen)
389 {
390  const unsigned char *result;
391  char fullkey[MAX_DB_FIELD];
392  size_t fullkey_len;
393  int res = 0;
394 
395  if (strlen(family) + strlen(key) + 2 > sizeof(fullkey) - 1) {
396  ast_log(LOG_WARNING, "Family and key length must be less than %zu bytes\n", sizeof(fullkey) - 3);
397  return -1;
398  }
399 
400  fullkey_len = snprintf(fullkey, sizeof(fullkey), "/%s/%s", family, key);
401 
402  ast_mutex_lock(&dblock);
403  if (sqlite3_bind_text(get_stmt, 1, fullkey, fullkey_len, SQLITE_STATIC) != SQLITE_OK) {
404  ast_log(LOG_WARNING, "Couldn't bind key to stmt: %s\n", sqlite3_errmsg(astdb));
405  res = -1;
406  } else if (sqlite3_step(get_stmt) != SQLITE_ROW) {
407  ast_debug(1, "Unable to find key '%s' in family '%s'\n", key, family);
408  res = -1;
409  } else if (!(result = sqlite3_column_text(get_stmt, 0))) {
410  ast_log(LOG_WARNING, "Couldn't get value\n");
411  res = -1;
412  } else {
413  const char *value = (const char *) result;
414 
415  if (bufferlen == -1) {
416  *buffer = ast_strdup(value);
417  } else {
418  ast_copy_string(*buffer, value, bufferlen);
419  }
420  }
421  sqlite3_reset(get_stmt);
422  ast_mutex_unlock(&dblock);
423 
424  return res;
425 }
426 
427 int ast_db_get(const char *family, const char *key, char *value, int valuelen)
428 {
429  ast_assert(value != NULL);
430 
431  /* Make sure we initialize */
432  value[0] = 0;
433 
434  return db_get_common(family, key, &value, valuelen);
435 }
436 
437 int ast_db_get_allocated(const char *family, const char *key, char **out)
438 {
439  *out = NULL;
440 
441  return db_get_common(family, key, out, -1);
442 }
443 
444 int ast_db_exists(const char *family, const char *key)
445 {
446  int result;
447  char fullkey[MAX_DB_FIELD];
448  size_t fullkey_len;
449  int res = 0;
450 
451  fullkey_len = snprintf(fullkey, sizeof(fullkey), "/%s/%s", family, key);
452  if (fullkey_len >= sizeof(fullkey)) {
453  ast_log(LOG_WARNING, "Family and key length must be less than %zu bytes\n", sizeof(fullkey) - 3);
454  return -1;
455  }
456 
457  ast_mutex_lock(&dblock);
458  res = sqlite3_bind_text(exists_stmt, 1, fullkey, fullkey_len, SQLITE_STATIC);
459  if (res != SQLITE_OK) {
460  ast_log(LOG_WARNING, "Couldn't bind key to stmt: %d:%s\n", res, sqlite3_errmsg(astdb));
461  res = 0;
462  } else if (sqlite3_step(exists_stmt) != SQLITE_ROW) {
463  res = 0;
464  } else if (!(result = sqlite3_column_int(exists_stmt, 0))) {
465  res = 0;
466  } else {
467  res = result;
468  }
469  sqlite3_reset(exists_stmt);
470  ast_mutex_unlock(&dblock);
471 
472  return res;
473 }
474 
475 
476 int ast_db_del(const char *family, const char *key)
477 {
478  char fullkey[MAX_DB_FIELD];
479  size_t fullkey_len;
480  int res = 0;
481 
482  if (strlen(family) + strlen(key) + 2 > sizeof(fullkey) - 1) {
483  ast_log(LOG_WARNING, "Family and key length must be less than %zu bytes\n", sizeof(fullkey) - 3);
484  return -1;
485  }
486 
487  fullkey_len = snprintf(fullkey, sizeof(fullkey), "/%s/%s", family, key);
488 
489  ast_mutex_lock(&dblock);
490  if (sqlite3_bind_text(del_stmt, 1, fullkey, fullkey_len, SQLITE_STATIC) != SQLITE_OK) {
491  ast_log(LOG_WARNING, "Couldn't bind key to stmt: %s\n", sqlite3_errmsg(astdb));
492  res = -1;
493  } else if (sqlite3_step(del_stmt) != SQLITE_DONE) {
494  ast_debug(1, "Unable to find key '%s' in family '%s'\n", key, family);
495  res = -1;
496  }
497  sqlite3_reset(del_stmt);
498  db_sync();
499  ast_mutex_unlock(&dblock);
500 
501  return res;
502 }
503 
504 int ast_db_del2(const char *family, const char *key)
505 {
506  char fullkey[MAX_DB_FIELD];
507  char tmp[1];
508  size_t fullkey_len;
509  int mres, res = 0;
510 
511  if (strlen(family) + strlen(key) + 2 > sizeof(fullkey) - 1) {
512  ast_log(LOG_WARNING, "Family and key length must be less than %zu bytes\n", sizeof(fullkey) - 3);
513  return -1;
514  }
515 
516  fullkey_len = snprintf(fullkey, sizeof(fullkey), "/%s/%s", family, key);
517 
518  ast_mutex_lock(&dblock);
519  if (ast_db_get(family, key, tmp, sizeof(tmp))) {
520  ast_log(LOG_WARNING, "AstDB key %s does not exist\n", fullkey);
521  res = -1;
522  } else if (sqlite3_bind_text(del_stmt, 1, fullkey, fullkey_len, SQLITE_STATIC) != SQLITE_OK) {
523  ast_log(LOG_WARNING, "Couldn't bind key to stmt: %s\n", sqlite3_errmsg(astdb));
524  res = -1;
525  } else if ((mres = sqlite3_step(del_stmt) != SQLITE_DONE)) {
526  ast_log(LOG_WARNING, "AstDB error (%s): %s\n", fullkey, sqlite3_errstr(mres));
527  res = -1;
528  }
529  sqlite3_reset(del_stmt);
530  db_sync();
531  ast_mutex_unlock(&dblock);
532 
533  return res;
534 }
535 
536 int ast_db_deltree(const char *family, const char *keytree)
537 {
538  sqlite3_stmt *stmt = deltree_stmt;
539  char prefix[MAX_DB_FIELD];
540  int res = 0;
541 
542  if (!ast_strlen_zero(family)) {
543  if (!ast_strlen_zero(keytree)) {
544  /* Family and key tree */
545  snprintf(prefix, sizeof(prefix), "/%s/%s", family, keytree);
546  } else {
547  /* Family only */
548  snprintf(prefix, sizeof(prefix), "/%s", family);
549  }
550  } else {
551  prefix[0] = '\0';
552  stmt = deltree_all_stmt;
553  }
554 
555  ast_mutex_lock(&dblock);
556  if (!ast_strlen_zero(prefix) && (sqlite3_bind_text(stmt, 1, prefix, -1, SQLITE_STATIC) != SQLITE_OK)) {
557  ast_log(LOG_WARNING, "Couldn't bind %s to stmt: %s\n", prefix, sqlite3_errmsg(astdb));
558  res = -1;
559  } else if (sqlite3_step(stmt) != SQLITE_DONE) {
560  ast_log(LOG_WARNING, "Couldn't execute stmt: %s\n", sqlite3_errmsg(astdb));
561  res = -1;
562  }
563  res = sqlite3_changes(astdb);
564  sqlite3_reset(stmt);
565  db_sync();
566  ast_mutex_unlock(&dblock);
567 
568  return res;
569 }
570 
571 static struct ast_db_entry *db_gettree_common(sqlite3_stmt *stmt)
572 {
573  struct ast_db_entry *head = NULL, *prev = NULL, *cur;
574 
575  while (sqlite3_step(stmt) == SQLITE_ROW) {
576  const char *key, *value;
577  size_t key_len, value_len;
578 
579  key = (const char *) sqlite3_column_text(stmt, 0);
580  value = (const char *) sqlite3_column_text(stmt, 1);
581 
582  if (!key || !value) {
583  break;
584  }
585 
586  key_len = strlen(key);
587  value_len = strlen(value);
588 
589  cur = ast_malloc(sizeof(*cur) + key_len + value_len + 2);
590  if (!cur) {
591  break;
592  }
593 
594  cur->next = NULL;
595  cur->key = cur->data + value_len + 1;
596  memcpy(cur->data, value, value_len + 1);
597  memcpy(cur->key, key, key_len + 1);
598 
599  if (prev) {
600  prev->next = cur;
601  } else {
602  head = cur;
603  }
604  prev = cur;
605  }
606 
607  return head;
608 }
609 
610 struct ast_db_entry *ast_db_gettree(const char *family, const char *keytree)
611 {
612  char prefix[MAX_DB_FIELD];
613  sqlite3_stmt *stmt = gettree_stmt;
614  size_t res = 0;
615  struct ast_db_entry *ret;
616 
617  if (!ast_strlen_zero(family)) {
618  if (!ast_strlen_zero(keytree)) {
619  /* Family and key tree */
620  res = snprintf(prefix, sizeof(prefix), "/%s/%s", family, keytree);
621  } else {
622  /* Family only */
623  res = snprintf(prefix, sizeof(prefix), "/%s", family);
624  }
625 
626  if (res >= sizeof(prefix)) {
627  ast_log(LOG_WARNING, "Requested prefix is too long: %s\n", keytree);
628  return NULL;
629  }
630  } else {
631  prefix[0] = '\0';
632  stmt = gettree_all_stmt;
633  }
634 
635  ast_mutex_lock(&dblock);
636  if (res && (sqlite3_bind_text(stmt, 1, prefix, res, SQLITE_STATIC) != SQLITE_OK)) {
637  ast_log(LOG_WARNING, "Could not bind %s to stmt: %s\n", prefix, sqlite3_errmsg(astdb));
638  sqlite3_reset(stmt);
639  ast_mutex_unlock(&dblock);
640  return NULL;
641  }
642 
643  ret = db_gettree_common(stmt);
644  sqlite3_reset(stmt);
645  ast_mutex_unlock(&dblock);
646 
647  return ret;
648 }
649 
650 struct ast_db_entry *ast_db_gettree_by_prefix(const char *family, const char *key_prefix)
651 {
652  char prefix[MAX_DB_FIELD];
653  size_t res;
654  struct ast_db_entry *ret;
655 
656  res = snprintf(prefix, sizeof(prefix), "/%s/%s", family, key_prefix);
657  if (res >= sizeof(prefix)) {
658  ast_log(LOG_WARNING, "Requested key prefix is too long: %s\n", key_prefix);
659  return NULL;
660  }
661 
662  ast_mutex_lock(&dblock);
663  if (sqlite3_bind_text(gettree_prefix_stmt, 1, prefix, res, SQLITE_STATIC) != SQLITE_OK) {
664  ast_log(LOG_WARNING, "Could not bind %s to stmt: %s\n", prefix, sqlite3_errmsg(astdb));
665  sqlite3_reset(gettree_prefix_stmt);
666  ast_mutex_unlock(&dblock);
667  return NULL;
668  }
669 
670  ret = db_gettree_common(gettree_prefix_stmt);
671  sqlite3_reset(gettree_prefix_stmt);
672  ast_mutex_unlock(&dblock);
673 
674  return ret;
675 }
676 
677 void ast_db_freetree(struct ast_db_entry *dbe)
678 {
679  struct ast_db_entry *last;
680  while (dbe) {
681  last = dbe;
682  dbe = dbe->next;
683  ast_free(last);
684  }
685 }
686 
687 static char *handle_cli_database_put(struct ast_cli_entry *e, int cmd, struct ast_cli_args *a)
688 {
689  int res;
690 
691  switch (cmd) {
692  case CLI_INIT:
693  e->command = "database put";
694  e->usage =
695  "Usage: database put <family> <key> <value>\n"
696  " Adds or updates an entry in the Asterisk database for\n"
697  " a given family, key, and value.\n";
698  return NULL;
699  case CLI_GENERATE:
700  return NULL;
701  }
702 
703  if (a->argc != 5)
704  return CLI_SHOWUSAGE;
705  res = ast_db_put(a->argv[2], a->argv[3], a->argv[4]);
706  if (res) {
707  ast_cli(a->fd, "Failed to update entry\n");
708  } else {
709  ast_cli(a->fd, "Updated database successfully\n");
710  }
711  return CLI_SUCCESS;
712 }
713 
714 static char *handle_cli_database_get(struct ast_cli_entry *e, int cmd, struct ast_cli_args *a)
715 {
716  int res;
717  char tmp[MAX_DB_FIELD];
718 
719  switch (cmd) {
720  case CLI_INIT:
721  e->command = "database get";
722  e->usage =
723  "Usage: database get <family> <key>\n"
724  " Retrieves an entry in the Asterisk database for a given\n"
725  " family and key.\n";
726  return NULL;
727  case CLI_GENERATE:
728  return NULL;
729  }
730 
731  if (a->argc != 4)
732  return CLI_SHOWUSAGE;
733  res = ast_db_get(a->argv[2], a->argv[3], tmp, sizeof(tmp));
734  if (res) {
735  ast_cli(a->fd, "Database entry not found.\n");
736  } else {
737  ast_cli(a->fd, "Value: %s\n", tmp);
738  }
739  return CLI_SUCCESS;
740 }
741 
742 static char *handle_cli_database_del(struct ast_cli_entry *e, int cmd, struct ast_cli_args *a)
743 {
744  int res;
745 
746  switch (cmd) {
747  case CLI_INIT:
748  e->command = "database del";
749  e->usage =
750  "Usage: database del <family> <key>\n"
751  " Deletes an entry in the Asterisk database for a given\n"
752  " family and key.\n";
753  return NULL;
754  case CLI_GENERATE:
755  return NULL;
756  }
757 
758  if (a->argc != 4)
759  return CLI_SHOWUSAGE;
760  res = ast_db_del2(a->argv[2], a->argv[3]);
761  if (res) {
762  ast_cli(a->fd, "Database entry could not be removed.\n");
763  } else {
764  ast_cli(a->fd, "Database entry removed.\n");
765  }
766  return CLI_SUCCESS;
767 }
768 
769 static char *handle_cli_database_deltree(struct ast_cli_entry *e, int cmd, struct ast_cli_args *a)
770 {
771  int num_deleted;
772 
773  switch (cmd) {
774  case CLI_INIT:
775  e->command = "database deltree";
776  e->usage =
777  "Usage: database deltree <family> [keytree]\n"
778  " OR: database deltree <family>[/keytree]\n"
779  " Deletes a family or specific keytree within a family\n"
780  " in the Asterisk database. The two arguments may be\n"
781  " separated by either a space or a slash.\n";
782  return NULL;
783  case CLI_GENERATE:
784  return NULL;
785  }
786 
787  if ((a->argc < 3) || (a->argc > 4))
788  return CLI_SHOWUSAGE;
789  if (a->argc == 4) {
790  num_deleted = ast_db_deltree(a->argv[2], a->argv[3]);
791  } else {
792  num_deleted = ast_db_deltree(a->argv[2], NULL);
793  }
794  if (num_deleted < 0) {
795  ast_cli(a->fd, "Database unavailable.\n");
796  } else if (num_deleted == 0) {
797  ast_cli(a->fd, "Database entries do not exist.\n");
798  } else {
799  ast_cli(a->fd, "%d database entries removed.\n",num_deleted);
800  }
801  return CLI_SUCCESS;
802 }
803 
804 static char *handle_cli_database_show(struct ast_cli_entry *e, int cmd, struct ast_cli_args *a)
805 {
806  char prefix[MAX_DB_FIELD];
807  int counter = 0;
808  sqlite3_stmt *stmt = gettree_stmt;
809 
810  switch (cmd) {
811  case CLI_INIT:
812  e->command = "database show";
813  e->usage =
814  "Usage: database show [family [keytree]]\n"
815  " OR: database show [family[/keytree]]\n"
816  " Shows Asterisk database contents, optionally restricted\n"
817  " to a given family, or family and keytree. The two arguments\n"
818  " may be separated either by a space or by a slash.\n";
819  return NULL;
820  case CLI_GENERATE:
821  return NULL;
822  }
823 
824  if (a->argc == 4) {
825  /* Family and key tree */
826  snprintf(prefix, sizeof(prefix), "/%s/%s", a->argv[2], a->argv[3]);
827  } else if (a->argc == 3) {
828  /* Family only */
829  snprintf(prefix, sizeof(prefix), "/%s", a->argv[2]);
830  } else if (a->argc == 2) {
831  /* Neither */
832  prefix[0] = '\0';
833  stmt = gettree_all_stmt;
834 
835  } else {
836  return CLI_SHOWUSAGE;
837  }
838 
839  ast_mutex_lock(&dblock);
840  if (!ast_strlen_zero(prefix) && (sqlite3_bind_text(stmt, 1, prefix, -1, SQLITE_STATIC) != SQLITE_OK)) {
841  ast_log(LOG_WARNING, "Couldn't bind %s to stmt: %s\n", prefix, sqlite3_errmsg(astdb));
842  sqlite3_reset(stmt);
843  ast_mutex_unlock(&dblock);
844  return NULL;
845  }
846 
847  while (sqlite3_step(stmt) == SQLITE_ROW) {
848  const char *key_s, *value_s;
849  if (!(key_s = (const char *) sqlite3_column_text(stmt, 0))) {
850  ast_log(LOG_WARNING, "Skipping invalid key!\n");
851  continue;
852  }
853  if (!(value_s = (const char *) sqlite3_column_text(stmt, 1))) {
854  ast_log(LOG_WARNING, "Skipping invalid value!\n");
855  continue;
856  }
857  ++counter;
858  ast_cli(a->fd, "%-50s: %-25s\n", key_s, value_s);
859  }
860 
861  sqlite3_reset(stmt);
862  ast_mutex_unlock(&dblock);
863 
864  ast_cli(a->fd, "%d results found.\n", counter);
865  return CLI_SUCCESS;
866 }
867 
868 static char *handle_cli_database_showkey(struct ast_cli_entry *e, int cmd, struct ast_cli_args *a)
869 {
870  int counter = 0;
871 
872  switch (cmd) {
873  case CLI_INIT:
874  e->command = "database showkey";
875  e->usage =
876  "Usage: database showkey <keytree>\n"
877  " Shows Asterisk database contents, restricted to a given key.\n";
878  return NULL;
879  case CLI_GENERATE:
880  return NULL;
881  }
882 
883  if (a->argc != 3) {
884  return CLI_SHOWUSAGE;
885  }
886 
887  ast_mutex_lock(&dblock);
888  if (!ast_strlen_zero(a->argv[2]) && (sqlite3_bind_text(showkey_stmt, 1, a->argv[2], -1, SQLITE_STATIC) != SQLITE_OK)) {
889  ast_log(LOG_WARNING, "Couldn't bind %s to stmt: %s\n", a->argv[2], sqlite3_errmsg(astdb));
890  sqlite3_reset(showkey_stmt);
891  ast_mutex_unlock(&dblock);
892  return NULL;
893  }
894 
895  while (sqlite3_step(showkey_stmt) == SQLITE_ROW) {
896  const char *key_s, *value_s;
897  if (!(key_s = (const char *) sqlite3_column_text(showkey_stmt, 0))) {
898  break;
899  }
900  if (!(value_s = (const char *) sqlite3_column_text(showkey_stmt, 1))) {
901  break;
902  }
903  ++counter;
904  ast_cli(a->fd, "%-50s: %-25s\n", key_s, value_s);
905  }
906  sqlite3_reset(showkey_stmt);
907  ast_mutex_unlock(&dblock);
908 
909  ast_cli(a->fd, "%d results found.\n", counter);
910  return CLI_SUCCESS;
911 }
912 
913 static int display_results(void *arg, int columns, char **values, char **colnames)
914 {
915  struct ast_cli_args *a = arg;
916  size_t x;
917 
918  for (x = 0; x < columns; x++) {
919  ast_cli(a->fd, "%-5s: %-50s\n", colnames[x], values[x]);
920  }
921  ast_cli(a->fd, "\n");
922 
923  return 0;
924 }
925 
926 static char *handle_cli_database_query(struct ast_cli_entry *e, int cmd, struct ast_cli_args *a)
927 {
928 
929  switch (cmd) {
930  case CLI_INIT:
931  e->command = "database query";
932  e->usage =
933  "Usage: database query \"<SQL Statement>\"\n"
934  " Run a user-specified SQL query on the database. Be careful.\n";
935  return NULL;
936  case CLI_GENERATE:
937  return NULL;
938  }
939 
940  if (a->argc != 3) {
941  return CLI_SHOWUSAGE;
942  }
943 
944  ast_mutex_lock(&dblock);
945  db_execute_sql(a->argv[2], display_results, a);
946  db_sync(); /* Go ahead and sync the db in case they write */
947  ast_mutex_unlock(&dblock);
948 
949  return CLI_SUCCESS;
950 }
951 
952 static struct ast_cli_entry cli_database[] = {
953  AST_CLI_DEFINE(handle_cli_database_show, "Shows database contents"),
954  AST_CLI_DEFINE(handle_cli_database_showkey, "Shows database contents"),
955  AST_CLI_DEFINE(handle_cli_database_get, "Gets database value"),
956  AST_CLI_DEFINE(handle_cli_database_put, "Adds/updates database value"),
957  AST_CLI_DEFINE(handle_cli_database_del, "Removes database key/value"),
958  AST_CLI_DEFINE(handle_cli_database_deltree, "Removes database keytree/values"),
959  AST_CLI_DEFINE(handle_cli_database_query, "Run a user-specified query on the astdb"),
960 };
961 
962 static int manager_dbput(struct mansession *s, const struct message *m)
963 {
964  const char *family = astman_get_header(m, "Family");
965  const char *key = astman_get_header(m, "Key");
966  const char *val = astman_get_header(m, "Val");
967  int res;
968 
969  if (ast_strlen_zero(family)) {
970  astman_send_error(s, m, "No family specified");
971  return 0;
972  }
973  if (ast_strlen_zero(key)) {
974  astman_send_error(s, m, "No key specified");
975  return 0;
976  }
977 
978  res = ast_db_put(family, key, S_OR(val, ""));
979  if (res) {
980  astman_send_error(s, m, "Failed to update entry");
981  } else {
982  astman_send_ack(s, m, "Updated database successfully");
983  }
984  return 0;
985 }
986 
987 static int manager_dbget(struct mansession *s, const struct message *m)
988 {
989  const char *id = astman_get_header(m,"ActionID");
990  char idText[256];
991  const char *family = astman_get_header(m, "Family");
992  const char *key = astman_get_header(m, "Key");
993  char tmp[MAX_DB_FIELD];
994  int res;
995 
996  if (ast_strlen_zero(family)) {
997  astman_send_error(s, m, "No family specified.");
998  return 0;
999  }
1000  if (ast_strlen_zero(key)) {
1001  astman_send_error(s, m, "No key specified.");
1002  return 0;
1003  }
1004 
1005  idText[0] = '\0';
1006  if (!ast_strlen_zero(id))
1007  snprintf(idText, sizeof(idText) ,"ActionID: %s\r\n", id);
1008 
1009  res = ast_db_get(family, key, tmp, sizeof(tmp));
1010  if (res) {
1011  astman_send_error(s, m, "Database entry not found");
1012  } else {
1013  astman_send_listack(s, m, "Result will follow", "start");
1014 
1015  astman_append(s, "Event: DBGetResponse\r\n"
1016  "Family: %s\r\n"
1017  "Key: %s\r\n"
1018  "Val: %s\r\n"
1019  "%s"
1020  "\r\n",
1021  family, key, tmp, idText);
1022 
1023  astman_send_list_complete_start(s, m, "DBGetComplete", 1);
1025  }
1026  return 0;
1027 }
1028 
1029 static int manager_db_tree_get(struct mansession *s, const struct message *m)
1030 {
1031  char prefix[MAX_DB_FIELD];
1032  char idText[256];
1033  const char *id = astman_get_header(m,"ActionID");
1034  const char *family = astman_get_header(m, "Family");
1035  const char *key = astman_get_header(m, "Key");
1036  sqlite3_stmt *stmt = gettree_stmt;
1037  int count = 0;
1038 
1039  if (!ast_strlen_zero(family) && !ast_strlen_zero(key)) {
1040  /* Family and key tree */
1041  snprintf(prefix, sizeof(prefix), "/%s/%s", family, key);
1042  } else if (!ast_strlen_zero(family)) {
1043  /* Family only */
1044  snprintf(prefix, sizeof(prefix), "/%s", family);
1045  } else {
1046  /* Neither */
1047  prefix[0] = '\0';
1048  stmt = gettree_all_stmt;
1049  }
1050 
1051  idText[0] = '\0';
1052  if (!ast_strlen_zero(id)) {
1053  snprintf(idText, sizeof(idText) ,"ActionID: %s\r\n", id);
1054  }
1055 
1056  ast_mutex_lock(&dblock);
1057  if (!ast_strlen_zero(prefix) && (sqlite3_bind_text(stmt, 1, prefix, -1, SQLITE_STATIC) != SQLITE_OK)) {
1058  ast_log(LOG_WARNING, "Couldn't bind %s to stmt: %s\n", prefix, sqlite3_errmsg(astdb));
1059  sqlite3_reset(stmt);
1060  ast_mutex_unlock(&dblock);
1061  astman_send_error(s, m, "Unable to search database");
1062  return 0;
1063  }
1064 
1065  astman_send_listack(s, m, "Result will follow", "start");
1066 
1067  while (sqlite3_step(stmt) == SQLITE_ROW) {
1068  const char *key_s, *value_s;
1069  if (!(key_s = (const char *) sqlite3_column_text(stmt, 0))) {
1070  ast_log(LOG_WARNING, "Skipping invalid key!\n");
1071  continue;
1072  }
1073  if (!(value_s = (const char *) sqlite3_column_text(stmt, 1))) {
1074  ast_log(LOG_WARNING, "Skipping invalid value!\n");
1075  continue;
1076  }
1077  astman_append(s, "Event: DBGetTreeResponse\r\n"
1078  "Key: %s\r\n"
1079  "Val: %s\r\n"
1080  "%s"
1081  "\r\n",
1082  key_s, value_s, idText);
1083  count++;
1084  }
1085 
1086  sqlite3_reset(stmt);
1087  ast_mutex_unlock(&dblock);
1088 
1089  astman_send_list_complete_start(s, m, "DBGetTreeComplete", count);
1091 
1092  return 0;
1093 }
1094 
1095 static int manager_dbdel(struct mansession *s, const struct message *m)
1096 {
1097  const char *family = astman_get_header(m, "Family");
1098  const char *key = astman_get_header(m, "Key");
1099  int res;
1100 
1101  if (ast_strlen_zero(family)) {
1102  astman_send_error(s, m, "No family specified.");
1103  return 0;
1104  }
1105 
1106  if (ast_strlen_zero(key)) {
1107  astman_send_error(s, m, "No key specified.");
1108  return 0;
1109  }
1110 
1111  res = ast_db_del2(family, key);
1112  if (res)
1113  astman_send_error(s, m, "Database entry could not be deleted");
1114  else
1115  astman_send_ack(s, m, "Key deleted successfully");
1116 
1117  return 0;
1118 }
1119 
1120 static int manager_dbdeltree(struct mansession *s, const struct message *m)
1121 {
1122  const char *family = astman_get_header(m, "Family");
1123  const char *key = astman_get_header(m, "Key");
1124  int num_deleted;
1125 
1126  if (ast_strlen_zero(family)) {
1127  astman_send_error(s, m, "No family specified.");
1128  return 0;
1129  }
1130 
1131  if (!ast_strlen_zero(key)) {
1132  num_deleted = ast_db_deltree(family, key);
1133  } else {
1134  num_deleted = ast_db_deltree(family, NULL);
1135  }
1136 
1137  if (num_deleted < 0) {
1138  astman_send_error(s, m, "Database unavailable");
1139  } else if (num_deleted == 0) {
1140  astman_send_error(s, m, "Database entry not found");
1141  } else {
1142  astman_send_ack(s, m, "Key tree deleted successfully");
1143  }
1144 
1145  return 0;
1146 }
1147 
1148 /*!
1149  * \internal
1150  * \brief Signal the astdb sync thread to do its thing.
1151  *
1152  * \note dblock is assumed to be held when calling this function.
1153  */
1154 static void db_sync(void)
1155 {
1156  dosync = 1;
1157  ast_cond_signal(&dbcond);
1158 }
1159 
1160 /*!
1161  * \internal
1162  * \brief astdb sync thread
1163  *
1164  * This thread is in charge of syncing astdb to disk after a change.
1165  * By pushing it off to this thread to take care of, this I/O bound operation
1166  * will not block other threads from performing other critical processing.
1167  * If changes happen rapidly, this thread will also ensure that the sync
1168  * operations are rate limited.
1169  */
1170 static void *db_sync_thread(void *data)
1171 {
1172  ast_mutex_lock(&dblock);
1173  ast_db_begin_transaction();
1174  for (;;) {
1175  /* If dosync is set, db_sync() was called during sleep(1),
1176  * and the pending transaction should be committed.
1177  * Otherwise, block until db_sync() is called.
1178  */
1179  while (!dosync) {
1180  ast_cond_wait(&dbcond, &dblock);
1181  }
1182  dosync = 0;
1183  if (ast_db_commit_transaction()) {
1184  ast_db_rollback_transaction();
1185  }
1186  if (doexit) {
1187  ast_mutex_unlock(&dblock);
1188  break;
1189  }
1190  ast_db_begin_transaction();
1191  ast_mutex_unlock(&dblock);
1192  sleep(1);
1193  ast_mutex_lock(&dblock);
1194  }
1195 
1196  return NULL;
1197 }
1198 
1199 /*!
1200  * \internal
1201  * \brief Clean up resources on Asterisk shutdown
1202  */
1203 static void astdb_atexit(void)
1204 {
1205  ast_cli_unregister_multiple(cli_database, ARRAY_LEN(cli_database));
1206  ast_manager_unregister("DBGet");
1207  ast_manager_unregister("DBGetTree");
1208  ast_manager_unregister("DBPut");
1209  ast_manager_unregister("DBDel");
1210  ast_manager_unregister("DBDelTree");
1211 
1212  /* Set doexit to 1 to kill thread. db_sync must be called with
1213  * mutex held. */
1214  ast_mutex_lock(&dblock);
1215  doexit = 1;
1216  db_sync();
1217  ast_mutex_unlock(&dblock);
1218 
1219  pthread_join(syncthread, NULL);
1220  ast_mutex_lock(&dblock);
1221  clean_statements();
1222  if (sqlite3_close(astdb) == SQLITE_OK) {
1223  astdb = NULL;
1224  }
1225  ast_mutex_unlock(&dblock);
1226 }
1227 
1228 int astdb_init(void)
1229 {
1230  ast_cond_init(&dbcond, NULL);
1231 
1232  if (db_init()) {
1233  return -1;
1234  }
1235 
1236  if (ast_pthread_create_background(&syncthread, NULL, db_sync_thread, NULL)) {
1237  return -1;
1238  }
1239 
1240  ast_register_atexit(astdb_atexit);
1241  ast_cli_register_multiple(cli_database, ARRAY_LEN(cli_database));
1242  ast_manager_register_xml_core("DBGet", EVENT_FLAG_SYSTEM | EVENT_FLAG_REPORTING, manager_dbget);
1243  ast_manager_register_xml_core("DBGetTree", EVENT_FLAG_SYSTEM | EVENT_FLAG_REPORTING, manager_db_tree_get);
1244  ast_manager_register_xml_core("DBPut", EVENT_FLAG_SYSTEM, manager_dbput);
1245  ast_manager_register_xml_core("DBDel", EVENT_FLAG_SYSTEM, manager_dbdel);
1246  ast_manager_register_xml_core("DBDelTree", EVENT_FLAG_SYSTEM, manager_dbdeltree);
1247  return 0;
1248 }
static int db_open(struct realtime_sqlite3_db *db)
Open a database and appropriately set debugging on the db handle.
void astman_append(struct mansession *s, const char *fmt,...)
Definition: manager.c:3310
Asterisk main include file. File version handling, generic pbx functions.
static void * db_sync_thread(void *data)
Wrap commands in transactions increased write performance.
int ast_cli_unregister_multiple(struct ast_cli_entry *e, int len)
Unregister multiple commands.
Definition: clicompat.c:30
int ast_db_exists(const char *family, const char *key)
Check if family/key exitsts.
Definition: main/db.c:444
Convenient Signal Processing routines.
void astman_send_list_complete_start(struct mansession *s, const struct message *m, const char *event_name, int count)
Start the list complete event.
Definition: manager.c:3467
descriptor for a cli entry.
Definition: cli.h:171
int ast_db_del2(const char *family, const char *key)
Same as ast_db_del, but with more stringent error checking.
Definition: main/db.c:504
void ast_db_freetree(struct ast_db_entry *dbe)
Free structure created by ast_db_gettree()
Definition: main/db.c:677
#define ast_cli_register_multiple(e, len)
Register multiple commands.
Definition: cli.h:265
void astman_send_ack(struct mansession *s, const struct message *m, char *msg)
Send ack in manager transaction.
Definition: manager.c:3421
#define ast_strdup(str)
A wrapper for strdup()
Definition: astmm.h:241
Generic File Format Support. Should be included by clients of the file handling routines. File service providers should instead include mod_format.h.
struct ast_db_entry * ast_db_gettree(const char *family, const char *keytree)
Get a list of values within the astdb tree.
Definition: main/db.c:610
#define ast_manager_register_xml_core(action, authority, func)
Register a manager callback using XML documentation to describe the manager.
Definition: manager.h:202
int astdb_init(void)
Definition: main/db.c:1228
int ast_db_del(const char *family, const char *key)
Delete entry in astdb.
Definition: main/db.c:476
Utility functions.
#define ast_asprintf(ret, fmt,...)
A wrapper for asprintf()
Definition: astmm.h:267
const char * astman_get_header(const struct message *m, char *var)
Get header from manager transaction.
Definition: manager.c:3050
int ast_db_get(const char *family, const char *key, char *value, int valuelen)
Get key value specified by family/key.
Definition: main/db.c:427
General Asterisk PBX channel definitions.
Asterisk file paths, configured in asterisk.conf.
void astman_send_list_complete_end(struct mansession *s)
End the list complete event.
Definition: manager.c:3475
In case you didn't read that giant block of text above the mansession_session struct, the mansession is named this solely to keep the API the same in Asterisk. This structure really represents data that is different from Manager action to Manager action. The mansession_session pointer contained within points to session-specific data.
Definition: manager.c:1785
int ast_register_atexit(void(*func)(void))
Register a function to be executed before Asterisk exits.
Definition: clicompat.c:13
#define ast_malloc(len)
A wrapper for malloc()
Definition: astmm.h:191
#define ast_debug(level,...)
Log a DEBUG message.
#define ast_alloca(size)
call __builtin_alloca to ensure we get gcc builtin semantics
Definition: astmm.h:288
int ast_manager_unregister(const char *action)
Unregister a registered manager command.
Definition: manager.c:8057
The AMI - Asterisk Manager Interface - is a TCP protocol created to manage Asterisk with third-party ...
int ast_safe_system(const char *s)
Safely spawn an OS shell command while closing file descriptors.
Definition: extconf.c:829
struct ast_db_entry * ast_db_gettree_by_prefix(const char *family, const char *key_prefix)
Get a list of values with the given key prefix.
Definition: main/db.c:650
Definition: astdb.h:31
static char * columns
char * command
Definition: cli.h:186
Prototypes for public functions only of internal interest,.
const char * usage
Definition: cli.h:177
Standard Command Line Interface.
void ast_copy_string(char *dst, const char *src, size_t size)
Size-limited null-terminating string copy.
Definition: strings.h:425
#define S_OR(a, b)
returns the equivalent of logic or for strings: first one if not empty, otherwise second one...
Definition: strings.h:80
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: main/db.c:437
int ast_db_put(const char *family, const char *key, const char *value)
Store value addressed by family/key.
Definition: main/db.c:342
void astman_send_error(struct mansession *s, const struct message *m, char *error)
Send error in manager transaction.
Definition: manager.c:3389
Persistent data storage (akin to *doze registry)
Application convenience functions, designed to give consistent look and feel to Asterisk apps...
int ast_db_deltree(const char *family, const char *keytree)
Delete one or more entries in astdb.
Definition: main/db.c:536
void astman_send_listack(struct mansession *s, const struct message *m, char *msg, char *listflag)
Send ack in manager transaction to begin a list.
Definition: manager.c:3431