Asterisk - The Open Source Telephony Project GIT-master-f45f878
asterisk.c
Go to the documentation of this file.
1/*
2 * Asterisk -- An open source telephony toolkit.
3 *
4 * Copyright (C) 1999 - 2018, 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
20/* Doxygenified Copyright Header */
21/*!
22 * \mainpage Asterisk -- The Open Source Telephony Project
23 *
24 * \par Welcome
25 *
26 * This documentation created by the Doxygen project clearly explains the
27 * internals of the Asterisk software. This documentation contains basic
28 * examples, developer documentation, support information, and information
29 * for upgrading.
30 *
31 * \section community Community
32 * Asterisk is a big project and has a busy community. Look at the
33 * resources for questions and stick around to help answer questions.
34 * \li \ref asterisk_community_resources
35 *
36 * \par Developer Documentation for Asterisk
37 *
38 * This is the main developer documentation for Asterisk. It is
39 * generated by running "make progdocs" from the Asterisk source tree.
40 *
41 * In addition to the information available on the Asterisk source code,
42 * please see the appendices for information on coding guidelines,
43 * release management, commit policies, and more.
44 *
45 * \arg \ref AsteriskArchitecture
46 *
47 * \par Additional documentation
48 * \arg \ref Licensing
49 * \arg \ref DevDoc
50 * \arg \ref configuration_file
51 * \arg \ref channel_drivers
52 * \arg \ref applications
53 *
54 * \section copyright Copyright and Author
55 *
56 * Copyright (C) 1999 - 2021, Sangoma Technologies Corporation.
57 * Asterisk is a <a href="https://cdn.sangoma.com/wp-content/uploads/Sangoma-Trademark-Policy.pdf">registered trademark</a>
58 * of <a rel="nofollow" href="http://www.sangoma.com">Sangoma Technologies Corporation</a>.
59 *
60 * \author Mark Spencer <markster@digium.com>
61 *
62 * See http://www.asterisk.org for more information about
63 * the Asterisk project. Please do not directly contact
64 * any of the maintainers of this project for assistance;
65 * the project provides a web site, mailing lists, and IRC
66 * channels for your use.
67 *
68 */
69
70/*!
71 * \page asterisk_community_resources Asterisk Community Resources
72 * \par Websites
73 * \li https://www.asterisk.org Asterisk Homepage
74 * \li https://docs.asterisk.org Asterisk documentation
75 *
76 * \par Mailing Lists
77 * \par
78 * All lists: http://lists.digium.com/mailman/listinfo
79 * \li aadk-commits SVN commits to the AADK repository
80 * \li asterisk-addons-commits SVN commits to the Asterisk addons project
81 * \li asterisk-announce [no description available]
82 * \li asterisk-biz Commercial and Business-Oriented Asterisk Discussion
83 * \li Asterisk-BSD Asterisk on BSD discussion
84 * \li asterisk-bugs [no description available]
85 * \li asterisk-commits SVN commits to the Asterisk project
86 * \li asterisk-dev Asterisk Developers Mailing List
87 * \li asterisk-doc Discussions regarding The Asterisk Documentation Project
88 * \li asterisk-embedded Asterisk Embedded Development
89 * \li asterisk-gui Asterisk GUI project discussion
90 * \li asterisk-gui-commits SVN commits to the Asterisk-GUI project
91 * \li asterisk-ha-clustering Asterisk High Availability and Clustering List - Non-Commercial Discussion
92 * \li Asterisk-i18n Discussion of Asterisk internationalization
93 * \li asterisk-r2 [no description available]
94 * \li asterisk-scf-commits Commits to the Asterisk SCF project code repositories
95 * \li asterisk-scf-committee Asterisk SCF Steering Committee discussions
96 * \li asterisk-scf-dev Asterisk SCF Developers Mailing List
97 * \li asterisk-scf-wiki-changes Changes to the Asterisk SCF space on wiki.asterisk.org
98 * \li asterisk-security Asterisk Security Discussion
99 * \li asterisk-speech-rec Use of speech recognition in Asterisk
100 * \li asterisk-ss7 [no description available]
101 * \li asterisk-users Asterisk Users Mailing List - Non-Commercial Discussion
102 * \li asterisk-video Development discussion of video media support in Asterisk
103 * \li asterisk-wiki-changes Changes to the Asterisk space on wiki.asterisk.org
104 * \li asterisknow AsteriskNOW Discussion
105 * \li dahdi-commits SVN commits to the DAHDI project
106 * \li digium-announce Digium Product Announcements
107 * \li Dundi Distributed Universal Number Discovery
108 * \li libiax2-commits SVN commits to the libiax2 project
109 * \li libpri-commits SVN commits to the libpri project
110 * \li libss7-commits SVN commits to the libss7 project
111 * \li svn-commits SVN commits to the Digium repositories
112 * \li Test-results Results from automated testing
113 * \li thirdparty-commits SVN commits to the Digium third-party software repository
114 * \li zaptel-commits SVN commits to the Zaptel project
115 *
116 * \par Forums
117 * \li Forums are located at http://forums.asterisk.org/
118 *
119 * \par IRC
120 * \par
121 * Use https://libera.chat IRC server to connect with Asterisk
122 * developers and users in realtime.
123 *
124 * \li \verbatim #asterisk \endverbatim Asterisk Users Room
125 * \li \verbatim #asterisk-dev \endverbatim Asterisk Developers Room
126 *
127 * \par More
128 * \par
129 * If you would like to add a resource to this list please create an issue
130 * on the issue tracker with a patch.
131 */
132
133/*! \file
134 * \brief Top level source file for Asterisk - the Open Source PBX.
135 * Implementation of PBX core functions and CLI interface.
136 */
137
138/*! \li \ref asterisk.c uses the configuration file \ref asterisk.conf
139 * \addtogroup configuration_file
140 */
141
142/*! \page asterisk.conf asterisk.conf
143 * \verbinclude asterisk.conf.sample
144 */
145
146/*** MODULEINFO
147 <support_level>core</support_level>
148 ***/
149
150#include "asterisk.h"
151
152#include "asterisk/_private.h"
153
154#undef sched_setscheduler
155#undef setpriority
156#include <sys/time.h>
157#include <fcntl.h>
158#include <signal.h>
159#include <sched.h>
160#include <sys/un.h>
161#include <sys/wait.h>
162#include <ctype.h>
163#include <sys/resource.h>
164#include <grp.h>
165#include <pwd.h>
166#include <sys/stat.h>
167#if defined(HAVE_SYSINFO)
168#include <sys/sysinfo.h>
169#elif defined(HAVE_SYSCTL)
170#include <sys/param.h>
171#include <sys/sysctl.h>
172#include <sys/vmmeter.h>
173#if defined(__FreeBSD__) || defined(__DragonFly__)
174#include <vm/vm_param.h>
175#endif
176#if defined(HAVE_SWAPCTL)
177#include <sys/swap.h>
178#endif
179#endif
180#include <regex.h>
181#include <histedit.h>
182
183#if defined(SOLARIS)
184int daemon(int, int); /* defined in libresolv of all places */
185#include <sys/loadavg.h>
186#endif
187
188#ifdef linux
189#include <sys/prctl.h>
190#ifdef HAVE_CAP
191#include <sys/capability.h>
192#endif /* HAVE_CAP */
193#endif /* linux */
194
195/* we define here the variables so to better agree on the prototype */
196#include "asterisk/paths.h"
197#include "asterisk/network.h"
198#include "asterisk/cli.h"
199#include "asterisk/channel.h"
200#include "asterisk/translate.h"
201#include "asterisk/pickup.h"
202#include "asterisk/acl.h"
203#include "asterisk/ulaw.h"
204#include "asterisk/alaw.h"
205#include "asterisk/callerid.h"
206#include "asterisk/image.h"
207#include "asterisk/tdd.h"
208#include "asterisk/term.h"
209#include "asterisk/manager.h"
210#include "asterisk/cdr.h"
211#include "asterisk/pbx.h"
212#include "asterisk/app.h"
213#include "asterisk/mwi.h"
214#include "asterisk/lock.h"
215#include "asterisk/utils.h"
216#include "asterisk/file.h"
217#include "asterisk/io.h"
218#include "asterisk/config.h"
219#include "asterisk/ast_version.h"
220#include "asterisk/linkedlists.h"
221#include "asterisk/devicestate.h"
223#include "asterisk/module.h"
224#include "asterisk/buildinfo.h"
225#include "asterisk/xmldoc.h"
226#include "asterisk/poll-compat.h"
227#include "asterisk/test.h"
228#include "asterisk/rtp_engine.h"
229#include "asterisk/format.h"
230#include "asterisk/aoc.h"
231#include "asterisk/uuid.h"
232#include "asterisk/sorcery.h"
233#include "asterisk/bucket.h"
234#include "asterisk/stasis.h"
235#include "asterisk/json.h"
239#include "asterisk/endpoints.h"
240#include "asterisk/codec.h"
242#include "asterisk/media_cache.h"
243#include "asterisk/astdb.h"
244#include "asterisk/options.h"
245#include "asterisk/utf8.h"
246
247#include "../defaults.h"
248
249/*** DOCUMENTATION
250 <managerEvent language="en_US" name="FullyBooted">
251 <managerEventInstance class="EVENT_FLAG_SYSTEM">
252 <synopsis>Raised when all Asterisk initialization procedures have finished.</synopsis>
253 <syntax>
254 <parameter name="Status">
255 <para>Informational message</para>
256 </parameter>
257 <parameter name="Uptime">
258 <para>Seconds since start</para>
259 </parameter>
260 <parameter name="LastReload">
261 <para>Seconds since last reload</para>
262 </parameter>
263 </syntax>
264 </managerEventInstance>
265 </managerEvent>
266 <managerEvent language="en_US" name="Shutdown">
267 <managerEventInstance class="EVENT_FLAG_SYSTEM">
268 <synopsis>Raised when Asterisk is shutdown or restarted.</synopsis>
269 <syntax>
270 <parameter name="Shutdown">
271 <para>Whether the shutdown is proceeding cleanly (all channels
272 were hungup successfully) or uncleanly (channels will be
273 terminated)</para>
274 <enumlist>
275 <enum name="Uncleanly"/>
276 <enum name="Cleanly"/>
277 </enumlist>
278 </parameter>
279 <parameter name="Restart">
280 <para>Whether or not a restart will occur.</para>
281 <enumlist>
282 <enum name="True"/>
283 <enum name="False"/>
284 </enumlist>
285 </parameter>
286 </syntax>
287 </managerEventInstance>
288 </managerEvent>
289 ***/
290
291#ifndef AF_LOCAL
292#define AF_LOCAL AF_UNIX
293#define PF_LOCAL PF_UNIX
294#endif
295
296#define AST_MAX_CONNECTS 128
297#define NUM_MSGS 64
298
299/*! Displayed copyright tag */
300#define COPYRIGHT_TAG "Copyright (C) 1999 - 2022, Sangoma Technologies Corporation and others."
301
302/*! \brief Welcome message when starting a CLI interface */
303#define WELCOME_MESSAGE \
304 ast_verbose("Asterisk %s, " COPYRIGHT_TAG "\n" \
305 "Created by Mark Spencer <markster@digium.com>\n" \
306 "Asterisk comes with ABSOLUTELY NO WARRANTY; type 'core show warranty' for details.\n" \
307 "This is free software, with components licensed under the GNU General Public\n" \
308 "License version 2 and other licenses; you are welcome to redistribute it under\n" \
309 "certain conditions. Type 'core show license' for details.\n" \
310 "=========================================================================\n", ast_get_version()) \
311
312static int ast_socket = -1; /*!< UNIX Socket for allowing remote control */
313static int ast_socket_is_sd = 0; /*!< Is socket activation responsible for ast_socket? */
314static int ast_consock = -1; /*!< UNIX Socket for controlling another asterisk */
316struct console {
317 int fd; /*!< File descriptor */
318 int p[2]; /*!< Pipe */
319 pthread_t t; /*!< Thread of handler */
320 int mute; /*!< Is the console muted for logs */
321 int uid; /*!< Remote user ID. */
322 int gid; /*!< Remote group ID. */
323 int levels[NUMLOGLEVELS]; /*!< Which log levels are enabled for the console */
324 /*! Verbosity level of this console. */
326};
327
329 void (*func)(void);
332};
333
335
336struct timeval ast_startuptime;
337struct timeval ast_lastreloadtime;
338
339static History *el_hist;
340static EditLine *el;
341static char *remotehostname;
342
344
345static int ast_el_add_history(const char *);
346static int ast_el_read_history(const char *);
347static int ast_el_write_history(const char *);
348
349static void ast_el_read_default_histfile(void);
350static void ast_el_write_default_histfile(void);
351
352static void asterisk_daemon(int isroot, const char *runuser, const char *rungroup);
353
354static char *_argv[256];
355
356typedef enum {
357 /*! Normal operation */
359 /*! Committed to shutting down. Final phase */
361 /*! Committed to shutting down. Initial phase */
363 /*!
364 * Valid values for quit_handler() niceness below.
365 * These shutdown/restart levels can be cancelled.
366 *
367 * Remote console exit right now
368 */
370 /*! core stop/restart now */
372 /*! core stop/restart gracefully */
374 /*! core stop/restart when convenient */
377
379
380/*! Prevent new channel allocation for shutdown. */
382
383static int restartnow;
385static pthread_t mon_sig_flags;
386static int canary_pid = 0;
387static char canary_filename[128];
389
390static char randompool[256];
391
392#ifdef HAVE_CAP
393static cap_t child_cap;
394#endif
395
396static int sig_alert_pipe[2] = { -1, -1 };
397static struct {
398 unsigned int need_reload:1;
399 unsigned int need_quit:1;
400 unsigned int need_quit_handler:1;
401 unsigned int need_el_end:1;
403
404#if !defined(LOW_MEMORY)
407 char *name;
408 pthread_t id;
409 int lwp;
410};
411
413
415{
416 struct thread_list_t *new = ast_calloc(1, sizeof(*new));
417
418 if (!new)
419 return;
420
422 new->id = pthread_self();
423 new->lwp = ast_get_tid();
424 new->name = name; /* steal the allocated memory for the thread name */
428}
429
431{
432 struct thread_list_t *x;
433
436 if ((void *) x->id == id) {
438 break;
439 }
440 }
443 if (x) {
444 ast_free(x->name);
445 ast_free(x);
446 }
447}
448
449/*! \brief Print the contents of a file */
450static int print_file(int fd, char *desc, const char *filename)
451{
452 FILE *f;
453 char c;
454 if (!(f = fopen(filename, "r"))) {
455 return -1;
456 }
457 ast_cli(fd, "%s", desc);
458 while ((c = fgetc(f)) != EOF) {
459 ast_cli(fd, "%c", c);
460 }
461 fclose(f);
462 /* no need for trailing new line, the file already has one */
463 return 0;
464}
465
466/*! \brief Give an overview of core settings */
467static char *handle_show_settings(struct ast_cli_entry *e, int cmd, struct ast_cli_args *a)
468{
469 char buf[BUFSIZ];
470 struct ast_tm tm;
471 char eid_str[128];
472 struct rlimit limits;
473 char pbx_uuid[AST_UUID_STR_LEN];
474#if defined(HAVE_EACCESS) || defined(HAVE_EUIDACCESS)
475 char dir[PATH_MAX];
476#endif
477
478 switch (cmd) {
479 case CLI_INIT:
480 e->command = "core show settings";
481 e->usage = "Usage: core show settings\n"
482 " Show core misc settings";
483 return NULL;
484 case CLI_GENERATE:
485 return NULL;
486 }
487
488 ast_eid_to_str(eid_str, sizeof(eid_str), &ast_eid_default);
489 ast_pbx_uuid_get(pbx_uuid, sizeof(pbx_uuid));
490
491 ast_cli(a->fd, "\nPBX Core settings\n");
492 ast_cli(a->fd, "-----------------\n");
493 ast_cli(a->fd, " Version: %s\n", ast_get_version());
494 ast_cli(a->fd, " ABI related Build Options: %s\n", S_OR(ast_get_build_opts(), "(none)"));
495 ast_cli(a->fd, " All Build Options: %s\n", S_OR(ast_get_build_opts_all(), "(none)"));
497 ast_cli(a->fd, " Maximum calls: %d (Current %d)\n", ast_option_maxcalls, ast_active_channels());
498 else
499 ast_cli(a->fd, " Maximum calls: Not set\n");
500
501 if (getrlimit(RLIMIT_NOFILE, &limits)) {
502 ast_cli(a->fd, " Maximum open file handles: Error because of %s\n", strerror(errno));
503 } else if (limits.rlim_cur == RLIM_INFINITY) {
504 ast_cli(a->fd, " Maximum open file handles: Unlimited\n");
505 } else if (limits.rlim_cur < ast_option_maxfiles) {
506 ast_cli(a->fd, " Maximum open file handles: %d (is) %d (requested)\n", (int) limits.rlim_cur, ast_option_maxfiles);
507 } else {
508 ast_cli(a->fd, " Maximum open file handles: %d\n", (int) limits.rlim_cur);
509 }
510
511 ast_cli(a->fd, " Root console verbosity: %d\n", option_verbose);
512 ast_cli(a->fd, " Current console verbosity: %d\n", ast_verb_console_get());
513 ast_cli(a->fd, " Debug level: %d\n", option_debug);
514 ast_cli(a->fd, " Trace level: %d\n", option_trace);
515 ast_cli(a->fd, " Dump core on crash: %s\n", ast_opt_dump_core ? "Yes" : "No");
516 print_file(a->fd, " Core dump file: ", "/proc/sys/kernel/core_pattern");
517 ast_cli(a->fd, " Maximum load average: %lf\n", ast_option_maxload);
518#if defined(HAVE_SYSINFO)
519 ast_cli(a->fd, " Minimum free memory: %ld MB\n", option_minmemfree);
520#endif
521 if (ast_localtime(&ast_startuptime, &tm, NULL)) {
522 ast_strftime(buf, sizeof(buf), "%H:%M:%S", &tm);
523 ast_cli(a->fd, " Startup time: %s\n", buf);
524 }
526 ast_strftime(buf, sizeof(buf), "%H:%M:%S", &tm);
527 ast_cli(a->fd, " Last reload time: %s\n", buf);
528 }
529 ast_cli(a->fd, " System: %s/%s built by %s on %s %s\n", ast_build_os, ast_build_kernel, ast_build_user, ast_build_machine, ast_build_date);
530 ast_cli(a->fd, " System name: %s\n", ast_config_AST_SYSTEM_NAME);
531 ast_cli(a->fd, " Entity ID: %s\n", eid_str);
532 ast_cli(a->fd, " PBX UUID: %s\n", pbx_uuid);
533 ast_cli(a->fd, " Default language: %s\n", ast_defaultlanguage);
534 ast_cli(a->fd, " Language prefix: %s\n", ast_language_is_prefix ? "Enabled" : "Disabled");
535 ast_cli(a->fd, " User name and group: %s/%s\n", ast_config_AST_RUN_USER, ast_config_AST_RUN_GROUP);
536#if defined(HAVE_EACCESS) || defined(HAVE_EUIDACCESS)
537#if defined(HAVE_EUIDACCESS) && !defined(HAVE_EACCESS)
538#define eaccess euidaccess
539#endif
540 if (!getcwd(dir, sizeof(dir))) {
541 if (eaccess(dir, R_OK | X_OK | F_OK)) {
542 ast_cli(a->fd, " Running directory: %s\n", "Unable to access");
543 } else {
544 ast_cli(a->fd, " Running directory: %s (%s)\n", dir, "Unable to access");
545 }
546 } else {
547 ast_cli(a->fd, " Running directory: %s\n", dir);
548 }
549#endif /* defined(HAVE_EACCESS) || defined(HAVE_EUIDACCESS) */
550 ast_cli(a->fd, " Executable includes: %s\n", ast_test_flag(&ast_options, AST_OPT_FLAG_EXEC_INCLUDES) ? "Enabled" : "Disabled");
551 ast_cli(a->fd, " Transcode via SLIN: %s\n", ast_test_flag(&ast_options, AST_OPT_FLAG_TRANSCODE_VIA_SLIN) ? "Enabled" : "Disabled");
552 ast_cli(a->fd, " Transmit silence during rec: %s\n", ast_test_flag(&ast_options, AST_OPT_FLAG_TRANSMIT_SILENCE) ? "Enabled" : "Disabled");
553 ast_cli(a->fd, " Generic PLC: %s\n", ast_test_flag(&ast_options, AST_OPT_FLAG_GENERIC_PLC) ? "Enabled" : "Disabled");
554 ast_cli(a->fd, " Generic PLC on equal codecs: %s\n", ast_test_flag(&ast_options, AST_OPT_FLAG_GENERIC_PLC_ON_EQUAL_CODECS) ? "Enabled" : "Disabled");
555 ast_cli(a->fd, " Hide Msg Chan AMI events: %s\n", ast_opt_hide_messaging_ami_events ? "Enabled" : "Disabled");
556 ast_cli(a->fd, " Sounds search custom dir: %s\n", ast_opt_sounds_search_custom ? "Enabled" : "Disabled");
557 ast_cli(a->fd, " Min DTMF duration:: %u\n", option_dtmfminduration);
558#if !defined(LOW_MEMORY)
559 ast_cli(a->fd, " Cache media frames: %s\n", ast_opt_cache_media_frames ? "Enabled" : "Disabled");
560#endif
561 ast_cli(a->fd, " RTP use dynamic payloads: %u\n", ast_option_rtpusedynamic);
562
564 ast_cli(a->fd, " RTP dynamic payload types: %u,%u-%u\n",
568 ast_cli(a->fd, " RTP dynamic payload types: %u-%u,%u-%u\n",
571 } else {
572 ast_cli(a->fd, " RTP dynamic payload types: %u-%u\n",
574 }
575
576 ast_cli(a->fd, "\n* Subsystems\n");
577 ast_cli(a->fd, " -------------\n");
578 ast_cli(a->fd, " Manager (AMI): %s\n", ast_manager_check_enabled() ? "Enabled" : "Disabled");
579 ast_cli(a->fd, " Web Manager (AMI/HTTP): %s\n", ast_webmanager_check_enabled() ? "Enabled" : "Disabled");
580 ast_cli(a->fd, " Call data records: %s\n", ast_cdr_is_enabled() ? "Enabled" : "Disabled");
581 ast_cli(a->fd, " Realtime Architecture (ARA): %s\n", ast_realtime_enabled() ? "Enabled" : "Disabled");
582
583 /*! \todo we could check musiconhold, voicemail, smdi, adsi, queues */
584
585 ast_cli(a->fd, "\n* Directories\n");
586 ast_cli(a->fd, " -------------\n");
587 ast_cli(a->fd, " Configuration file: %s\n", ast_config_AST_CONFIG_FILE);
588 ast_cli(a->fd, " Configuration directory: %s\n", ast_config_AST_CONFIG_DIR);
589 ast_cli(a->fd, " Module directory: %s\n", ast_config_AST_MODULE_DIR);
590 ast_cli(a->fd, " Spool directory: %s\n", ast_config_AST_SPOOL_DIR);
591 ast_cli(a->fd, " Log directory: %s\n", ast_config_AST_LOG_DIR);
592 ast_cli(a->fd, " Run/Sockets directory: %s\n", ast_config_AST_RUN_DIR);
593 ast_cli(a->fd, " PID file: %s\n", ast_config_AST_PID);
594 ast_cli(a->fd, " VarLib directory: %s\n", ast_config_AST_VAR_DIR);
595 ast_cli(a->fd, " Data directory: %s\n", ast_config_AST_DATA_DIR);
596 ast_cli(a->fd, " ASTDB: %s\n", ast_config_AST_DB);
597 ast_cli(a->fd, " IAX2 Keys directory: %s\n", ast_config_AST_KEY_DIR);
598 ast_cli(a->fd, " AGI Scripts directory: %s\n", ast_config_AST_AGI_DIR);
599 ast_cli(a->fd, " Cache directory: %s\n", ast_config_AST_CACHE_DIR);
600 ast_cli(a->fd, "\n\n");
601 return CLI_SUCCESS;
602}
603
604static char *handle_show_threads(struct ast_cli_entry *e, int cmd, struct ast_cli_args *a)
605{
606 int count = 0;
607 struct thread_list_t *cur;
608 switch (cmd) {
609 case CLI_INIT:
610 e->command = "core show threads";
611 e->usage =
612 "Usage: core show threads\n"
613 " List threads currently active in the system.\n";
614 return NULL;
615 case CLI_GENERATE:
616 return NULL;
617 }
618
620 AST_RWLIST_TRAVERSE(&thread_list, cur, list) {
621 ast_cli(a->fd, "%p %d %s\n", (void *)cur->id, cur->lwp, cur->name);
622 count++;
623 }
625 ast_cli(a->fd, "%d threads listed.\n", count);
626 return CLI_SUCCESS;
627}
628
629#if defined (HAVE_SYSCTL) && defined(HAVE_SWAPCTL)
630/*
631 * swapmode is rewritten by Tobias Weingartner <weingart@openbsd.org>
632 * to be based on the new swapctl(2) system call.
633 */
634static int swapmode(int *used, int *total)
635{
636 struct swapent *swdev;
637 int nswap, rnswap, i;
638
639 nswap = swapctl(SWAP_NSWAP, 0, 0);
640 if (nswap == 0)
641 return 0;
642
643 swdev = ast_calloc(nswap, sizeof(*swdev));
644 if (swdev == NULL)
645 return 0;
646
647 rnswap = swapctl(SWAP_STATS, swdev, nswap);
648 if (rnswap == -1) {
649 ast_free(swdev);
650 return 0;
651 }
652
653 /* if rnswap != nswap, then what? */
654
655 /* Total things up */
656 *total = *used = 0;
657 for (i = 0; i < nswap; i++) {
658 if (swdev[i].se_flags & SWF_ENABLE) {
659 *used += (swdev[i].se_inuse / (1024 / DEV_BSIZE));
660 *total += (swdev[i].se_nblks / (1024 / DEV_BSIZE));
661 }
662 }
663 ast_free(swdev);
664 return 1;
665}
666#endif
667
668#if defined(HAVE_SYSINFO) || defined(HAVE_SYSCTL)
669/*! \brief Give an overview of system statistics */
670static char *handle_show_sysinfo(struct ast_cli_entry *e, int cmd, struct ast_cli_args *a)
671{
672 uint64_t physmem, freeram;
673#if defined(HAVE_SYSINFO) || defined(HAVE_SWAPCTL)
674 int totalswap = 0;
675 uint64_t freeswap = 0;
676#endif
677 int nprocs = 0;
678 long uptime = 0;
679#if defined(HAVE_SYSINFO)
680 struct sysinfo sys_info;
681#elif defined(HAVE_SYSCTL)
682 static int pageshift;
683 struct vmtotal vmtotal;
684 struct timeval boottime;
685 time_t now;
686 int mib[2], pagesize;
687#if defined(HAVE_SWAPCTL)
688 int usedswap = 0;
689#endif
690 size_t len;
691#endif
692
693 switch (cmd) {
694 case CLI_INIT:
695 e->command = "core show sysinfo";
696 e->usage =
697 "Usage: core show sysinfo\n"
698 " List current system information.\n";
699 return NULL;
700 case CLI_GENERATE:
701 return NULL;
702 }
703
704#if defined(HAVE_SYSINFO)
705 sysinfo(&sys_info);
706 uptime = sys_info.uptime / 3600;
707 physmem = sys_info.totalram * sys_info.mem_unit;
708 freeram = (sys_info.freeram * sys_info.mem_unit) / 1024;
709 totalswap = (sys_info.totalswap * sys_info.mem_unit) / 1024;
710 freeswap = (sys_info.freeswap * sys_info.mem_unit) / 1024;
711 nprocs = sys_info.procs;
712#elif defined(HAVE_SYSCTL)
713 /* calculate the uptime by looking at boottime */
714 time(&now);
715 mib[0] = CTL_KERN;
716 mib[1] = KERN_BOOTTIME;
717 len = sizeof(boottime);
718 if (sysctl(mib, 2, &boottime, &len, NULL, 0) != -1) {
719 uptime = now - boottime.tv_sec;
720 }
721 uptime = uptime/3600;
722 /* grab total physical memory */
723 mib[0] = CTL_HW;
724#if defined(HW_PHYSMEM64)
725 mib[1] = HW_PHYSMEM64;
726#else
727 mib[1] = HW_PHYSMEM;
728#endif
729 len = sizeof(physmem);
730 sysctl(mib, 2, &physmem, &len, NULL, 0);
731
732 pagesize = getpagesize();
733 pageshift = 0;
734 while (pagesize > 1) {
735 pageshift++;
736 pagesize >>= 1;
737 }
738
739 /* we only need the amount of log(2)1024 for our conversion */
740 pageshift -= 10;
741
742 /* grab vm totals */
743 mib[0] = CTL_VM;
744 mib[1] = VM_METER;
745 len = sizeof(vmtotal);
746 sysctl(mib, 2, &vmtotal, &len, NULL, 0);
747 freeram = (vmtotal.t_free << pageshift);
748 /* generate swap usage and totals */
749#if defined(HAVE_SWAPCTL)
750 swapmode(&usedswap, &totalswap);
751 freeswap = (totalswap - usedswap);
752#endif
753 /* grab number of processes */
754#if defined(__OpenBSD__)
755 mib[0] = CTL_KERN;
756 mib[1] = KERN_NPROCS;
757 len = sizeof(nprocs);
758 sysctl(mib, 2, &nprocs, &len, NULL, 0);
759#endif
760#endif
761
762 ast_cli(a->fd, "\nSystem Statistics\n");
763 ast_cli(a->fd, "-----------------\n");
764 ast_cli(a->fd, " System Uptime: %ld hours\n", uptime);
765 ast_cli(a->fd, " Total RAM: %" PRIu64 " KiB\n", physmem / 1024);
766 ast_cli(a->fd, " Free RAM: %" PRIu64 " KiB\n", freeram);
767#if defined(HAVE_SYSINFO)
768 ast_cli(a->fd, " Buffer RAM: %" PRIu64 " KiB\n", ((uint64_t) sys_info.bufferram * sys_info.mem_unit) / 1024);
769#endif
770#if defined(HAVE_SYSINFO) || defined(HAVE_SWAPCTL)
771 ast_cli(a->fd, " Total Swap Space: %d KiB\n", totalswap);
772 ast_cli(a->fd, " Free Swap Space: %" PRIu64 " KiB\n\n", freeswap);
773#endif
774 ast_cli(a->fd, " Number of Processes: %d \n\n", nprocs);
775 return CLI_SUCCESS;
776}
777#endif
778
780 const char *name;
781 uint64_t scale; /* if non-zero, values are scaled by this */
782 int64_t mark;
783 int64_t value;
784 int64_t events;
785};
786
790 struct profile_entry e[0];
791};
792
793static struct profile_data *prof_data;
794#endif /* ! LOW_MEMORY */
795
796/*! \brief allocates a counter with a given name and scale.
797 * \return Returns the identifier of the counter.
798 */
799int ast_add_profile(const char *name, uint64_t scale)
800{
801#if !defined(LOW_MEMORY)
802 int l = sizeof(struct profile_data);
803 int n = 10; /* default entries */
804
805 if (prof_data == NULL) {
806 prof_data = ast_calloc(1, l + n*sizeof(struct profile_entry));
807 if (prof_data == NULL)
808 return -1;
809 prof_data->entries = 0;
810 prof_data->max_size = n;
811 }
813 void *p;
814 n = prof_data->max_size + 20;
815 p = ast_realloc(prof_data, l + n*sizeof(struct profile_entry));
816 if (p == NULL)
817 return -1;
818 prof_data = p;
819 prof_data->max_size = n;
820 }
821 n = prof_data->entries++;
823 prof_data->e[n].value = 0;
824 prof_data->e[n].events = 0;
825 prof_data->e[n].mark = 0;
826 prof_data->e[n].scale = scale;
827 return n;
828#else /* if defined(LOW_MEMORY) */
829 return 0;
830#endif
831}
832
833int64_t ast_profile(int i, int64_t delta)
834{
835#if !defined(LOW_MEMORY)
836 if (!prof_data || i < 0 || i > prof_data->entries) /* invalid index */
837 return 0;
838 if (prof_data->e[i].scale > 1)
839 delta /= prof_data->e[i].scale;
840 prof_data->e[i].value += delta;
841 prof_data->e[i].events++;
842 return prof_data->e[i].value;
843#else /* if defined(LOW_MEMORY) */
844 return 0;
845#endif
846}
847
848#if !defined(LOW_MEMORY)
849/* The RDTSC instruction was introduced on the Pentium processor and is not
850 * implemented on certain clones, like the Cyrix 586. Hence, the previous
851 * expectation of __i386__ was in error. */
852#if defined ( __i686__) && (defined(__FreeBSD__) || defined(__NetBSD__) || defined(linux))
853#if defined(__FreeBSD__)
854#include <machine/cpufunc.h>
855#elif defined(__NetBSD__) || defined(linux)
856static __inline uint64_t
857rdtsc(void)
858{
859 uint64_t rv;
860
861 __asm __volatile(".byte 0x0f, 0x31" : "=A" (rv));
862 return (rv);
863}
864#endif
865#else /* supply a dummy function on other platforms */
866static __inline uint64_t
867rdtsc(void)
868{
869 return 0;
870}
871#endif
872#endif /* ! LOW_MEMORY */
873
874int64_t ast_mark(int i, int startstop)
875{
876#if !defined(LOW_MEMORY)
877 if (!prof_data || i < 0 || i > prof_data->entries) /* invalid index */
878 return 0;
879 if (startstop == 1)
880 prof_data->e[i].mark = rdtsc();
881 else {
882 prof_data->e[i].mark = (rdtsc() - prof_data->e[i].mark);
883 if (prof_data->e[i].scale > 1)
884 prof_data->e[i].mark /= prof_data->e[i].scale;
885 prof_data->e[i].value += prof_data->e[i].mark;
886 prof_data->e[i].events++;
887 }
888 return prof_data->e[i].mark;
889#else /* if defined(LOW_MEMORY) */
890 return 0;
891#endif
892}
893
894#if !defined(LOW_MEMORY)
895#define DEFINE_PROFILE_MIN_MAX_VALUES min = 0; \
896 max = prof_data->entries;\
897 if (a->argc > 3) { /* specific entries */ \
898 if (isdigit(a->argv[3][0])) { \
899 min = atoi(a->argv[3]); \
900 if (a->argc == 5 && strcmp(a->argv[4], "-")) \
901 max = atoi(a->argv[4]); \
902 } else \
903 search = a->argv[3]; \
904 } \
905 if (max > prof_data->entries) \
906 max = prof_data->entries;
907
908static char *handle_show_profile(struct ast_cli_entry *e, int cmd, struct ast_cli_args *a)
909{
910 int i, min, max;
911 const char *search = NULL;
912 switch (cmd) {
913 case CLI_INIT:
914 e->command = "core show profile";
915 e->usage = "Usage: core show profile\n"
916 " show profile information";
917 return NULL;
918 case CLI_GENERATE:
919 return NULL;
920 }
921
922 if (prof_data == NULL)
923 return 0;
924
926 ast_cli(a->fd, "profile values (%d, allocated %d)\n-------------------\n",
928 ast_cli(a->fd, "%6s %8s %10s %12s %12s %s\n", "ID", "Scale", "Events",
929 "Value", "Average", "Name");
930 for (i = min; i < max; i++) {
931 struct profile_entry *entry = &prof_data->e[i];
932 if (!search || strstr(entry->name, search))
933 ast_cli(a->fd, "%6d: [%8ld] %10ld %12lld %12lld %s\n",
934 i,
935 (long)entry->scale,
936 (long)entry->events, (long long)entry->value,
937 (long long)(entry->events ? entry->value / entry->events : entry->value),
938 entry->name);
939 }
940 return CLI_SUCCESS;
941}
942
943static char *handle_clear_profile(struct ast_cli_entry *e, int cmd, struct ast_cli_args *a)
944{
945 int i, min, max;
946 const char *search = NULL;
947 switch (cmd) {
948 case CLI_INIT:
949 e->command = "core clear profile";
950 e->usage = "Usage: core clear profile\n"
951 " clear profile information";
952 return NULL;
953 case CLI_GENERATE:
954 return NULL;
955 }
956
957 if (prof_data == NULL)
958 return 0;
959
961 for (i= min; i < max; i++) {
962 if (!search || strstr(prof_data->e[i].name, search)) {
963 prof_data->e[i].value = 0;
964 prof_data->e[i].events = 0;
965 }
966 }
967 return CLI_SUCCESS;
968}
969#undef DEFINE_PROFILE_MIN_MAX_VALUES
970
971#endif /* ! LOW_MEMORY */
972
973int ast_pbx_uuid_get(char *pbx_uuid, int length)
974{
975 return ast_db_get("pbx", "UUID", pbx_uuid, length);
976}
977
978static void publish_fully_booted(void)
979{
980 struct ast_json *json_object;
981 int uptime = 0;
982 int lastreloaded = 0;
983 struct timeval tmp;
984 struct timeval curtime = ast_tvnow();
985
986 if (ast_startuptime.tv_sec) {
987 tmp = ast_tvsub(curtime, ast_startuptime);
988 uptime = (int) tmp.tv_sec;
989 }
990
991 if (ast_lastreloadtime.tv_sec) {
992 tmp = ast_tvsub(curtime, ast_lastreloadtime);
993 lastreloaded = (int) tmp.tv_sec;
994 }
995
996 json_object = ast_json_pack("{s: s, s: i, s: i}",
997 "Status", "Fully Booted",
998 "Uptime", uptime,
999 "LastReload", lastreloaded);
1000 ast_manager_publish_event("FullyBooted", EVENT_FLAG_SYSTEM, json_object);
1001 ast_json_unref(json_object);
1002}
1003
1004static void ast_run_atexits(int run_cleanups)
1005{
1006 struct ast_atexit *ae;
1007
1009 while ((ae = AST_LIST_REMOVE_HEAD(&atexits, list))) {
1010 if (ae->func && (!ae->is_cleanup || run_cleanups)) {
1011 ae->func();
1012 }
1013 ast_free(ae);
1014 }
1016}
1017
1018static void __ast_unregister_atexit(void (*func)(void))
1019{
1020 struct ast_atexit *ae;
1021
1023 if (ae->func == func) {
1025 ast_free(ae);
1026 break;
1027 }
1028 }
1030}
1031
1032static int register_atexit(void (*func)(void), int is_cleanup)
1033{
1034 struct ast_atexit *ae;
1035
1036 ae = ast_calloc(1, sizeof(*ae));
1037 if (!ae) {
1038 return -1;
1039 }
1040 ae->func = func;
1041 ae->is_cleanup = is_cleanup;
1042
1047
1048 return 0;
1049}
1050
1051int ast_register_atexit(void (*func)(void))
1052{
1053 return register_atexit(func, 0);
1054}
1055
1056int ast_register_cleanup(void (*func)(void))
1057{
1058 return register_atexit(func, 1);
1059}
1060
1061void ast_unregister_atexit(void (*func)(void))
1062{
1066}
1067
1068/* Sending commands from consoles back to the daemon requires a terminating NULL */
1069static int fdsend(int fd, const char *s)
1070{
1071 return write(fd, s, strlen(s) + 1);
1072}
1073
1074/* Sending messages from the daemon back to the display requires _excluding_ the terminating NULL */
1075static int fdprint(int fd, const char *s)
1076{
1077 return write(fd, s, strlen(s));
1078}
1079
1080/*! \brief NULL handler so we can collect the child exit status */
1081static void _null_sig_handler(int sig)
1082{
1083}
1084
1085static struct sigaction null_sig_handler = {
1086 .sa_handler = _null_sig_handler,
1087 .sa_flags = SA_RESTART,
1088};
1089
1090static struct sigaction ignore_sig_handler = {
1091 .sa_handler = SIG_IGN,
1092};
1093
1095/*! \brief Keep track of how many threads are currently trying to wait*() on
1096 * a child process
1097 */
1098static unsigned int safe_system_level = 0;
1099static struct sigaction safe_system_prev_handler;
1100
1102{
1103 unsigned int level;
1104
1106 level = safe_system_level++;
1107
1108 /* only replace the handler if it has not already been done */
1109 if (level == 0) {
1110 sigaction(SIGCHLD, &null_sig_handler, &safe_system_prev_handler);
1111 }
1112
1114}
1115
1117{
1118 unsigned int level;
1119
1121 level = --safe_system_level;
1122
1123 /* only restore the handler if we are the last one */
1124 if (level == 0) {
1125 sigaction(SIGCHLD, &safe_system_prev_handler, NULL);
1126 }
1127
1129}
1130
1131/*! \brief fork and perform other preparations for spawning applications */
1132static pid_t safe_exec_prep(int dualfork)
1133{
1134 pid_t pid;
1135
1136#if defined(HAVE_WORKING_FORK) || defined(HAVE_WORKING_VFORK)
1138
1139#ifdef HAVE_WORKING_FORK
1140 pid = fork();
1141#else
1142 pid = vfork();
1143#endif
1144
1145 if (pid == 0) {
1146#ifdef HAVE_CAP
1147 cap_set_proc(child_cap);
1148#endif
1149#ifdef HAVE_WORKING_FORK
1152 }
1153 /* Close file descriptors and launch system command */
1154 ast_close_fds_above_n(STDERR_FILENO);
1155#endif
1156 if (dualfork) {
1157#ifdef HAVE_WORKING_FORK
1158 pid = fork();
1159#else
1160 pid = vfork();
1161#endif
1162 if (pid < 0) {
1163 /* Second fork failed. */
1164 /* No logger available. */
1165 _exit(1);
1166 }
1167
1168 if (pid > 0) {
1169 /* This is the first fork, exit so the reaper finishes right away. */
1170 _exit(0);
1171 }
1172
1173 /* This is the second fork. The first fork will exit immediately so
1174 * Asterisk doesn't have to wait for completion.
1175 * ast_safe_system("cmd &") would run in the background, but the '&'
1176 * cannot be added with ast_safe_execvp, so we have to double fork.
1177 */
1178 }
1179 }
1180
1181 if (pid < 0) {
1182 ast_log(LOG_WARNING, "Fork failed: %s\n", strerror(errno));
1183 }
1184#else
1185 ast_log(LOG_WARNING, "Fork failed: %s\n", strerror(ENOTSUP));
1186 pid = -1;
1187#endif
1188
1189 return pid;
1190}
1191
1192/*! \brief wait for spawned application to complete and unreplace sigchld */
1193static int safe_exec_wait(pid_t pid)
1194{
1195 int res = -1;
1196
1197#if defined(HAVE_WORKING_FORK) || defined(HAVE_WORKING_VFORK)
1198 if (pid > 0) {
1199 for (;;) {
1200 int status;
1201
1202 res = waitpid(pid, &status, 0);
1203 if (res > -1) {
1204 res = WIFEXITED(status) ? WEXITSTATUS(status) : -1;
1205 break;
1206 }
1207 if (errno != EINTR) {
1208 break;
1209 }
1210 }
1211 }
1212
1214#endif
1215
1216 return res;
1217}
1218
1219int ast_safe_execvp(int dualfork, const char *file, char *const argv[])
1220{
1221 pid_t pid = safe_exec_prep(dualfork);
1222
1223 if (pid == 0) {
1224 execvp(file, argv);
1225 _exit(1);
1226 /* noreturn from _exit */
1227 }
1228
1229 return safe_exec_wait(pid);
1230}
1231
1232int ast_safe_system(const char *s)
1233{
1234 pid_t pid = safe_exec_prep(0);
1235
1236 if (pid == 0) {
1237 execl("/bin/sh", "/bin/sh", "-c", s, (char *) NULL);
1238 _exit(1);
1239 /* noreturn from _exit */
1240 }
1241
1242 return safe_exec_wait(pid);
1243}
1244
1245/*!
1246 * \brief enable or disable a logging level to a specified console
1247 */
1248void ast_console_toggle_loglevel(int fd, int level, int state)
1249{
1250 int x;
1251
1252 if (level >= NUMLOGLEVELS) {
1253 level = NUMLOGLEVELS - 1;
1254 }
1255
1256 for (x = 0;x < AST_MAX_CONNECTS; x++) {
1257 if (fd == consoles[x].fd) {
1258 /*
1259 * Since the logging occurs when levels are false, set to
1260 * flipped iinput because this function accepts 0 as off and 1 as on
1261 */
1262 consoles[x].levels[level] = state ? 0 : 1;
1263 return;
1264 }
1265 }
1266}
1267
1268/*!
1269 * \brief mute or unmute a console from logging
1270 */
1271void ast_console_toggle_mute(int fd, int silent)
1272{
1273 int x;
1274 for (x = 0;x < AST_MAX_CONNECTS; x++) {
1275 if (fd == consoles[x].fd) {
1276 if (consoles[x].mute) {
1277 consoles[x].mute = 0;
1278 if (!silent)
1279 ast_cli(fd, "Console is not muted anymore.\n");
1280 } else {
1281 consoles[x].mute = 1;
1282 if (!silent)
1283 ast_cli(fd, "Console is muted.\n");
1284 }
1285 return;
1286 }
1287 }
1288 ast_cli(fd, "Couldn't find remote console.\n");
1289}
1290
1291/*!
1292 * \brief log the string to all attached network console clients
1293 */
1294static void ast_network_puts_mutable(const char *string, int level, int sublevel)
1295{
1296 int x;
1297
1298 for (x = 0; x < AST_MAX_CONNECTS; ++x) {
1299 if (consoles[x].fd < 0
1300 || consoles[x].mute
1301 || consoles[x].levels[level]
1302 || (level == __LOG_VERBOSE && consoles[x].option_verbose < sublevel)) {
1303 continue;
1304 }
1305 fdprint(consoles[x].p[1], string);
1306 }
1307}
1308
1309/*!
1310 * \brief log the string to the root console, and all attached
1311 * network console clients
1312 */
1313void ast_console_puts_mutable(const char *string, int level)
1314{
1315 ast_console_puts_mutable_full(string, level, 0);
1316}
1317
1318static int console_print(const char *s);
1319
1320void ast_console_puts_mutable_full(const char *message, int level, int sublevel)
1321{
1322 /* Send to the root console */
1324
1325 /* Wake up a poll()ing console */
1327 pthread_kill(consolethread, SIGURG);
1328 }
1329
1330 /* Send to any network console clients */
1331 ast_network_puts_mutable(message, level, sublevel);
1332}
1333
1334/*!
1335 * \brief write the string to all attached console clients
1336 */
1337static void ast_network_puts(const char *string)
1338{
1339 int x;
1340
1341 for (x = 0; x < AST_MAX_CONNECTS; ++x) {
1342 if (consoles[x].fd < 0) {
1343 continue;
1344 }
1345 fdprint(consoles[x].p[1], string);
1346 }
1347}
1348
1349/*!
1350 * \brief write the string to the root console, and all attached
1351 * network console clients
1352 */
1353void ast_console_puts(const char *string)
1354{
1355 /* Send to the root console */
1356 fputs(string, stdout);
1357 fflush(stdout);
1358
1359 /* Send to any network console clients */
1360 ast_network_puts(string);
1361}
1362
1363static pthread_t lthread;
1364
1365/*!
1366 * \brief read() function supporting the reception of user credentials.
1367 *
1368 * \param fd Socket file descriptor.
1369 * \param buffer Receive buffer.
1370 * \param size 'buffer' size.
1371 * \param con Console structure to set received credentials
1372 * \retval -1 on error
1373 * \retval the number of bytes received on success.
1374 */
1375static int read_credentials(int fd, char *buffer, size_t size, struct console *con)
1376{
1377#if defined(SO_PEERCRED)
1378#ifdef HAVE_STRUCT_SOCKPEERCRED_UID
1379#define HAVE_STRUCT_UCRED_UID
1380 struct sockpeercred cred;
1381#else
1382 struct ucred cred;
1383#endif
1384 socklen_t len = sizeof(cred);
1385#endif
1386#if defined(HAVE_GETPEEREID)
1387 uid_t uid;
1388 gid_t gid;
1389#else
1390 int uid, gid;
1391#endif
1392 int result;
1393
1394 result = read(fd, buffer, size);
1395 if (result < 0) {
1396 return result;
1397 }
1398
1399#if defined(SO_PEERCRED) && (defined(HAVE_STRUCT_UCRED_UID) || defined(HAVE_STRUCT_UCRED_CR_UID))
1400 if (getsockopt(fd, SOL_SOCKET, SO_PEERCRED, &cred, &len)) {
1401 return result;
1402 }
1403#if defined(HAVE_STRUCT_UCRED_UID)
1404 uid = cred.uid;
1405 gid = cred.gid;
1406#else /* defined(HAVE_STRUCT_UCRED_CR_UID) */
1407 uid = cred.cr_uid;
1408 gid = cred.cr_gid;
1409#endif /* defined(HAVE_STRUCT_UCRED_UID) */
1410
1411#elif defined(HAVE_GETPEEREID)
1412 if (getpeereid(fd, &uid, &gid)) {
1413 return result;
1414 }
1415#else
1416 return result;
1417#endif
1418 con->uid = uid;
1419 con->gid = gid;
1420
1421 return result;
1422}
1423
1424/* This is the thread running the remote console on the main process. */
1425static void *netconsole(void *vconsole)
1426{
1427 struct console *con = vconsole;
1428 char hostname[MAXHOSTNAMELEN] = "";
1429 char inbuf[512];
1430 char outbuf[512];
1431 const char * const end_buf = inbuf + sizeof(inbuf);
1432 char *start_read = inbuf;
1433 int res;
1434 struct pollfd fds[2];
1435
1436 if (gethostname(hostname, sizeof(hostname)-1))
1437 ast_copy_string(hostname, "<Unknown>", sizeof(hostname));
1438 snprintf(outbuf, sizeof(outbuf), "%s/%ld/%s\n", hostname, (long)ast_mainpid, ast_get_version());
1439 fdprint(con->fd, outbuf);
1441 for (;;) {
1442 fds[0].fd = con->fd;
1443 fds[0].events = POLLIN;
1444 fds[0].revents = 0;
1445 fds[1].fd = con->p[0];
1446 fds[1].events = POLLIN;
1447 fds[1].revents = 0;
1448
1449 res = ast_poll(fds, 2, -1);
1450 if (res < 0) {
1451 if (errno != EINTR)
1452 ast_log(LOG_WARNING, "poll returned < 0: %s\n", strerror(errno));
1453 continue;
1454 }
1455 if (fds[0].revents) {
1456 int cmds_read, bytes_read;
1457 if ((bytes_read = read_credentials(con->fd, start_read, end_buf - start_read, con)) < 1) {
1458 break;
1459 }
1460 /* XXX This will only work if it is the first command, and I'm not sure fixing it is worth the effort. */
1461 if (strncmp(inbuf, "cli quit after ", 15) == 0) {
1462 ast_cli_command_multiple_full(con->uid, con->gid, con->fd, bytes_read - 15, inbuf + 15);
1463 break;
1464 }
1465 /* ast_cli_command_multiple_full will only process individual commands terminated by a
1466 * NULL and not trailing partial commands. */
1467 if (!(cmds_read = ast_cli_command_multiple_full(con->uid, con->gid, con->fd, bytes_read + start_read - inbuf, inbuf))) {
1468 /* No commands were read. We either have a short read on the first command
1469 * with space left, or a command that is too long */
1470 if (start_read + bytes_read < end_buf) {
1471 start_read += bytes_read;
1472 } else {
1473 ast_log(LOG_ERROR, "Command too long! Skipping\n");
1474 start_read = inbuf;
1475 }
1476 continue;
1477 }
1478 if (start_read[bytes_read - 1] == '\0') {
1479 /* The read ended on a command boundary, start reading again at the head of inbuf */
1480 start_read = inbuf;
1481 continue;
1482 }
1483 /* If we get this far, we have left over characters that have not been processed.
1484 * Advance to the character after the last command read by ast_cli_command_multiple_full.
1485 * We are guaranteed to have at least cmds_read NULLs */
1486 while (cmds_read-- && (start_read = strchr(start_read, '\0'))) {
1487 start_read++;
1488 }
1489 memmove(inbuf, start_read, end_buf - start_read);
1490 start_read = end_buf - start_read + inbuf;
1491 }
1492 if (fds[1].revents) {
1493 res = read_credentials(con->p[0], outbuf, sizeof(outbuf), con);
1494 if (res < 1) {
1495 ast_log(LOG_ERROR, "read returned %d\n", res);
1496 break;
1497 }
1498 res = write(con->fd, outbuf, res);
1499 if (res < 1)
1500 break;
1501 }
1502 }
1504 if (!ast_opt_hide_connect) {
1505 ast_verb(3, "Remote UNIX connection disconnected\n");
1506 }
1507 close(con->fd);
1508 close(con->p[0]);
1509 close(con->p[1]);
1510 con->fd = -1;
1511
1512 return NULL;
1513}
1514
1515static void *listener(void *unused)
1516{
1517 struct sockaddr_un sunaddr;
1518 int s;
1519 socklen_t len;
1520 int x;
1521 int poll_result;
1522 struct pollfd fds[1];
1523
1524 for (;;) {
1525 if (ast_socket < 0) {
1526 return NULL;
1527 }
1528 fds[0].fd = ast_socket;
1529 fds[0].events = POLLIN;
1530 poll_result = ast_poll(fds, 1, -1);
1531 pthread_testcancel();
1532 if (poll_result < 0) {
1533 if (errno != EINTR) {
1534 ast_log(LOG_WARNING, "poll returned error: %s\n", strerror(errno));
1535 }
1536 continue;
1537 }
1538 len = sizeof(sunaddr);
1539 s = accept(ast_socket, (struct sockaddr *)&sunaddr, &len);
1540 if (s < 0) {
1541 if (errno != EINTR)
1542 ast_log(LOG_WARNING, "Accept returned %d: %s\n", s, strerror(errno));
1543 } else {
1544#if defined(SO_PASSCRED)
1545 int sckopt = 1;
1546 /* turn on socket credentials passing. */
1547 if (setsockopt(s, SOL_SOCKET, SO_PASSCRED, &sckopt, sizeof(sckopt)) < 0) {
1548 ast_log(LOG_WARNING, "Unable to turn on socket credentials passing\n");
1549 close(s);
1550 } else
1551#endif
1552 {
1553 for (x = 0; x < AST_MAX_CONNECTS; x++) {
1554 if (consoles[x].fd >= 0) {
1555 continue;
1556 }
1557 if (socketpair(AF_LOCAL, SOCK_STREAM, 0, consoles[x].p)) {
1558 ast_log(LOG_ERROR, "Unable to create pipe: %s\n", strerror(errno));
1559 fdprint(s, "Server failed to create pipe\n");
1560 close(s);
1561 break;
1562 }
1563 ast_fd_set_flags(consoles[x].p[1], O_NONBLOCK);
1564 consoles[x].mute = 1; /* Default is muted, we will un-mute if necessary */
1565 /* Default uid and gid to -2, so then in cli.c/cli_has_permissions() we will be able
1566 to know if the user didn't send the credentials. */
1567 consoles[x].uid = -2;
1568 consoles[x].gid = -2;
1569 /* Server default of remote console verbosity level is OFF. */
1570 consoles[x].option_verbose = 0;
1571 consoles[x].fd = s;
1573 consoles[x].fd = -1;
1574 ast_log(LOG_ERROR, "Unable to spawn thread to handle connection: %s\n", strerror(errno));
1575 close(consoles[x].p[0]);
1576 close(consoles[x].p[1]);
1577 fdprint(s, "Server failed to spawn thread\n");
1578 close(s);
1579 }
1580 break;
1581 }
1582 if (x >= AST_MAX_CONNECTS) {
1583 fdprint(s, "No more connections allowed\n");
1584 ast_log(LOG_WARNING, "No more connections allowed\n");
1585 close(s);
1586 } else if ((consoles[x].fd > -1) && (!ast_opt_hide_connect)) {
1587 ast_verb(3, "Remote UNIX connection\n");
1588 }
1589 }
1590 }
1591 }
1592 return NULL;
1593}
1594
1595static int ast_makesocket(void)
1596{
1597 struct sockaddr_un sunaddr;
1598 int res;
1599 int x;
1600 uid_t uid = -1;
1601 gid_t gid = -1;
1602
1603 for (x = 0; x < AST_MAX_CONNECTS; x++) {
1604 consoles[x].fd = -1;
1605 }
1606
1607 if (ast_socket_is_sd) {
1609
1610 goto start_lthread;
1611 }
1612
1613 unlink(ast_config_AST_SOCKET);
1614 ast_socket = socket(PF_LOCAL, SOCK_STREAM, 0);
1615 if (ast_socket < 0) {
1616 ast_log(LOG_WARNING, "Unable to create control socket: %s\n", strerror(errno));
1617 return -1;
1618 }
1619 memset(&sunaddr, 0, sizeof(sunaddr));
1620 sunaddr.sun_family = AF_LOCAL;
1621 ast_copy_string(sunaddr.sun_path, ast_config_AST_SOCKET, sizeof(sunaddr.sun_path));
1622 res = bind(ast_socket, (struct sockaddr *)&sunaddr, sizeof(sunaddr));
1623 if (res) {
1624 ast_log(LOG_WARNING, "Unable to bind socket to %s: %s\n", ast_config_AST_SOCKET, strerror(errno));
1625 close(ast_socket);
1626 ast_socket = -1;
1627 return -1;
1628 }
1629 res = listen(ast_socket, 2);
1630 if (res < 0) {
1631 ast_log(LOG_WARNING, "Unable to listen on socket %s: %s\n", ast_config_AST_SOCKET, strerror(errno));
1632 close(ast_socket);
1633 ast_socket = -1;
1634 return -1;
1635 }
1636
1637start_lthread:
1639 ast_log(LOG_WARNING, "Unable to create listener thread.\n");
1640 close(ast_socket);
1641 return -1;
1642 }
1643
1644 if (ast_socket_is_sd) {
1645 /* owner/group/permissions are set by systemd, we might not even have access
1646 * to socket file so leave it alone */
1647 return 0;
1648 }
1649
1651 struct passwd *pw;
1652 if ((pw = getpwnam(ast_config_AST_CTL_OWNER)) == NULL)
1653 ast_log(LOG_WARNING, "Unable to find uid of user %s\n", ast_config_AST_CTL_OWNER);
1654 else
1655 uid = pw->pw_uid;
1656 }
1657
1659 struct group *grp;
1660 if ((grp = getgrnam(ast_config_AST_CTL_GROUP)) == NULL)
1661 ast_log(LOG_WARNING, "Unable to find gid of group %s\n", ast_config_AST_CTL_GROUP);
1662 else
1663 gid = grp->gr_gid;
1664 }
1665
1666 if (chown(ast_config_AST_SOCKET, uid, gid) < 0)
1667 ast_log(LOG_WARNING, "Unable to change ownership of %s: %s\n", ast_config_AST_SOCKET, strerror(errno));
1668
1670 unsigned int p1;
1671 mode_t p;
1672 sscanf(ast_config_AST_CTL_PERMISSIONS, "%30o", &p1);
1673 p = p1;
1674 if ((chmod(ast_config_AST_SOCKET, p)) < 0)
1675 ast_log(LOG_WARNING, "Unable to change file permissions of %s: %s\n", ast_config_AST_SOCKET, strerror(errno));
1676 }
1677
1678 return 0;
1679}
1680
1681static int ast_tryconnect(void)
1682{
1683 struct sockaddr_un sunaddr;
1684 int res;
1685 ast_consock = socket(PF_LOCAL, SOCK_STREAM, 0);
1686 if (ast_consock < 0) {
1687 fprintf(stderr, "Unable to create socket: %s\n", strerror(errno));
1688 return 0;
1689 }
1690 memset(&sunaddr, 0, sizeof(sunaddr));
1691 sunaddr.sun_family = AF_LOCAL;
1692 ast_copy_string(sunaddr.sun_path, ast_config_AST_SOCKET, sizeof(sunaddr.sun_path));
1693 res = connect(ast_consock, (struct sockaddr *)&sunaddr, sizeof(sunaddr));
1694 if (res) {
1695 close(ast_consock);
1696 ast_consock = -1;
1697 return 0;
1698 } else
1699 return 1;
1700}
1701
1702/*! \brief Urgent handler
1703 *
1704 * Called by soft_hangup to interrupt the poll, read, or other
1705 * system call. We don't actually need to do anything though.
1706 * Remember: Cannot EVER ast_log from within a signal handler
1707 */
1708static void _urg_handler(int num)
1709{
1710 return;
1711}
1712
1713static struct sigaction urg_handler = {
1714 .sa_handler = _urg_handler,
1715};
1716
1717static void _hup_handler(int num)
1718{
1719 int save_errno = errno;
1720
1721 if (restartnow) {
1722 if (el) {
1723 el_end(el);
1724 }
1725 execvp(_argv[0], _argv);
1726 }
1727
1728 printf("Received HUP signal -- Reloading configs\n");
1729 sig_flags.need_reload = 1;
1731 fprintf(stderr, "hup_handler: write() failed: %s\n", strerror(errno));
1732 }
1733 errno = save_errno;
1734}
1735
1736static struct sigaction hup_handler = {
1737 .sa_handler = _hup_handler,
1738 .sa_flags = SA_RESTART,
1739};
1740
1741static void _child_handler(int sig)
1742{
1743 /* Must not ever ast_log or ast_verbose within signal handler */
1744 int n, status, save_errno = errno;
1745
1746 /*
1747 * Reap all dead children -- not just one
1748 */
1749 for (n = 0; waitpid(-1, &status, WNOHANG) > 0; n++)
1750 ;
1751 if (n == 0 && option_debug)
1752 printf("Huh? Child handler, but nobody there?\n");
1753 errno = save_errno;
1754}
1755
1756static struct sigaction child_handler = {
1757 .sa_handler = _child_handler,
1758 .sa_flags = SA_RESTART,
1759};
1760
1761/*! \brief Set an X-term or screen title */
1762static void set_title(char *text)
1763{
1764 if (getenv("TERM") && strstr(getenv("TERM"), "xterm"))
1765 fprintf(stdout, "\033]2;%s\007", text);
1766}
1767
1768static void set_icon(char *text)
1769{
1770 if (getenv("TERM") && strstr(getenv("TERM"), "xterm"))
1771 fprintf(stdout, "\033]1;%s\007", text);
1772}
1773
1774/*! \brief Check whether we were set to high(er) priority. */
1775static int has_priority(void)
1776{
1777 /* Neither of these calls should fail with these arguments. */
1778#ifdef __linux__
1779 /* For SCHED_OTHER, SCHED_BATCH and SCHED_IDLE, this will return
1780 * 0. For the realtime priorities SCHED_RR and SCHED_FIFO, it
1781 * will return something >= 1. */
1782 return sched_getscheduler(0);
1783#else
1784 /* getpriority() can return a value in -20..19 (or even -INF..20)
1785 * where negative numbers are high priority. We don't bother
1786 * checking errno. If the query fails and it returns -1, we'll
1787 * assume that we're running at high prio; a safe assumption
1788 * that will enable the resource starvation monitor (canary)
1789 * just in case. */
1790 return (getpriority(PRIO_PROCESS, 0) < 0);
1791#endif
1792}
1793
1794/*! \brief Set priority on all known threads. */
1795static int set_priority_all(int pri)
1796{
1797#if !defined(__linux__)
1798 /* The non-linux version updates the entire process prio. */
1799 return ast_set_priority(pri);
1800#elif defined(LOW_MEMORY)
1801 ast_log(LOG_WARNING, "Unable to enumerate all threads to update priority\n");
1802 return ast_set_priority(pri);
1803#else
1804 struct thread_list_t *cur;
1805 struct sched_param sched;
1806 char const *policy_str;
1807 int policy;
1808
1809 memset(&sched, 0, sizeof(sched));
1810 if (pri) {
1811 policy = SCHED_RR;
1812 policy_str = "realtime";
1813 sched.sched_priority = 10;
1814 } else {
1815 policy = SCHED_OTHER;
1816 policy_str = "regular";
1817 sched.sched_priority = 0;
1818 }
1819 if (sched_setscheduler(getpid(), policy, &sched)) {
1820 ast_log(LOG_WARNING, "Unable to set %s thread priority on main thread\n", policy_str);
1821 return -1;
1822 }
1823 ast_verb(1, "Setting %s thread priority on all threads\n", policy_str);
1825 AST_RWLIST_TRAVERSE(&thread_list, cur, list) {
1826 /* Don't care about the return value. It should work. */
1827 sched_setscheduler(cur->lwp, policy, &sched);
1828 }
1830 return 0;
1831#endif
1832}
1833
1834/*! \brief We set ourselves to a high priority, that we might pre-empt
1835 * everything else. If your PBX has heavy activity on it, this is a
1836 * good thing.
1837 */
1839{
1840 struct sched_param sched;
1841 memset(&sched, 0, sizeof(sched));
1842#ifdef __linux__
1843 if (pri) {
1844 sched.sched_priority = 10;
1845 if (sched_setscheduler(0, SCHED_RR, &sched)) {
1846 return -1;
1847 }
1848 } else {
1849 sched.sched_priority = 0;
1850 /* According to the manpage, these parameters can never fail. */
1851 sched_setscheduler(0, SCHED_OTHER, &sched);
1852 }
1853#else
1854 if (pri) {
1855 if (setpriority(PRIO_PROCESS, 0, -10) == -1) {
1856 ast_log(LOG_WARNING, "Unable to set high priority\n");
1857 return -1;
1858 } else
1859 ast_verb(1, "Set to high priority\n");
1860 } else {
1861 /* According to the manpage, these parameters can never fail. */
1862 setpriority(PRIO_PROCESS, 0, 0);
1863 }
1864#endif
1865 return 0;
1866}
1867
1869{
1871}
1872
1874{
1875 return shutdown_pending;
1876}
1877
1879{
1880 int shutdown_aborted = 0;
1881
1883 if (shuttingdown >= SHUTDOWN_FAST) {
1885 shutdown_pending = 0;
1886 shutdown_aborted = 1;
1887 }
1889 return shutdown_aborted;
1890}
1891
1892/*!
1893 * \internal
1894 * \brief Initiate system shutdown -- prevents new channels from being allocated.
1895 */
1896static void ast_begin_shutdown(void)
1897{
1900 shutdown_pending = 1;
1901 }
1903}
1904
1905static int can_safely_quit(shutdown_nice_t niceness, int restart);
1906static void really_quit(int num, shutdown_nice_t niceness, int restart);
1907
1908static void quit_handler(int num, shutdown_nice_t niceness, int restart)
1909{
1910 if (can_safely_quit(niceness, restart)) {
1911 really_quit(num, niceness, restart);
1912 /* No one gets here. */
1913 }
1914 /* It wasn't our time. */
1915}
1916
1917#define SHUTDOWN_TIMEOUT 15 /* Seconds */
1918
1919/*!
1920 * \internal
1921 * \brief Wait for all channels to die, a timeout, or shutdown cancelled.
1922 * \since 13.3.0
1923 *
1924 * \param niceness Shutdown niceness in effect
1925 * \param seconds Number of seconds to wait or less than zero if indefinitely.
1926 *
1927 * \retval zero if waiting wasn't necessary. We were idle.
1928 * \retval non-zero if we had to wait.
1929 */
1930static int wait_for_channels_to_die(shutdown_nice_t niceness, int seconds)
1931{
1932 time_t start;
1933 time_t now;
1934 int waited = 0;
1935
1936 time(&start);
1937 for (;;) {
1938 if (!ast_undestroyed_channels() || shuttingdown != niceness) {
1939 break;
1940 }
1941 if (seconds < 0) {
1942 /* No timeout so just poll every second */
1943 sleep(1);
1944 } else {
1945 time(&now);
1946
1947 /* Wait up to the given seconds for all channels to go away */
1948 if (seconds < (now - start)) {
1949 break;
1950 }
1951
1952 /* Sleep 1/10 of a second */
1953 usleep(100000);
1954 }
1955 waited = 1;
1956 }
1957 return waited;
1958}
1959
1960static int can_safely_quit(shutdown_nice_t niceness, int restart)
1961{
1962 int waited = 0;
1963
1964 /* Check if someone else isn't already doing this. */
1966 if (shuttingdown != NOT_SHUTTING_DOWN && niceness >= shuttingdown) {
1967 /* Already in progress and other request was less nice. */
1969 ast_verbose("Ignoring asterisk %s request, already in progress.\n", restart ? "restart" : "shutdown");
1970 return 0;
1971 }
1972 shuttingdown = niceness;
1974
1975 /* Try to get as many CDRs as possible submitted to the backend engines
1976 * (if in batch mode). really_quit happens to call it again when running
1977 * the atexit handlers, otherwise this would be a bit early. */
1979
1980 /*
1981 * Shutdown the message queue for the technology agnostic message channel.
1982 * This has to occur before we pause shutdown pending ast_undestroyed_channels.
1983 *
1984 * XXX This is not reversed on shutdown cancel.
1985 */
1987
1988 if (niceness == SHUTDOWN_NORMAL) {
1989 /* Begin shutdown routine, hanging up active channels */
1991 if (ast_opt_console) {
1992 ast_verb(0, "Beginning asterisk %s....\n", restart ? "restart" : "shutdown");
1993 }
1995 waited |= wait_for_channels_to_die(niceness, SHUTDOWN_TIMEOUT);
1996 } else if (niceness >= SHUTDOWN_NICE) {
1997 if (niceness != SHUTDOWN_REALLY_NICE) {
1999 }
2000 if (ast_opt_console) {
2001 ast_verb(0, "Waiting for inactivity to perform %s...\n", restart ? "restart" : "halt");
2002 }
2003 waited |= wait_for_channels_to_die(niceness, -1);
2004 }
2005
2006 /* Re-acquire lock and check if someone changed the niceness, in which
2007 * case someone else has taken over the shutdown.
2008 */
2010 if (shuttingdown != niceness) {
2012 ast_verb(0, "Asterisk %s cancelled.\n", restart ? "restart" : "shutdown");
2013 }
2015 return 0;
2016 }
2017
2018 if (niceness >= SHUTDOWN_REALLY_NICE) {
2021
2022 /* No more Mr. Nice guy. We are committed to shutting down now. */
2026
2028 }
2031
2032 if (niceness >= SHUTDOWN_NORMAL && waited) {
2033 /*
2034 * We were not idle. Give things in progress a chance to
2035 * recognize the final shutdown phase.
2036 */
2037 sleep(1);
2038 }
2039 return 1;
2040}
2041
2042/*! Called when exiting is certain. */
2043static void really_quit(int num, shutdown_nice_t niceness, int restart)
2044{
2045 int active_channels;
2046 struct ast_json *json_object = NULL;
2047 int run_cleanups = niceness >= SHUTDOWN_NICE;
2048
2049 if (run_cleanups && modules_shutdown()) {
2050 ast_verb(0, "Some modules could not be unloaded, switching to fast shutdown\n");
2051 run_cleanups = 0;
2052 }
2053
2054 if (!restart && !ast_opt_remote) {
2055 ast_sd_notify("STOPPING=1");
2056 }
2059 if (consolethread == AST_PTHREADT_NULL || consolethread == pthread_self()) {
2060 /* Only end if we are the consolethread, otherwise there's a race with that thread. */
2061 if (el != NULL) {
2062 el_end(el);
2063 }
2064 if (el_hist != NULL) {
2065 history_end(el_hist);
2066 }
2067 } else if (!restart) {
2068 sig_flags.need_el_end = 1;
2069 pthread_kill(consolethread, SIGURG);
2070 }
2071 }
2072 active_channels = ast_active_channels();
2073 /* Don't publish messages if we're a remote console - we won't have all of the Stasis
2074 * topics or message types
2075 */
2076 if (!ast_opt_remote) {
2077 json_object = ast_json_pack("{s: s, s: s}",
2078 "Shutdown", active_channels ? "Uncleanly" : "Cleanly",
2079 "Restart", restart ? "True" : "False");
2080 ast_manager_publish_event("Shutdown", EVENT_FLAG_SYSTEM, json_object);
2081 ast_json_unref(json_object);
2082 json_object = NULL;
2083 }
2084 ast_verb(0, "Asterisk %s ending (%d).\n",
2085 active_channels ? "uncleanly" : "cleanly", num);
2086
2087 ast_verb(0, "Executing last minute cleanups\n");
2088 ast_run_atexits(run_cleanups);
2089
2090 ast_debug(1, "Asterisk ending (%d).\n", num);
2091 if (ast_socket > -1) {
2092 pthread_cancel(lthread);
2093 close(ast_socket);
2094 ast_socket = -1;
2095 if (!ast_socket_is_sd) {
2096 unlink(ast_config_AST_SOCKET);
2097 }
2098 pthread_kill(lthread, SIGURG);
2099 pthread_join(lthread, NULL);
2100 }
2101 if (ast_consock > -1)
2102 close(ast_consock);
2103 if (!ast_opt_remote)
2104 unlink(ast_config_AST_PID);
2106 printf("%s", term_quit());
2107 if (restart) {
2108 int i;
2109 ast_verb(0, "Preparing for Asterisk restart...\n");
2110 /* Mark all FD's for closing on exec */
2111 for (i = 3; i < 32768; i++) {
2112 fcntl(i, F_SETFD, FD_CLOEXEC);
2113 }
2114 ast_verb(0, "Asterisk is now restarting...\n");
2115 restartnow = 1;
2116
2117 /* close logger */
2118 close_logger();
2120
2121 /* If there is a consolethread running send it a SIGHUP
2122 so it can execvp, otherwise we can do it ourselves */
2123 if ((consolethread != AST_PTHREADT_NULL) && (consolethread != pthread_self())) {
2124 pthread_kill(consolethread, SIGHUP);
2125 /* Give the signal handler some time to complete */
2126 sleep(2);
2127 } else
2128 execvp(_argv[0], _argv);
2129
2130 } else {
2131 /* close logger */
2132 close_logger();
2134 }
2135
2136 exit(0);
2137}
2138
2139static void __quit_handler(int num)
2140{
2141 sig_flags.need_quit = 1;
2143 fprintf(stderr, "quit_handler: write() failed: %s\n", strerror(errno));
2144 }
2145 /* There is no need to restore the signal handler here, since the app
2146 * is going to exit */
2147}
2148
2149static void __remote_quit_handler(int num)
2150{
2151 sig_flags.need_quit = 1;
2152}
2153
2154static void set_header(char *outbuf, int maxout, char level)
2155{
2156 const char *cmp;
2157 char date[40];
2158
2159 switch (level) {
2160 case 0: cmp = NULL;
2161 break;
2162 case 1: cmp = VERBOSE_PREFIX_1;
2163 break;
2164 case 2: cmp = VERBOSE_PREFIX_2;
2165 break;
2166 case 3: cmp = VERBOSE_PREFIX_3;
2167 break;
2168 case 4: cmp = VERBOSE_PREFIX_4;
2169 break;
2170 case 5: cmp = VERBOSE_PREFIX_5;
2171 break;
2172 case 6: cmp = VERBOSE_PREFIX_6;
2173 break;
2174 case 7: cmp = VERBOSE_PREFIX_7;
2175 break;
2176 case 8: cmp = VERBOSE_PREFIX_8;
2177 break;
2178 case 9: cmp = VERBOSE_PREFIX_9;
2179 break;
2180 default: cmp = VERBOSE_PREFIX_10;
2181 break;
2182 }
2183
2184 if (ast_opt_timestamp) {
2185 struct ast_tm tm;
2186 struct timeval now = ast_tvnow();
2187 ast_localtime(&now, &tm, NULL);
2188 ast_strftime(date, sizeof(date), ast_logger_get_dateformat(), &tm);
2189 }
2190
2191 snprintf(outbuf, maxout, "%s%s%s%s%s%s",
2192 ast_opt_timestamp ? "[" : "",
2193 ast_opt_timestamp ? date : "",
2194 ast_opt_timestamp ? "] " : "",
2195 cmp ? ast_term_color(COLOR_GRAY, 0) : "",
2196 cmp ? cmp : "",
2197 cmp ? ast_term_reset() : "");
2198}
2199
2202};
2203
2204static int console_state_init(void *ptr)
2205{
2206 struct console_state_data *state = ptr;
2207 state->verbose_line_level = 0;
2208 return 0;
2209}
2210
2212
2213static int console_print(const char *s)
2214{
2215 struct console_state_data *state =
2217
2218 char prefix[80];
2219 const char *c;
2220 int num, res = 0;
2221 unsigned int newline;
2222
2223 do {
2224 if (VERBOSE_HASMAGIC(s)) {
2225
2226 /* always use the given line's level, otherwise
2227 we'll use the last line's level */
2228 state->verbose_line_level = VERBOSE_MAGIC2LEVEL(s);
2229
2230 /* move past magic */
2231 s++;
2232
2233 set_header(prefix, sizeof(prefix), state->verbose_line_level);
2234 } else {
2235 *prefix = '\0';
2236 }
2237 c = s;
2238
2239 /* for a given line separate on verbose magic, newline, and eol */
2240 if ((s = strchr(c, '\n'))) {
2241 ++s;
2242 newline = 1;
2243 } else {
2244 s = strchr(c, '\0');
2245 newline = 0;
2246 }
2247
2248 /* check if we should write this line after calculating begin/end
2249 so we process the case of a higher level line embedded within
2250 two lower level lines */
2251 if (state->verbose_line_level > option_verbose) {
2252 continue;
2253 }
2254
2255 if (!ast_strlen_zero(prefix)) {
2256 fputs(prefix, stdout);
2257 }
2258
2259 num = s - c;
2260 if (fwrite(c, sizeof(char), num, stdout) < num) {
2261 break;
2262 }
2263
2264 if (!res) {
2265 /* if at least some info has been written
2266 we'll want to return true */
2267 res = 1;
2268 }
2269 } while (*s);
2270
2271 if (newline) {
2272 /* if ending on a newline then reset last level to zero
2273 since what follows may be not be logging output */
2274 state->verbose_line_level = 0;
2275 }
2276
2277 if (res) {
2278 fflush(stdout);
2279 }
2280
2281 return res;
2282}
2283
2284static int ast_all_zeros(const char *s)
2285{
2286 while (*s) {
2287 if (*s > 32)
2288 return 0;
2289 s++;
2290 }
2291 return 1;
2292}
2293
2294/* This is the main console CLI command handler. Run by the main() thread. */
2295static void consolehandler(const char *s)
2296{
2297 printf("%s", term_end());
2298 fflush(stdout);
2299
2300 /* Called when readline data is available */
2301 if (!ast_all_zeros(s))
2303 /* The real handler for bang */
2304 if (s[0] == '!') {
2305 if (s[1])
2306 ast_safe_system(s+1);
2307 else
2308 ast_safe_system(getenv("SHELL") ? getenv("SHELL") : "/bin/sh");
2309 } else
2310 ast_cli_command(STDOUT_FILENO, s);
2311}
2312
2313static int remoteconsolehandler(const char *s)
2314{
2315 int ret = 0;
2316
2317 /* Called when readline data is available */
2318 if (!ast_all_zeros(s))
2320
2321 while (isspace(*s)) {
2322 s++;
2323 }
2324
2325 /* The real handler for bang */
2326 if (s[0] == '!') {
2327 if (s[1])
2328 ast_safe_system(s+1);
2329 else
2330 ast_safe_system(getenv("SHELL") ? getenv("SHELL") : "/bin/sh");
2331 ret = 1;
2332 } else if ((strncasecmp(s, "quit", 4) == 0 || strncasecmp(s, "exit", 4) == 0) &&
2333 (s[4] == '\0' || isspace(s[4]))) {
2335 ret = 1;
2336 }
2337
2338 return ret;
2339}
2340
2341static char *handle_version(struct ast_cli_entry *e, int cmd, struct ast_cli_args *a)
2342{
2343 switch (cmd) {
2344 case CLI_INIT:
2345 e->command = "core show version";
2346 e->usage =
2347 "Usage: core show version\n"
2348 " Shows Asterisk version information.\n";
2349 return NULL;
2350 case CLI_GENERATE:
2351 return NULL;
2352 }
2353
2354 if (a->argc != 3)
2355 return CLI_SHOWUSAGE;
2356 ast_cli(a->fd, "Asterisk %s built by %s @ %s on a %s running %s on %s\n",
2359 return CLI_SUCCESS;
2360}
2361
2362static char *handle_stop_now(struct ast_cli_entry *e, int cmd, struct ast_cli_args *a)
2363{
2364 switch (cmd) {
2365 case CLI_INIT:
2366 e->command = "core stop now";
2367 e->usage =
2368 "Usage: core stop now\n"
2369 " Shuts down a running Asterisk immediately, hanging up all active calls .\n";
2371 return NULL;
2372 case CLI_GENERATE:
2373 return NULL;
2374 }
2375
2376 if (a->argc != e->args)
2377 return CLI_SHOWUSAGE;
2378 quit_handler(0, SHUTDOWN_NORMAL, 0 /* not restart */);
2379 return CLI_SUCCESS;
2380}
2381
2382static char *handle_stop_gracefully(struct ast_cli_entry *e, int cmd, struct ast_cli_args *a)
2383{
2384 switch (cmd) {
2385 case CLI_INIT:
2386 e->command = "core stop gracefully";
2387 e->usage =
2388 "Usage: core stop gracefully\n"
2389 " Causes Asterisk to not accept new calls, and exit when all\n"
2390 " active calls have terminated normally.\n";
2392 return NULL;
2393 case CLI_GENERATE:
2394 return NULL;
2395 }
2396
2397 if (a->argc != e->args)
2398 return CLI_SHOWUSAGE;
2399 quit_handler(0, SHUTDOWN_NICE, 0 /* no restart */);
2400 return CLI_SUCCESS;
2401}
2402
2403static char *handle_stop_when_convenient(struct ast_cli_entry *e, int cmd, struct ast_cli_args *a)
2404{
2405 switch (cmd) {
2406 case CLI_INIT:
2407 e->command = "core stop when convenient";
2408 e->usage =
2409 "Usage: core stop when convenient\n"
2410 " Causes Asterisk to perform a shutdown when all active calls have ended.\n";
2412 return NULL;
2413 case CLI_GENERATE:
2414 return NULL;
2415 }
2416
2417 if (a->argc != e->args)
2418 return CLI_SHOWUSAGE;
2419 ast_cli(a->fd, "Waiting for inactivity to perform halt\n");
2420 quit_handler(0, SHUTDOWN_REALLY_NICE, 0 /* don't restart */);
2421 return CLI_SUCCESS;
2422}
2423
2424static char *handle_restart_now(struct ast_cli_entry *e, int cmd, struct ast_cli_args *a)
2425{
2426 switch (cmd) {
2427 case CLI_INIT:
2428 e->command = "core restart now";
2429 e->usage =
2430 "Usage: core restart now\n"
2431 " Causes Asterisk to hangup all calls and exec() itself performing a cold\n"
2432 " restart.\n";
2434 return NULL;
2435 case CLI_GENERATE:
2436 return NULL;
2437 }
2438
2439 if (a->argc != e->args)
2440 return CLI_SHOWUSAGE;
2441 quit_handler(0, SHUTDOWN_NORMAL, 1 /* restart */);
2442 return CLI_SUCCESS;
2443}
2444
2445static char *handle_restart_gracefully(struct ast_cli_entry *e, int cmd, struct ast_cli_args *a)
2446{
2447 switch (cmd) {
2448 case CLI_INIT:
2449 e->command = "core restart gracefully";
2450 e->usage =
2451 "Usage: core restart gracefully\n"
2452 " Causes Asterisk to stop accepting new calls and exec() itself performing a cold\n"
2453 " restart when all active calls have ended.\n";
2455 return NULL;
2456 case CLI_GENERATE:
2457 return NULL;
2458 }
2459
2460 if (a->argc != e->args)
2461 return CLI_SHOWUSAGE;
2462 quit_handler(0, SHUTDOWN_NICE, 1 /* restart */);
2463 return CLI_SUCCESS;
2464}
2465
2466static char *handle_restart_when_convenient(struct ast_cli_entry *e, int cmd, struct ast_cli_args *a)
2467{
2468 switch (cmd) {
2469 case CLI_INIT:
2470 e->command = "core restart when convenient";
2471 e->usage =
2472 "Usage: core restart when convenient\n"
2473 " Causes Asterisk to perform a cold restart when all active calls have ended.\n";
2475 return NULL;
2476 case CLI_GENERATE:
2477 return NULL;
2478 }
2479
2480 if (a->argc != e->args)
2481 return CLI_SHOWUSAGE;
2482 ast_cli(a->fd, "Waiting for inactivity to perform restart\n");
2483 quit_handler(0, SHUTDOWN_REALLY_NICE, 1 /* restart */);
2484 return CLI_SUCCESS;
2485}
2486
2487static char *handle_abort_shutdown(struct ast_cli_entry *e, int cmd, struct ast_cli_args *a)
2488{
2489 switch (cmd) {
2490 case CLI_INIT:
2491 e->command = "core abort shutdown";
2492 e->usage =
2493 "Usage: core abort shutdown\n"
2494 " Causes Asterisk to abort an executing shutdown or restart, and resume normal\n"
2495 " call operations.\n";
2497 return NULL;
2498 case CLI_GENERATE:
2499 return NULL;
2500 }
2501
2502 if (a->argc != e->args)
2503 return CLI_SHOWUSAGE;
2504
2506
2507 return CLI_SUCCESS;
2508}
2509
2510static char *handle_bang(struct ast_cli_entry *e, int cmd, struct ast_cli_args *a)
2511{
2512 switch (cmd) {
2513 case CLI_INIT:
2514 e->command = "!";
2515 e->usage =
2516 "Usage: !<command>\n"
2517 " Executes a given shell command\n";
2518 return NULL;
2519 case CLI_GENERATE:
2520 return NULL;
2521 }
2522
2523 return CLI_SUCCESS;
2524}
2525static const char warranty_lines[] = {
2526 "\n"
2527 " NO WARRANTY\n"
2528 "\n"
2529 "BECAUSE THE PROGRAM IS LICENSED FREE OF CHARGE, THERE IS NO WARRANTY\n"
2530 "FOR THE PROGRAM, TO THE EXTENT PERMITTED BY APPLICABLE LAW. EXCEPT WHEN\n"
2531 "OTHERWISE STATED IN WRITING THE COPYRIGHT HOLDERS AND/OR OTHER PARTIES\n"
2532 "PROVIDE THE PROGRAM \"AS IS\" WITHOUT WARRANTY OF ANY KIND, EITHER EXPRESSED\n"
2533 "OR IMPLIED, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF\n"
2534 "MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE. THE ENTIRE RISK AS\n"
2535 "TO THE QUALITY AND PERFORMANCE OF THE PROGRAM IS WITH YOU. SHOULD THE\n"
2536 "PROGRAM PROVE DEFECTIVE, YOU ASSUME THE COST OF ALL NECESSARY SERVICING,\n"
2537 "REPAIR OR CORRECTION.\n"
2538 "\n"
2539 "IN NO EVENT UNLESS REQUIRED BY APPLICABLE LAW OR AGREED TO IN WRITING\n"
2540 "WILL ANY COPYRIGHT HOLDER, OR ANY OTHER PARTY WHO MAY MODIFY AND/OR\n"
2541 "REDISTRIBUTE THE PROGRAM AS PERMITTED ABOVE, BE LIABLE TO YOU FOR DAMAGES,\n"
2542 "INCLUDING ANY GENERAL, SPECIAL, INCIDENTAL OR CONSEQUENTIAL DAMAGES ARISING\n"
2543 "OUT OF THE USE OR INABILITY TO USE THE PROGRAM (INCLUDING BUT NOT LIMITED\n"
2544 "TO LOSS OF DATA OR DATA BEING RENDERED INACCURATE OR LOSSES SUSTAINED BY\n"
2545 "YOU OR THIRD PARTIES OR A FAILURE OF THE PROGRAM TO OPERATE WITH ANY OTHER\n"
2546 "PROGRAMS), EVEN IF SUCH HOLDER OR OTHER PARTY HAS BEEN ADVISED OF THE\n"
2547 "POSSIBILITY OF SUCH DAMAGES.\n"
2548};
2549
2550static char *show_warranty(struct ast_cli_entry *e, int cmd, struct ast_cli_args *a)
2551{
2552 switch (cmd) {
2553 case CLI_INIT:
2554 e->command = "core show warranty";
2555 e->usage =
2556 "Usage: core show warranty\n"
2557 " Shows the warranty (if any) for this copy of Asterisk.\n";
2558 return NULL;
2559 case CLI_GENERATE:
2560 return NULL;
2561 }
2562
2563 ast_cli(a->fd, "%s", warranty_lines);
2564
2565 return CLI_SUCCESS;
2566}
2567
2568static const char license_lines[] = {
2569 "\n"
2570 "This program is free software; you can redistribute it and/or modify\n"
2571 "it under the terms of the GNU General Public License version 2 as\n"
2572 "published by the Free Software Foundation.\n"
2573 "\n"
2574 "This program also contains components licensed under other licenses.\n"
2575 "They include:\n"
2576 "\n"
2577 "This program is distributed in the hope that it will be useful,\n"
2578 "but WITHOUT ANY WARRANTY; without even the implied warranty of\n"
2579 "MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the\n"
2580 "GNU General Public License for more details.\n"
2581 "\n"
2582 "You should have received a copy of the GNU General Public License\n"
2583 "along with this program; if not, write to the Free Software\n"
2584 "Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA\n"
2585};
2586
2587static char *show_license(struct ast_cli_entry *e, int cmd, struct ast_cli_args *a)
2588{
2589 switch (cmd) {
2590 case CLI_INIT:
2591 e->command = "core show license";
2592 e->usage =
2593 "Usage: core show license\n"
2594 " Shows the license(s) for this copy of Asterisk.\n";
2595 return NULL;
2596 case CLI_GENERATE:
2597 return NULL;
2598 }
2599
2600 ast_cli(a->fd, "%s", license_lines);
2601
2602 return CLI_SUCCESS;
2603}
2604
2605#define ASTERISK_PROMPT "*CLI> "
2606
2607/*!
2608 * \brief Shutdown Asterisk CLI commands.
2609 *
2610 * \note These CLI commands cannot be unregistered at shutdown
2611 * because one of them is likely the reason for the shutdown.
2612 * The CLI generates a warning if a command is in-use when it is
2613 * unregistered.
2614 */
2616 AST_CLI_DEFINE(handle_stop_now, "Shut down Asterisk immediately"),
2617 AST_CLI_DEFINE(handle_stop_gracefully, "Gracefully shut down Asterisk"),
2618 AST_CLI_DEFINE(handle_stop_when_convenient, "Shut down Asterisk at empty call volume"),
2619 AST_CLI_DEFINE(handle_restart_now, "Restart Asterisk immediately"),
2620 AST_CLI_DEFINE(handle_restart_gracefully, "Restart Asterisk gracefully"),
2621 AST_CLI_DEFINE(handle_restart_when_convenient, "Restart Asterisk at empty call volume"),
2622};
2623
2624static struct ast_cli_entry cli_asterisk[] = {
2625 AST_CLI_DEFINE(handle_abort_shutdown, "Cancel a running shutdown"),
2626 AST_CLI_DEFINE(show_warranty, "Show the warranty (if any) for this copy of Asterisk"),
2627 AST_CLI_DEFINE(show_license, "Show the license(s) for this copy of Asterisk"),
2628 AST_CLI_DEFINE(handle_version, "Display version info"),
2629 AST_CLI_DEFINE(handle_bang, "Execute a shell command"),
2630#if !defined(LOW_MEMORY)
2631 AST_CLI_DEFINE(handle_show_threads, "Show running threads"),
2632#if defined(HAVE_SYSINFO) || defined(HAVE_SYSCTL)
2633 AST_CLI_DEFINE(handle_show_sysinfo, "Show System Information"),
2634#endif
2635 AST_CLI_DEFINE(handle_show_profile, "Display profiling info"),
2636 AST_CLI_DEFINE(handle_show_settings, "Show some core settings"),
2637 AST_CLI_DEFINE(handle_clear_profile, "Clear profiling info"),
2638#endif /* ! LOW_MEMORY */
2639};
2640
2642{
2643 char buf[80];
2644
2645 /*
2646 * Tell the server asterisk instance about the verbose level
2647 * initially desired.
2648 */
2649 if (option_verbose) {
2650 snprintf(buf, sizeof(buf), "core set verbose atleast %d silent", option_verbose);
2652 }
2653
2654 if (option_debug) {
2655 snprintf(buf, sizeof(buf), "core set debug atleast %d", option_debug);
2657 }
2658
2659 /* Leave verbose filtering to the server. */
2660 option_verbose = INT_MAX;
2661
2662 if (!ast_opt_mute) {
2663 fdsend(ast_consock, "logger mute silent");
2664 } else {
2665 printf("log and verbose output currently muted ('logger mute' to unmute)\n");
2666 }
2667}
2668
2669#ifdef HAVE_LIBEDIT_IS_UNICODE
2670#define CHAR_T_LIBEDIT wchar_t
2671#define CHAR_TO_LIBEDIT(c) btowc(c)
2672#else
2673#define CHAR_T_LIBEDIT char
2674#define CHAR_TO_LIBEDIT(c) c
2675#endif
2676
2677static int ast_el_read_char(EditLine *editline, CHAR_T_LIBEDIT *cp)
2678{
2679 int num_read = 0;
2680 int lastpos = 0;
2681 struct pollfd fds[2];
2682 int res;
2683 int max;
2684#define EL_BUF_SIZE 512
2685 char buf[EL_BUF_SIZE];
2686
2687 for (;;) {
2688 max = 1;
2689 fds[0].fd = ast_consock;
2690 fds[0].events = POLLIN;
2691 if (!ast_opt_exec) {
2692 fds[1].fd = STDIN_FILENO;
2693 fds[1].events = POLLIN;
2694 max++;
2695 }
2696 res = ast_poll(fds, max, -1);
2697 if (res < 0) {
2698 if (sig_flags.need_quit || sig_flags.need_quit_handler || sig_flags.need_el_end) {
2699 break;
2700 }
2701 if (errno == EINTR) {
2702 continue;
2703 }
2704 fprintf(stderr, "poll failed: %s\n", strerror(errno));
2705 break;
2706 }
2707
2708 if (!ast_opt_exec && fds[1].revents) {
2709 char c = '\0';
2710
2711 num_read = read(STDIN_FILENO, &c, 1);
2712 if (num_read < 1) {
2713 break;
2714 }
2715
2716 *cp = CHAR_TO_LIBEDIT(c);
2717
2718 return num_read;
2719 }
2720
2721 if (fds[0].revents) {
2722 res = read(ast_consock, buf, sizeof(buf) - 1);
2723 /* if the remote side disappears exit */
2724 if (res < 1) {
2725 fprintf(stderr, "\nDisconnected from Asterisk server\n");
2726 if (!ast_opt_reconnect) {
2728 } else {
2729 int tries;
2730 int reconnects_per_second = 20;
2731
2732 fprintf(stderr, "Attempting to reconnect for 30 seconds\n");
2733 for (tries = 0; tries < 30 * reconnects_per_second; tries++) {
2734 if (ast_tryconnect()) {
2735 fprintf(stderr, "Reconnect succeeded after %.3f seconds\n", 1.0 / reconnects_per_second * tries);
2736 printf("%s", term_quit());
2739 break;
2740 }
2741
2742 usleep(1000000 / reconnects_per_second);
2743 }
2744 if (tries >= 30 * reconnects_per_second) {
2745 fprintf(stderr, "Failed to reconnect for 30 seconds. Quitting.\n");
2747 }
2748 }
2749 continue;
2750 }
2751
2752 buf[res] = '\0';
2753
2754 /* Write over the CLI prompt */
2755 if (!ast_opt_exec && !lastpos) {
2756 if (write(STDOUT_FILENO, "\r␛[0K", 5) < 0) {
2757 }
2758 }
2759
2761
2762 if ((res < EL_BUF_SIZE - 1) && ((buf[res-1] == '\n') || (res >= 2 && buf[res-2] == '\n'))) {
2763 *cp = CHAR_TO_LIBEDIT(CC_REFRESH);
2764
2765 return 1;
2766 }
2767 lastpos = 1;
2768 }
2769 }
2770
2771 *cp = CHAR_TO_LIBEDIT('\0');
2772
2773 return 0;
2774}
2775
2776static struct ast_str *prompt = NULL;
2777
2778static char *cli_prompt(EditLine *editline)
2779{
2780 char tmp[100];
2781 char *pfmt;
2782 int color_used = 0;
2783 static int cli_prompt_changes = 0;
2784 struct passwd *pw;
2785 struct group *gr;
2786
2787 if (prompt == NULL) {
2788 prompt = ast_str_create(100);
2789 } else if (!cli_prompt_changes) {
2790 return ast_str_buffer(prompt);
2791 } else {
2793 }
2794
2795 if ((pfmt = getenv("ASTERISK_PROMPT"))) {
2796 char *t = pfmt;
2797 struct timeval ts = ast_tvnow();
2798 while (*t != '\0') {
2799 if (*t == '%') {
2800 char hostname[MAXHOSTNAMELEN] = "";
2801 int i, which;
2802 struct ast_tm tm = { 0, };
2803 int fgcolor = COLOR_WHITE, bgcolor = COLOR_BLACK;
2804
2805 t++;
2806 switch (*t) {
2807 case 'C': /* color */
2808 t++;
2809 if (sscanf(t, "%30d;%30d%n", &fgcolor, &bgcolor, &i) == 2) {
2810 ast_term_color_code(&prompt, fgcolor, bgcolor);
2811 t += i - 1;
2812 } else if (sscanf(t, "%30d%n", &fgcolor, &i) == 1) {
2813 ast_term_color_code(&prompt, fgcolor, 0);
2814 t += i - 1;
2815 }
2816
2817 /* If the color has been reset correctly, then there's no need to reset it later */
2818 color_used = ((fgcolor == COLOR_WHITE) && (bgcolor == COLOR_BLACK)) ? 0 : 1;
2819 break;
2820 case 'd': /* date */
2821 if (ast_localtime(&ts, &tm, NULL)) {
2822 ast_strftime(tmp, sizeof(tmp), "%Y-%m-%d", &tm);
2823 ast_str_append(&prompt, 0, "%s", tmp);
2824 cli_prompt_changes++;
2825 }
2826 break;
2827 case 'g': /* group */
2828 if ((gr = getgrgid(getgid()))) {
2829 ast_str_append(&prompt, 0, "%s", gr->gr_name);
2830 }
2831 break;
2832 case 'h': /* hostname */
2833 if (!gethostname(hostname, sizeof(hostname) - 1)) {
2834 ast_str_append(&prompt, 0, "%s", hostname);
2835 } else {
2836 ast_str_append(&prompt, 0, "%s", "localhost");
2837 }
2838 break;
2839 case 'H': /* short hostname */
2840 if (!gethostname(hostname, sizeof(hostname) - 1)) {
2841 char *dotptr;
2842 if ((dotptr = strchr(hostname, '.'))) {
2843 *dotptr = '\0';
2844 }
2845 ast_str_append(&prompt, 0, "%s", hostname);
2846 } else {
2847 ast_str_append(&prompt, 0, "%s", "localhost");
2848 }
2849 break;
2850#ifdef HAVE_GETLOADAVG
2851 case 'l': /* load avg */
2852 t++;
2853 if (sscanf(t, "%30d", &which) == 1 && which > 0 && which <= 3) {
2854 double list[3];
2855 getloadavg(list, 3);
2856 ast_str_append(&prompt, 0, "%.2f", list[which - 1]);
2857 cli_prompt_changes++;
2858 }
2859 break;
2860#endif
2861 case 's': /* Asterisk system name (from asterisk.conf) */
2863 break;
2864 case 't': /* time */
2865 if (ast_localtime(&ts, &tm, NULL)) {
2866 ast_strftime(tmp, sizeof(tmp), "%H:%M:%S", &tm);
2867 ast_str_append(&prompt, 0, "%s", tmp);
2868 cli_prompt_changes++;
2869 }
2870 break;
2871 case 'u': /* username */
2872 if ((pw = getpwuid(getuid()))) {
2873 ast_str_append(&prompt, 0, "%s", pw->pw_name);
2874 }
2875 break;
2876 case '#': /* process console or remote? */
2877 ast_str_append(&prompt, 0, "%c", ast_opt_remote ? '>' : '#');
2878 break;
2879 case '%': /* literal % */
2880 ast_str_append(&prompt, 0, "%c", '%');
2881 break;
2882 case '\0': /* % is last character - prevent bug */
2883 t--;
2884 break;
2885 }
2886 } else {
2887 ast_str_append(&prompt, 0, "%c", *t);
2888 }
2889 t++;
2890 }
2891 if (color_used) {
2892 /* Force colors back to normal at end */
2894 }
2895 } else {
2896 ast_str_set(&prompt, 0, "%s%s",
2899 }
2900
2901 return ast_str_buffer(prompt);
2902}
2903
2905{
2906 char *retstr;
2907 struct ast_vector_string *vec = ast_calloc(1, sizeof(*vec));
2908
2909 if (!vec) {
2910 return NULL;
2911 }
2912
2913 while ((retstr = strsep(&buf, " "))) {
2914 if (!strcmp(retstr, AST_CLI_COMPLETE_EOF)) {
2915 break;
2916 }
2917
2918 retstr = ast_strdup(retstr);
2919 if (!retstr || AST_VECTOR_APPEND(vec, retstr)) {
2920 ast_free(retstr);
2921 goto vector_cleanup;
2922 }
2923 }
2924
2925 if (!AST_VECTOR_SIZE(vec)) {
2926 goto vector_cleanup;
2927 }
2928
2929 return vec;
2930
2931vector_cleanup:
2934
2935 return NULL;
2936}
2937
2938static void ast_cli_display_match_list(struct ast_vector_string *matches, int max)
2939{
2940 int idx = 1;
2941 /* find out how many entries can be put on one line, with two spaces between strings */
2942 int limit = ast_get_termcols(STDOUT_FILENO) / (max + 2);
2943
2944 if (limit == 0) {
2945 limit = 1;
2946 }
2947
2948 for (;;) {
2949 int numoutputline;
2950
2951 for (numoutputline = 0; numoutputline < limit && idx < AST_VECTOR_SIZE(matches); idx++) {
2952 numoutputline++;
2953 fprintf(stdout, "%-*s ", max, AST_VECTOR_GET(matches, idx));
2954 }
2955
2956 if (!numoutputline) {
2957 break;
2958 }
2959
2960 fprintf(stdout, "\n");
2961 }
2962}
2963
2964
2965static char *cli_complete(EditLine *editline, int ch)
2966{
2967 int len = 0;
2968 char *ptr;
2969 struct ast_vector_string *matches;
2970 int retval = CC_ERROR;
2971 char savechr;
2972 int res;
2973
2974 LineInfo *lf = (LineInfo *)el_line(editline);
2975
2976 savechr = *(char *)lf->cursor;
2977 *(char *)lf->cursor = '\0';
2978 ptr = (char *)lf->cursor;
2979 if (ptr) {
2980 while (ptr > lf->buffer) {
2981 if (isspace(*ptr)) {
2982 ptr++;
2983 break;
2984 }
2985 ptr--;
2986 }
2987 }
2988
2989 len = lf->cursor - ptr;
2990
2991 if (ast_opt_remote) {
2992#define CMD_MATCHESARRAY "_COMMAND MATCHESARRAY \"%s\" \"%s\""
2993 char *mbuf;
2994 char *new_mbuf;
2995 int mlen = 0;
2996 int maxmbuf = ast_asprintf(&mbuf, CMD_MATCHESARRAY, lf->buffer, ptr);
2997
2998 if (maxmbuf == -1) {
2999 *((char *) lf->cursor) = savechr;
3000
3001 return (char *)(CC_ERROR);
3002 }
3003
3004 fdsend(ast_consock, mbuf);
3005 res = 0;
3006 mlen = 0;
3007 mbuf[0] = '\0';
3008
3009 while (!strstr(mbuf, AST_CLI_COMPLETE_EOF) && res != -1) {
3010 if (mlen + 1024 > maxmbuf) {
3011 /* Expand buffer to the next 1024 byte increment plus a NULL terminator. */
3012 maxmbuf = mlen + 1024;
3013 new_mbuf = ast_realloc(mbuf, maxmbuf + 1);
3014 if (!new_mbuf) {
3015 ast_free(mbuf);
3016 *((char *) lf->cursor) = savechr;
3017
3018 return (char *)(CC_ERROR);
3019 }
3020 mbuf = new_mbuf;
3021 }
3022 /* Only read 1024 bytes at a time */
3023 res = read(ast_consock, mbuf + mlen, 1024);
3024 if (res > 0) {
3025 if (!strncmp(mbuf, "Usage:", 6)) {
3026 /*
3027 * Abort on malformed tab completes
3028 * If help (tab complete) follows certain
3029 * special characters, the main Asterisk process
3030 * provides usage for the internal tab complete
3031 * helper command that the remote console processes
3032 * use.
3033 * If this happens, the AST_CLI_COMPLETE_EOF sentinel
3034 * value never gets sent. As a result, we'll just block
3035 * forever if we don't handle this case.
3036 * If we get command usage on a tab complete, then
3037 * we know this scenario just happened and we should
3038 * just silently ignore and do nothing.
3039 */
3040 break;
3041 }
3042 mlen += res;
3043 mbuf[mlen] = '\0';
3044 }
3045 }
3046 mbuf[mlen] = '\0';
3047
3048 matches = ast_el_strtoarr(mbuf);
3049 ast_free(mbuf);
3050 } else {
3051 matches = ast_cli_completion_vector((char *)lf->buffer, ptr);
3052 }
3053
3054 if (matches) {
3055 int i;
3056 int maxlen, match_len;
3057 const char *best_match = AST_VECTOR_GET(matches, 0);
3058
3059 if (!ast_strlen_zero(best_match)) {
3060 el_deletestr(editline, (int) len);
3061 el_insertstr(editline, best_match);
3062 retval = CC_REFRESH;
3063 }
3064
3065 if (AST_VECTOR_SIZE(matches) == 2) {
3066 /* Found an exact match */
3067 el_insertstr(editline, " ");
3068 retval = CC_REFRESH;
3069 } else {
3070 /* Must be more than one match */
3071 for (i = 1, maxlen = 0; i < AST_VECTOR_SIZE(matches); i++) {
3072 match_len = strlen(AST_VECTOR_GET(matches, i));
3073 if (match_len > maxlen) {
3074 maxlen = match_len;
3075 }
3076 }
3077
3078 fprintf(stdout, "\n");
3079 ast_cli_display_match_list(matches, maxlen);
3080 retval = CC_REDISPLAY;
3081 }
3083 AST_VECTOR_PTR_FREE(matches);
3084 }
3085
3086 *((char *) lf->cursor) = savechr;
3087
3088 return (char *)(long)retval;
3089}
3090
3091static int ast_el_initialize(void)
3092{
3093 HistEvent ev;
3094 char *editor, *editrc = getenv("EDITRC");
3095
3096 if (!(editor = getenv("AST_EDITMODE"))) {
3097 if (!(editor = getenv("AST_EDITOR"))) {
3098 editor = "emacs";
3099 }
3100 }
3101
3102 if (el != NULL)
3103 el_end(el);
3104 if (el_hist != NULL)
3105 history_end(el_hist);
3106
3107 el = el_init("asterisk", stdin, stdout, stderr);
3108 el_set(el, EL_PROMPT, cli_prompt);
3109
3110 el_set(el, EL_EDITMODE, 1);
3111 el_set(el, EL_EDITOR, editor);
3112 el_hist = history_init();
3113 if (!el || !el_hist)
3114 return -1;
3115
3116 /* setup history with 100 entries */
3117 history(el_hist, &ev, H_SETSIZE, 100);
3118
3119 el_set(el, EL_HIST, history, el_hist);
3120
3121 el_set(el, EL_ADDFN, "ed-complete", "Complete argument", cli_complete);
3122 /* Bind <tab> to command completion */
3123 el_set(el, EL_BIND, "^I", "ed-complete", NULL);
3124 /* Bind ? to command completion */
3125 el_set(el, EL_BIND, "?", "ed-complete", NULL);
3126 /* Bind ^D to redisplay */
3127 el_set(el, EL_BIND, "^D", "ed-redisplay", NULL);
3128 /* Bind Delete to delete char left */
3129 el_set(el, EL_BIND, "\\e[3~", "ed-delete-next-char", NULL);
3130 /* Bind Home and End to move to line start and end */
3131 el_set(el, EL_BIND, "\\e[1~", "ed-move-to-beg", NULL);
3132 el_set(el, EL_BIND, "\\e[4~", "ed-move-to-end", NULL);
3133 /* Bind C-left and C-right to move by word (not all terminals) */
3134 el_set(el, EL_BIND, "\\eOC", "vi-next-word", NULL);
3135 el_set(el, EL_BIND, "\\eOD", "vi-prev-word", NULL);
3136
3137 if (editrc) {
3138 el_source(el, editrc);
3139 }
3140
3141 return 0;
3142}
3143
3144#define MAX_HISTORY_COMMAND_LENGTH 256
3145
3146static int ast_el_add_history(const char *buf)
3147{
3148 HistEvent ev;
3149 char *stripped_buf;
3150
3151 if (el_hist == NULL || el == NULL) {
3153 }
3154 if (strlen(buf) > (MAX_HISTORY_COMMAND_LENGTH - 1)) {
3155 return 0;
3156 }
3157
3158 stripped_buf = ast_strip(ast_strdupa(buf));
3159
3160 /* HISTCONTROL=ignoredups */
3161 if (!history(el_hist, &ev, H_FIRST) && strcmp(ev.str, stripped_buf) == 0) {
3162 return 0;
3163 }
3164
3165 return history(el_hist, &ev, H_ENTER, stripped_buf);
3166}
3167
3168static int ast_el_write_history(const char *filename)
3169{
3170 HistEvent ev;
3171
3172 if (el_hist == NULL || el == NULL)
3174
3175 return (history(el_hist, &ev, H_SAVE, filename));
3176}
3177
3178static int ast_el_read_history(const char *filename)
3179{
3180 HistEvent ev;
3181
3182 if (el_hist == NULL || el == NULL) {
3184 }
3185
3186 if (access(filename, F_OK) == 0) {
3187 return history(el_hist, &ev, H_LOAD, filename);
3188 }
3189
3190 /* If the history file doesn't exist, failing to read it is unremarkable. */
3191 return 0;
3192}
3193
3194static void process_histfile(int (*readwrite)(const char *filename))
3195{
3196 struct passwd *pw = getpwuid(geteuid());
3197 int ret = 0;
3198 char *name = NULL;
3199
3200 if (!pw || ast_strlen_zero(pw->pw_dir)) {
3201 ast_log(LOG_ERROR, "Unable to determine home directory. History read/write disabled.\n");
3202 return;
3203 }
3204
3205 ret = ast_asprintf(&name, "%s/.asterisk_history", pw->pw_dir);
3206 if (ret <= 0) {
3207 ast_log(LOG_ERROR, "Unable to create history file name. History read/write disabled.\n");
3208 return;
3209 }
3210
3211 ret = readwrite(name);
3212 if (ret < 0) {
3213 ast_log(LOG_ERROR, "Unable to read or write history file '%s'\n", name);
3214 }
3215
3216 ast_free(name);
3217
3218 return;
3219}
3220
3222{
3224}
3225
3227{
3229}
3230
3231static void ast_remotecontrol(char *data)
3232{
3233 char buf[256] = "";
3234 int res;
3235 char *hostname;
3236 char *cpid;
3237 char *version;
3238 int pid;
3239 char *stringp = NULL;
3240
3241 char *ebuf;
3242 int num = 0;
3243
3244 ast_term_init();
3245 printf("%s", term_end());
3246 fflush(stdout);
3247
3248 memset(&sig_flags, 0, sizeof(sig_flags));
3249 signal(SIGINT, __remote_quit_handler);
3250 signal(SIGTERM, __remote_quit_handler);
3251 signal(SIGHUP, __remote_quit_handler);
3252
3253 if (read(ast_consock, buf, sizeof(buf) - 1) < 0) {
3254 ast_log(LOG_ERROR, "read() failed: %s\n", strerror(errno));
3255 return;
3256 }
3257 if (data) {
3258 char prefix[] = "cli quit after ";
3259 char *tmp = ast_alloca(strlen(data) + strlen(prefix) + 1);
3260 sprintf(tmp, "%s%s", prefix, data);
3261 if (write(ast_consock, tmp, strlen(tmp) + 1) < 0) {
3262 ast_log(LOG_ERROR, "write() failed: %s\n", strerror(errno));
3263 if (sig_flags.need_quit || sig_flags.need_quit_handler || sig_flags.need_el_end) {
3264 return;
3265 }
3266 }
3267 }
3268 stringp = buf;
3269 hostname = strsep(&stringp, "/");
3270 cpid = strsep(&stringp, "/");
3271 version = strsep(&stringp, "\n");
3272 if (!version)
3273 version = "<Version Unknown>";
3274 stringp = hostname;
3275 strsep(&stringp, ".");
3276 if (cpid)
3277 pid = atoi(cpid);
3278 else
3279 pid = -1;
3280 if (!data) {
3282 }
3283
3284 if (ast_opt_exec && data) { /* hack to print output then exit if asterisk -rx is used */
3285 int linefull = 1, prev_linefull = 1, prev_line_verbose = 0;
3286 struct pollfd fds;
3287 fds.fd = ast_consock;
3288 fds.events = POLLIN;
3289 fds.revents = 0;
3290
3291 while (ast_poll(&fds, 1, 60000) > 0) {
3292 char buffer[512] = "", *curline = buffer, *nextline;
3293 int not_written = 1;
3294
3295 if (sig_flags.need_quit || sig_flags.need_quit_handler || sig_flags.need_el_end) {
3296 break;
3297 }
3298
3299 if (read(ast_consock, buffer, sizeof(buffer) - 1) <= 0) {
3300 break;
3301 }
3302
3303 do {
3304 prev_linefull = linefull;
3305 if ((nextline = strchr(curline, '\n'))) {
3306 linefull = 1;
3307 nextline++;
3308 } else {
3309 linefull = 0;
3310 nextline = strchr(curline, '\0');
3311 }
3312
3313 /* Skip verbose lines */
3314 /* Prev line full? | Line is verbose | Last line verbose? | Print
3315 * TRUE | TRUE* | TRUE | FALSE
3316 * TRUE | TRUE* | FALSE | FALSE
3317 * TRUE | FALSE* | TRUE | TRUE
3318 * TRUE | FALSE* | FALSE | TRUE
3319 * FALSE | TRUE | TRUE* | FALSE
3320 * FALSE | TRUE | FALSE* | TRUE
3321 * FALSE | FALSE | TRUE* | FALSE
3322 * FALSE | FALSE | FALSE* | TRUE
3323 */
3324 if ((!prev_linefull && !prev_line_verbose) || (prev_linefull && *curline > 0)) {
3325 prev_line_verbose = 0;
3326 not_written = 0;
3327 if (write(STDOUT_FILENO, curline, nextline - curline) < 0) {
3328 ast_log(LOG_WARNING, "write() failed: %s\n", strerror(errno));
3329 }
3330 } else {
3331 prev_line_verbose = 1;
3332 }
3333 curline = nextline;
3334 } while (!ast_strlen_zero(curline));
3335
3336 /* No non-verbose output in 60 seconds. */
3337 if (not_written) {
3338 break;
3339 }
3340 }
3341 return;
3342 }
3343
3344 ast_verbose("Connected to Asterisk %s currently running on %s (pid = %d)\n", version, hostname, pid);
3346
3348 if (el_hist == NULL || el == NULL)
3351
3352 el_set(el, EL_GETCFN, ast_el_read_char);
3353
3354 for (;;) {
3355 ebuf = (char *)el_gets(el, &num);
3356
3357 if (sig_flags.need_quit || sig_flags.need_quit_handler || sig_flags.need_el_end) {
3358 break;
3359 }
3360
3361 if (!ebuf && write(1, "", 1) < 0)
3362 break;
3363
3364 if (!ast_strlen_zero(ebuf)) {
3365 if (ebuf[strlen(ebuf)-1] == '\n')
3366 ebuf[strlen(ebuf)-1] = '\0';
3367 if (!remoteconsolehandler(ebuf)) {
3368 res = write(ast_consock, ebuf, strlen(ebuf) + 1);
3369 if (res < 1) {
3370 ast_log(LOG_WARNING, "Unable to write: %s\n", strerror(errno));
3371 break;
3372 }
3373 }
3374 }
3375 }
3376 printf("\nDisconnected from Asterisk server\n");
3377}
3378
3379static int show_version(void)
3380{
3381 printf("Asterisk %s\n", ast_get_version());
3382 return 0;
3383}
3384
3385static int show_cli_help(void)
3386{
3387 printf("Asterisk %s, " COPYRIGHT_TAG "\n", ast_get_version());
3388 printf("Usage: asterisk [OPTIONS]\n");
3389 printf("Valid Options:\n");
3390 printf(" -V Display version number and exit\n");
3391 printf(" -C <configfile> Use an alternate configuration file\n");
3392 printf(" -G <group> Run as a group other than the caller\n");
3393 printf(" -U <user> Run as a user other than the caller\n");
3394 printf(" -c Provide console CLI\n");
3395 printf(" -d Increase debugging (multiple d's = more debugging)\n");
3396#if HAVE_WORKING_FORK
3397 printf(" -f Do not fork\n");
3398 printf(" -F Always fork\n");
3399#endif
3400 printf(" -g Dump core in case of a crash\n");
3401 printf(" -h This help screen\n");
3402 printf(" -i Initialize crypto keys at startup\n");
3403 printf(" -L <load> Limit the maximum load average before rejecting new calls\n");
3404 printf(" -M <value> Limit the maximum number of calls to the specified value\n");
3405 printf(" -m Mute debugging and console output on the console\n");
3406 printf(" -n Disable console colorization. Can be used only at startup.\n");
3407 printf(" -p Run as pseudo-realtime thread\n");
3408 printf(" -q Quiet mode (suppress output)\n");
3409 printf(" -r Connect to Asterisk on this machine\n");
3410 printf(" -R Same as -r, except attempt to reconnect if disconnected\n");
3411 printf(" -s <socket> Connect to Asterisk via socket <socket> (only valid with -r)\n");
3412 printf(" -t Record soundfiles in /var/tmp and move them where they\n");
3413 printf(" belong after they are done\n");
3414 printf(" -T Display the time in [Mmm dd hh:mm:ss] format for each line\n");
3415 printf(" of output to the CLI. Cannot be used with remote console mode.\n\n");
3416 printf(" -v Increase verbosity (multiple v's = more verbose)\n");
3417 printf(" -x <cmd> Execute command <cmd> (implies -r)\n");
3418 printf(" -X Enable use of #exec in asterisk.conf\n");
3419 printf(" -W Adjust terminal colors to compensate for a light background\n");
3420 printf("\n");
3421 return 0;
3422}
3423
3425{
3426 struct ast_config *cfg;
3427 struct ast_variable *v;
3428 struct ast_flags config_flags = { CONFIG_FLAG_NOCACHE | CONFIG_FLAG_NOREALTIME };
3429
3432
3433 cfg = ast_config_load2("pjproject.conf", "" /* core, can't reload */, config_flags);
3434 if (!cfg
3436 || cfg == CONFIG_STATUS_FILEINVALID) {
3437 /* We'll have to use defaults */
3438 return;
3439 }
3440
3441 for (v = ast_variable_browse(cfg, "startup"); v; v = v->next) {
3442 if (!strcasecmp(v->name, "log_level")) {
3443 if (sscanf(v->value, "%30d", &ast_option_pjproject_log_level) != 1) {
3445 } else if (ast_option_pjproject_log_level < 0) {
3449 }
3450 } else if (!strcasecmp(v->name, "cache_pools")) {
3452 }
3453 }
3454
3455 ast_config_destroy(cfg);
3456}
3457
3458static void *monitor_sig_flags(void *unused)
3459{
3460 for (;;) {
3461 struct pollfd p = { sig_alert_pipe[0], POLLIN, 0 };
3462
3463 ast_poll(&p, 1, -1);
3464 if (sig_flags.need_reload) {
3465 sig_flags.need_reload = 0;
3467 }
3468 if (sig_flags.need_quit) {
3469 sig_flags.need_quit = 0;
3470 if ((consolethread != AST_PTHREADT_NULL) && (consolethread != pthread_self())) {
3471 sig_flags.need_quit_handler = 1;
3472 pthread_kill(consolethread, SIGURG);
3473 } else {
3475 }
3476 }
3478 }
3479
3480 return NULL;
3481}
3482
3483static void *canary_thread(void *unused)
3484{
3485 struct stat canary_stat;
3486 struct timeval now;
3487
3488 /* Give the canary time to sing */
3489 sleep(120);
3490
3491 for (;;) {
3492 now = ast_tvnow();
3493 if (stat(canary_filename, &canary_stat) || now.tv_sec > canary_stat.st_mtime + 60) {
3495 "The canary is no more. He has ceased to be! "
3496 "He's expired and gone to meet his maker! "
3497 "He's a stiff! Bereft of life, he rests in peace. "
3498 "His metabolic processes are now history! He's off the twig! "
3499 "He's kicked the bucket. He's shuffled off his mortal coil, "
3500 "run down the curtain, and joined the bleeding choir invisible!! "
3501 "THIS is an EX-CANARY. (Reducing priority)\n");
3503 pthread_exit(NULL);
3504 }
3505
3506 /* Check the canary once a minute */
3507 sleep(60);
3508 }
3509}
3510
3511/* Used by libc's atexit(3) function */
3512static void canary_exit(void)
3513{
3514 if (canary_pid > 0) {
3515 int status;
3516 kill(canary_pid, SIGKILL);
3517 waitpid(canary_pid, &status, 0);
3518 }
3519}
3520
3521/* Execute CLI commands on startup. Run by main() thread. */
3522static void run_startup_commands(void)
3523{
3524 int fd;
3525 struct ast_config *cfg;
3526 struct ast_flags cfg_flags = { 0 };
3527 struct ast_variable *v;
3528
3529 if (!(cfg = ast_config_load2("cli.conf", "" /* core, can't reload */, cfg_flags)))
3530 return;
3532 return;
3533 }
3534
3535 fd = open("/dev/null", O_RDWR);
3536 if (fd < 0) {
3537 ast_config_destroy(cfg);
3538 return;
3539 }
3540
3541 for (v = ast_variable_browse(cfg, "startup_commands"); v; v = v->next) {
3542 if (ast_true(v->value))
3543 ast_cli_command(fd, v->name);
3544 }
3545
3546 close(fd);
3547 ast_config_destroy(cfg);
3548}
3549
3550static void env_init(void)
3551{
3552 setenv("AST_SYSTEMNAME", ast_config_AST_SYSTEM_NAME, 1);
3553 setenv("AST_BUILD_HOST", ast_build_hostname, 1);
3554 setenv("AST_BUILD_DATE", ast_build_date, 1);
3555 setenv("AST_BUILD_KERNEL", ast_build_kernel, 1);
3556 setenv("AST_BUILD_MACHINE", ast_build_machine, 1);
3557 setenv("AST_BUILD_OS", ast_build_os, 1);
3558 setenv("AST_BUILD_USER", ast_build_user, 1);
3559 setenv("AST_VERSION", ast_get_version(), 1);
3560}
3561
3562static void print_intro_message(const char *runuser, const char *rungroup)
3563{
3566 if (runuser) {
3567 ast_verbose("Running as user '%s'\n", runuser);
3568 }
3569 if (rungroup) {
3570 ast_verbose("Running under group '%s'\n", rungroup);
3571 }
3572 }
3573}
3574
3575static void main_atexit(void)
3576{
3578}
3579
3580int main(int argc, char *argv[])
3581{
3582 int c;
3583 int x;
3584 int isroot = 1, rundir_exists = 0;
3585 RAII_VAR(char *, runuser, NULL, ast_free);
3586 RAII_VAR(char *, rungroup, NULL, ast_free);
3587 RAII_VAR(char *, xarg, NULL, ast_free);
3588 struct rlimit l;
3589 static const char *getopt_settings = "BC:cde:FfG:ghIiL:M:mnpqRrs:TtU:VvWXx:";
3590
3591 /* Remember original args for restart */
3592 if (argc > ARRAY_LEN(_argv) - 1) {
3593 fprintf(stderr, "Truncating argument size to %d\n", (int)ARRAY_LEN(_argv) - 1);
3594 argc = ARRAY_LEN(_argv) - 1;
3595 }
3596 for (x = 0; x < argc; x++)
3597 _argv[x] = argv[x];
3598 _argv[x] = NULL;
3599
3600 if (geteuid() != 0)
3601 isroot = 0;
3602
3603 /* if the progname is rasterisk consider it a remote console */
3604 if (argv[0] && (strstr(argv[0], "rasterisk")) != NULL) {
3606 }
3607 ast_mainpid = getpid();
3608
3609 /* Process command-line options that affect asterisk.conf load. */
3610 while ((c = getopt(argc, argv, getopt_settings)) != -1) {
3611 switch (c) {
3612 case 'X':
3614 break;
3615 case 'C':
3616 set_asterisk_conf_path(optarg);
3617 break;
3618 case 'd':
3619 option_debug++;
3620 break;
3621 case 'h':
3622 show_cli_help();
3623 exit(0);
3624 case 'R':
3625 case 'r':
3626 case 'x':
3627 /* ast_opt_remote is checked during config load. This is only part of what
3628 * these options do, see the second loop for the rest of the actions. */
3630 break;
3631 case 'V':
3632 show_version();
3633 exit(0);
3634 case 'v':
3636 break;
3637 case '?':
3638 exit(1);
3639 }
3640 }
3641
3642 /* Initialize env so it is available if #exec is used in asterisk.conf. */
3643 env_init();
3644
3646
3647 /* Update env to include any systemname that was set. */
3648 env_init();
3649
3650 /*! \brief Check for options
3651 *
3652 * \todo Document these options
3653 */
3654 optind = 1;
3655 while ((c = getopt(argc, argv, getopt_settings)) != -1) {
3656 /*!\note Please keep the ordering here to alphabetical, capital letters
3657 * first. This will make it easier in the future to select unused
3658 * option flags for new features. */
3659 switch (c) {
3660 case 'B': /* Force black background */
3663 break;
3664 case 'X':
3665 /* The command-line -X option enables #exec for asterisk.conf only. */
3666 break;
3667 case 'C':
3668 /* already processed. */
3669 break;
3670 case 'c':
3672 break;
3673 case 'd':
3674 /* already processed. */
3675 break;
3676#if defined(HAVE_SYSINFO)
3677 case 'e':
3678 if ((sscanf(&optarg[1], "%30ld", &option_minmemfree) != 1) || (option_minmemfree < 0)) {
3680 }
3681 break;
3682#endif
3683#if HAVE_WORKING_FORK
3684 case 'F':
3686 break;
3687 case 'f':
3689 break;
3690#endif
3691 case 'G':
3692 rungroup = ast_strdup(optarg);
3693 break;
3694 case 'g':
3696 break;
3697 case 'h':
3698 /* already processed. */
3699 break;
3700 case 'I':
3701 fprintf(stderr,
3702 "NOTICE: The -I option is no longer needed.\n"
3703 " It will always be enabled if you have a timing module loaded.\n");
3704 break;
3705 case 'i':
3707 break;
3708 case 'L':
3709 if ((sscanf(optarg, "%30lf", &ast_option_maxload) != 1) || (ast_option_maxload < 0.0)) {
3710 ast_option_maxload = 0.0;
3711 }
3712 break;
3713 case 'M':
3714 if ((sscanf(optarg, "%30d", &ast_option_maxcalls) != 1) || (ast_option_maxcalls < 0)) {
3716 }
3717 break;
3718 case 'm':
3720 break;
3721 case 'n':
3723 break;
3724 case 'p':
3726 break;
3727 case 'q':
3729 break;
3730 case 'R':
3732 break;
3733 case 'r':
3735 break;
3736 case 's':
3737 if (ast_opt_remote) {
3738 set_socket_path(optarg);
3739 }
3740 break;
3741 case 'T':
3743 break;
3744 case 't':
3746 break;
3747 case 'U':
3748 runuser = ast_strdup(optarg);
3749 break;
3750 case 'V':
3751 case 'v':
3752 /* already processed. */
3753 break;
3754 case 'W': /* White background */
3757 break;
3758 case 'x':
3759 /* -r is implied by -x so set the flags -r sets as well. */
3761
3763 xarg = ast_strdup(optarg);
3764 break;
3765 case '?':
3766 /* already processed. */
3767 break;
3768 }
3769 }
3770
3771 if (ast_opt_remote) {
3772 int didwarn = 0;
3773 optind = 1;
3774
3775 /* Not all options can be used with remote console. Warn if they're used. */
3776 while ((c = getopt(argc, argv, getopt_settings)) != -1) {
3777 switch (c) {
3778 /* okay to run with remote console */
3779 case 'B': /* force black background */
3780 case 'C': /* set config path */
3781 case 'd': /* debug */
3782 case 'h': /* help */
3783 case 'I': /* obsolete timing option: warning already thrown if used */
3784 case 'L': /* max load */
3785 case 'M': /* max calls */
3786 case 'm': /* mute */
3787 /*! \note The q option is never used anywhere, only defined */
3788 case 'q': /* quiet */
3789 case 'R': /* reconnect */
3790 case 'r': /* remote */
3791 /*! \note Can ONLY be used with remote console */
3792 case 's': /* set socket path */
3793 case 'T': /* timestamp */
3794 case 'V': /* version */
3795 case 'v': /* verbose */
3796 case 'W': /* white background */
3797 case 'x': /* remote execute */
3798 case '?': /* ? */
3799 break;
3800 /* can only be run when Asterisk is starting */
3801 case 'X': /* enables #exec for asterisk.conf only. */
3802 case 'c': /* foreground console */
3803 case 'e': /* minimum memory free */
3804 case 'F': /* always fork */
3805 case 'f': /* no fork */
3806 case 'G': /* run group */
3807 case 'g': /* dump core */
3808 case 'i': /* init keys */
3809 case 'n': /* no color */
3810 case 'p': /* high priority */
3811 case 't': /* cache record files */
3812 case 'U': /* run user */
3813 fprintf(stderr, "'%c' option is not compatible with remote console mode and has no effect.\n", c);
3814 didwarn = 1;
3815 }
3816 }
3817 if (didwarn) {
3818 fprintf(stderr, "\n"); /* if any warnings print out, make them stand out */
3819 }
3820 }
3821
3822 /* For remote connections, change the name of the remote connection.
3823 * We do this for the benefit of init scripts (which need to know if/when
3824 * the main asterisk process has died yet). */
3825 if (ast_opt_remote) {
3826 strcpy(argv[0], "rasterisk");
3827 for (x = 1; x < argc; x++) {
3828 argv[x] = argv[0] + 10;
3829 }
3830 }
3831
3833 fprintf(stderr, "The 'languageprefix' option in asterisk.conf is deprecated; in a future release it will be removed, and your sound files will need to be organized in the 'new style' language layout.\n");
3834 }
3835
3837 fprintf(stderr, "'alwaysfork' is not compatible with console or remote console mode; ignored\n");
3839 }
3840
3841 if (ast_opt_dump_core) {
3842 memset(&l, 0, sizeof(l));
3843 l.rlim_cur = RLIM_INFINITY;
3844 l.rlim_max = RLIM_INFINITY;
3845 if (setrlimit(RLIMIT_CORE, &l)) {
3846 fprintf(stderr, "Unable to disable core size resource limit: %s\n", strerror(errno));
3847 }
3848 }
3849
3850 if (getrlimit(RLIMIT_NOFILE, &l)) {
3851 fprintf(stderr, "Unable to check file descriptor limit: %s\n", strerror(errno));
3852 }
3853
3854#if !defined(CONFIGURE_RAN_AS_ROOT)
3855 /* Check if select(2) will run with more file descriptors */
3856 do {
3857 int fd, fd2;
3858 ast_fdset readers;
3859 struct timeval tv = { 0, };
3860
3861 if (l.rlim_cur <= FD_SETSIZE) {
3862 /* The limit of select()able FDs is irrelevant, because we'll never
3863 * open one that high. */
3864 break;
3865 }
3866
3867 if (!(fd = open("/dev/null", O_RDONLY))) {
3868 fprintf(stderr, "Cannot open a file descriptor at boot? %s\n", strerror(errno));
3869 break; /* XXX Should we exit() here? XXX */
3870 }
3871
3872 fd2 = ((l.rlim_cur > sizeof(readers) * 8) ? sizeof(readers) * 8 : l.rlim_cur) - 1;
3873 if (dup2(fd, fd2) < 0) {
3874 fprintf(stderr, "Cannot open maximum file descriptor %d at boot? %s\n", fd2, strerror(errno));
3875 close(fd);
3876 break;
3877 }
3878
3879 FD_ZERO(&readers);
3880 FD_SET(fd2, &readers);
3881 if (ast_select(fd2 + 1, &readers, NULL, NULL, &tv) < 0) {
3882 fprintf(stderr, "Maximum select()able file descriptor is %d\n", FD_SETSIZE);
3883 }
3884 ast_FD_SETSIZE = l.rlim_cur > ast_FDMAX ? ast_FDMAX : l.rlim_cur;
3885 close(fd);
3886 close(fd2);
3887 } while (0);
3888#elif defined(HAVE_VARIABLE_FDSET)
3889 ast_FD_SETSIZE = l.rlim_cur > ast_FDMAX ? ast_FDMAX : l.rlim_cur;
3890#endif /* !defined(CONFIGURE_RAN_AS_ROOT) */
3891
3892 if ((!rungroup) && !ast_strlen_zero(ast_config_AST_RUN_GROUP))
3894 if ((!runuser) && !ast_strlen_zero(ast_config_AST_RUN_USER))
3896
3897 /* Must install this signal handler up here to ensure that if the canary
3898 * fails to execute that it doesn't kill the Asterisk process.
3899 */
3900 sigaction(SIGCHLD, &child_handler, NULL);
3901
3902 /* It's common on some platforms to clear /var/run at boot. Create the
3903 * socket file directory before we drop privileges. */
3904 if (mkdir(ast_config_AST_RUN_DIR, 0755)) {
3905 if (errno == EEXIST) {
3906 rundir_exists = 1;
3907 } else {
3908 fprintf(stderr, "Unable to create socket file directory. Remote consoles will not be able to connect! (%s)\n", strerror(x));
3909 }
3910 }
3911
3912#ifndef __CYGWIN__
3913
3914 if (isroot) {
3916 }
3917
3918 if (isroot && rungroup) {
3919 struct group *gr;
3920 gr = getgrnam(rungroup);
3921 if (!gr) {
3922 fprintf(stderr, "No such group '%s'!\n", rungroup);
3923 exit(1);
3924 }
3925 if (!rundir_exists && chown(ast_config_AST_RUN_DIR, -1, gr->gr_gid)) {
3926 fprintf(stderr, "Unable to chgrp run directory to %d (%s)\n", (int) gr->gr_gid, rungroup);
3927 }
3928 if (setgid(gr->gr_gid)) {
3929 fprintf(stderr, "Unable to setgid to %d (%s)\n", (int)gr->gr_gid, rungroup);
3930 exit(1);
3931 }
3932 if (setgroups(0, NULL)) {
3933 fprintf(stderr, "Unable to drop unneeded groups\n");
3934 exit(1);
3935 }
3936 }
3937
3938 if (runuser && !ast_test_flag(&ast_options, AST_OPT_FLAG_REMOTE)) {
3939#ifdef HAVE_CAP
3940 int has_cap = 1;
3941#endif /* HAVE_CAP */
3942 struct passwd *pw;
3943 pw = getpwnam(runuser);
3944 if (!pw) {
3945 fprintf(stderr, "No such user '%s'!\n", runuser);
3946 exit(1);
3947 }
3948 if (chown(ast_config_AST_RUN_DIR, pw->pw_uid, -1)) {
3949 fprintf(stderr, "Unable to chown run directory to %d (%s)\n", (int) pw->pw_uid, runuser);
3950 }
3951#ifdef HAVE_CAP
3952 if (prctl(PR_SET_KEEPCAPS, 1, 0, 0, 0)) {
3953 ast_log(LOG_WARNING, "Unable to keep capabilities.\n");
3954 has_cap = 0;
3955 }
3956#endif /* HAVE_CAP */
3957 if (!isroot && pw->pw_uid != geteuid()) {
3958 fprintf(stderr, "Asterisk started as nonroot, but runuser '%s' requested.\n", runuser);
3959 exit(1);
3960 }
3961 if (!rungroup) {
3962 if (setgid(pw->pw_gid)) {
3963 fprintf(stderr, "Unable to setgid to %d!\n", (int)pw->pw_gid);
3964 exit(1);
3965 }
3966 if (isroot && initgroups(pw->pw_name, pw->pw_gid)) {
3967 fprintf(stderr, "Unable to init groups for '%s'\n", runuser);
3968 exit(1);
3969 }
3970 }
3971 if (setuid(pw->pw_uid)) {
3972 fprintf(stderr, "Unable to setuid to %d (%s)\n", (int)pw->pw_uid, runuser);
3973 exit(1);
3974 }
3975#ifdef HAVE_CAP
3976 if (has_cap) {
3977 cap_t cap;
3978
3979 cap = cap_from_text("cap_net_admin=eip");
3980
3981 if (cap_set_proc(cap)) {
3982 fprintf(stderr, "Unable to install capabilities.\n");
3983 }
3984 if (cap_free(cap)) {
3985 fprintf(stderr, "Unable to drop capabilities.\n");
3986 }
3987 }
3988#endif /* HAVE_CAP */
3989 }
3990
3991#endif /* __CYGWIN__ */
3992
3993#ifdef linux
3994 if (geteuid() && ast_opt_dump_core) {
3995 if (prctl(PR_SET_DUMPABLE, 1, 0, 0, 0) < 0) {
3996 fprintf(stderr, "Unable to set the process for core dumps after changing to a non-root user. %s\n", strerror(errno));
3997 }
3998 }
3999#endif
4000
4001 {
4002#if defined(HAVE_EACCESS) || defined(HAVE_EUIDACCESS)
4003 char dir[PATH_MAX];
4004 if (!getcwd(dir, sizeof(dir)) || eaccess(dir, R_OK | X_OK | F_OK)) {
4005 fprintf(stderr, "Unable to access the running directory (%s). Changing to '/' for compatibility.\n", strerror(errno));
4006 /* If we cannot access the CWD, then we couldn't dump core anyway,
4007 * so chdir("/") won't break anything. */
4008 if (chdir("/")) {
4009 /* chdir(/) should never fail, so this ends up being a no-op */
4010 fprintf(stderr, "chdir(\"/\") failed?!! %s\n", strerror(errno));
4011 }
4012 } else
4013#endif /* defined(HAVE_EACCESS) || defined(HAVE_EUIDACCESS) */
4015 /* Backgrounding, but no cores, so chdir won't break anything. */
4016 if (chdir("/")) {
4017 fprintf(stderr, "Unable to chdir(\"/\") ?!! %s\n", strerror(errno));
4018 }
4019 }
4020 }
4021
4022 /* Initial value of the maximum active system verbosity level. */
4024
4025 if (ast_sd_get_fd_un(SOCK_STREAM, ast_config_AST_SOCKET) > 0) {
4026 ast_socket_is_sd = 1;
4027 }
4028
4029 /* DO NOT perform check for existing daemon if systemd has CLI socket activation */
4030 if (!ast_socket_is_sd && ast_tryconnect()) {
4031 /* One is already running */
4032 if (ast_opt_remote) {
4034 if (ast_opt_exec) {
4035 ast_remotecontrol(xarg);
4037 exit(0);
4038 }
4039 ast_term_init();
4040 printf("%s", term_end());
4041 fflush(stdout);
4042
4043 print_intro_message(runuser, rungroup);
4044 printf("%s", term_quit());
4047 exit(0);
4048 } else {
4049 fprintf(stderr, "Asterisk already running on %s. Use 'asterisk -r' to connect.\n", ast_config_AST_SOCKET);
4050 printf("%s", term_quit());
4051 exit(1);
4052 }
4053 } else if (ast_opt_remote || ast_opt_exec) {
4054 fprintf(stderr, "Unable to connect to remote asterisk (does %s exist?)\n", ast_config_AST_SOCKET);
4055 printf("%s", term_quit());
4056 exit(1);
4057 }
4058
4059#ifdef HAVE_CAP
4060 child_cap = cap_from_text("cap_net_admin-eip");
4061#endif
4062 /* Not a remote console? Start the daemon. */
4063 asterisk_daemon(isroot, runuser, rungroup);
4064#ifdef HAS_CAP
4065 cap_free(child_cap);
4066#endif
4067 return 0;
4068}
4069
4070static inline void check_init(int init_result, const char *name)
4071{
4072 if (init_result) {
4074 ast_log(LOG_ERROR, "%s initialization failed. ASTERISK EXITING!\n%s", name, term_quit());
4075 } else {
4076 fprintf(stderr, "%s initialization failed. ASTERISK EXITING!\n%s", name, term_quit());
4077 }
4078 ast_run_atexits(0);
4079 exit(init_result == -2 ? 2 : 1);
4080 }
4081}
4082
4083static void asterisk_daemon(int isroot, const char *runuser, const char *rungroup)
4084{
4085 FILE *f;
4086 sigset_t sigs;
4087 int num;
4088 char *buf;
4089 char pbx_uuid[AST_UUID_STR_LEN];
4090
4091 /* Set time as soon as possible */
4093
4094 /* This needs to remain as high up in the initial start up as possible.
4095 * daemon causes a fork to occur, which has all sorts of unintended
4096 * consequences for things that interact with threads. This call *must*
4097 * occur before anything in Asterisk spawns or manipulates thread related
4098 * primitives. */
4099#if HAVE_WORKING_FORK
4101#ifndef HAVE_SBIN_LAUNCHD
4102 if (daemon(1, 0) < 0) {
4103 fprintf(stderr, "daemon() failed: %s\n", strerror(errno));
4104 } else {
4105 ast_mainpid = getpid();
4106 }
4107#else
4108 fprintf(stderr, "Mac OS X detected. Use 'launchctl load /Library/LaunchDaemon/org.asterisk.asterisk.plist'.\n");
4109#endif
4110 }
4111#endif
4112
4113 /* At this point everything has been forked successfully,
4114 * we have determined that we aren't attempting to connect to
4115 * an Asterisk instance, and that there isn't one already running. */
4117
4119
4120 /* Check whether high prio was successfully set by us or some
4121 * other incantation. */
4122 if (has_priority()) {
4124 } else {
4126 }
4127
4128 /* Spawning of astcanary must happen AFTER the call to daemon(3) */
4130 snprintf(canary_filename, sizeof(canary_filename), "%s/alt.asterisk.canary.tweet.tweet.tweet", ast_config_AST_RUN_DIR);
4131
4132 /* Don't let the canary child kill Asterisk, if it dies immediately */
4133 sigaction(SIGPIPE, &ignore_sig_handler, NULL);
4134
4135 canary_pid = fork();
4136 if (canary_pid == 0) {
4137 char canary_binary[PATH_MAX], ppid[12];
4138
4139 /* Reset signal handler */
4140 signal(SIGCHLD, SIG_DFL);
4141 signal(SIGPIPE, SIG_DFL);
4142
4145 snprintf(ppid, sizeof(ppid), "%d", (int) ast_mainpid);
4146
4147 /* Use the astcanary binary that we installed */
4148 snprintf(canary_binary, sizeof(canary_binary), "%s/astcanary", ast_config_AST_SBIN_DIR);
4149 execl(canary_binary, "astcanary", canary_filename, ppid, (char *)NULL);
4150
4151 /* Should never happen */
4152 _exit(1);
4153 } else if (canary_pid > 0) {
4154 pthread_t dont_care;
4156 }
4157
4158 /* Kill the canary when we exit */
4160 }
4161
4162 /* Blindly write the PID file. */
4163 unlink(ast_config_AST_PID);
4164 f = fopen(ast_config_AST_PID, "w");
4165 if (f) {
4166 fprintf(f, "%ld\n", (long)ast_mainpid);
4167 fclose(f);
4168 } else {
4169 fprintf(stderr, "Unable to open pid file '%s': %s\n", ast_config_AST_PID, strerror(errno));
4170 }
4171
4172 /* Initialize the terminal. Since all processes have been forked,
4173 * we can now start using the standard log messages.
4174 */
4175 ast_term_init();
4176 printf("%s", term_end());
4177 fflush(stdout);
4178
4179 print_intro_message(runuser, rungroup);
4180
4182
4183 check_init(astobj2_init(), "AO2");
4184 check_init(ast_named_locks_init(), "Named Locks");
4185
4186 if (ast_opt_console) {
4187 if (el_hist == NULL || el == NULL)
4190 }
4191
4192#ifdef AST_XML_DOCS
4193 /* Load XML documentation. */
4195#endif
4196
4197 check_init(astdb_init(), "ASTdb");
4198
4199 ast_uuid_init();
4200
4201 if (ast_pbx_uuid_get(pbx_uuid, sizeof(pbx_uuid))) {
4202 ast_uuid_generate_str(pbx_uuid, sizeof(pbx_uuid));
4203 ast_db_put("pbx", "UUID", pbx_uuid);
4204 }
4205 ast_verb(0, "PBX UUID: %s\n", pbx_uuid);
4206
4207 check_init(ast_json_init(), "libjansson");
4208 ast_ulaw_init();
4209 ast_alaw_init();
4210 ast_utf8_init();
4211 tdd_init();
4212 callerid_init();
4214
4215 check_init(ast_utils_init(), "Utilities");
4216 check_init(ast_tps_init(), "Task Processor Core");
4217 check_init(ast_fd_init(), "File Descriptor Debugging");
4218 check_init(ast_pbx_init(), "ast_pbx_init");
4219 check_init(aco_init(), "Configuration Option Framework");
4220 check_init(stasis_init(), "Stasis");
4221#ifdef TEST_FRAMEWORK
4222 check_init(ast_test_init(), "Test Framework");
4223#endif
4224 check_init(ast_translate_init(), "Translator Core");
4225
4227
4228 check_init(ast_sorcery_init(), "Sorcery");
4229 check_init(ast_codec_init(), "Codecs");
4230 check_init(ast_format_init(), "Formats");
4231 check_init(ast_format_cache_init(), "Format Cache");
4232 check_init(ast_codec_builtin_init(), "Built-in Codecs");
4233 check_init(ast_bucket_init(), "Bucket API");
4234 check_init(ast_stasis_system_init(), "Stasis system-level information");
4235 check_init(ast_endpoint_stasis_init(), "Stasis Endpoint");
4236
4238 /* GCC 4.9 gives a bogus "right-hand operand of comma expression has
4239 * no effect" warning */
4240 (void) sigemptyset(&sigs);
4241 (void) sigaddset(&sigs, SIGHUP);
4242 (void) sigaddset(&sigs, SIGTERM);
4243 (void) sigaddset(&sigs, SIGINT);
4244 (void) sigaddset(&sigs, SIGPIPE);
4245 (void) sigaddset(&sigs, SIGWINCH);
4246 pthread_sigmask(SIG_BLOCK, &sigs, NULL);
4247 sigaction(SIGURG, &urg_handler, NULL);
4248 signal(SIGINT, __quit_handler);
4249 signal(SIGTERM, __quit_handler);
4250 sigaction(SIGHUP, &hup_handler, NULL);
4251 sigaction(SIGPIPE, &ignore_sig_handler, NULL);
4252
4253 /* ensure that the random number generators are seeded with a different value every time
4254 Asterisk is started
4255 */
4256 srand((unsigned int) getpid() + (unsigned int) time(NULL));
4257 initstate((unsigned int) getpid() * 65536 + (unsigned int) time(NULL), randompool, sizeof(randompool));
4258
4260
4261 check_init(init_logger(), "Logger");
4262 check_init(ast_rtp_engine_init(), "RTP Engine");
4263
4265
4266 check_init(ast_timing_init(), "Timing");
4267 check_init(ast_ssl_init(), "SSL");
4269 check_init(ast_pj_init(), "Embedded PJProject");
4270 check_init(app_init(), "App Core");
4271 check_init(mwi_init(), "MWI Core");
4272 check_init(devstate_init(), "Device State Core");
4273 check_init(ast_msg_init(), "Messaging API");
4274 check_init(ast_channels_init(), "Channel");
4275 check_init(ast_endpoint_init(), "Endpoints");
4276 check_init(ast_pickup_init(), "Call Pickup");
4277 check_init(ast_bridging_init(), "Bridging");
4278 check_init(ast_parking_stasis_init(), "Parking Core");
4279 check_init(ast_device_state_engine_init(), "Device State Engine");
4280 check_init(ast_presence_state_engine_init(), "Presence State Engine");
4281 check_init(dns_core_init(), "DNS Resolver Core");
4282 check_init(ast_dns_system_resolver_init(), "Default DNS resolver");
4283 check_init(ast_security_stasis_init(), "Security Stasis Topic and Events");
4284 check_init(ast_image_init(), "Image");
4285 check_init(ast_file_init(), "Generic File Format Support");
4286 check_init(load_pbx(), "load_pbx");
4287 check_init(load_pbx_builtins(), "Builtin PBX Applications");
4288 check_init(load_pbx_functions_cli(), "PBX Functions Support");
4289 check_init(load_pbx_variables(), "PBX Variables Support");
4290 check_init(load_pbx_switch(), "PBX Switch Support");
4291 check_init(load_pbx_app(), "PBX Application Support");
4292 check_init(load_pbx_hangup_handler(), "PBX Hangup Handler Support");
4293 check_init(ast_local_init(), "Local Proxy Channel Driver");
4294 check_init(ast_refer_init(), "Refer API");
4295
4296 /* We should avoid most config loads before this point as they can't use realtime. */
4297 check_init(load_modules(), "Module");
4298
4299 /*
4300 * This has to load after the dynamic modules load, as items in the media
4301 * cache can't be constructed from items in the AstDB without their
4302 * bucket backends.
4303 */
4304 check_init(ast_media_cache_init(), "Media Cache");
4305
4306 /* loads the cli_permissions.conf file needed to implement cli restrictions. */
4308 ast_cli_channels_init(); /* Not always safe to access CLI commands until startup is complete. */
4309
4310 ast_stun_init();
4311
4313
4314 if (ast_opt_no_fork) {
4315 consolethread = pthread_self();
4316 }
4317
4319
4321
4324
4325 pthread_sigmask(SIG_UNBLOCK, &sigs, NULL);
4326
4328
4332
4334 ast_sd_notify("READY=1");
4335
4336 ast_verb(0, COLORIZE_FMT "\n", COLORIZE(COLOR_BRGREEN, 0, "Asterisk Ready."));
4337
4339
4340 if (ast_opt_console) {
4341 /* Console stuff now... */
4342 /* Register our quit function */
4343 char title[256];
4344 char hostname[MAXHOSTNAMELEN] = "";
4345
4346 if (gethostname(hostname, sizeof(hostname) - 1)) {
4347 ast_copy_string(hostname, "<Unknown>", sizeof(hostname));
4348 }
4349
4351
4352 set_icon("Asterisk");
4353 snprintf(title, sizeof(title), "Asterisk Console on '%s' (pid %ld)", hostname, (long)ast_mainpid);
4354 set_title(title);
4355
4356 el_set(el, EL_GETCFN, ast_el_read_char);
4357
4358 for (;;) {
4359 if (sig_flags.need_el_end) {
4360 el_end(el);
4361
4362 return;
4363 }
4364
4365 if (sig_flags.need_quit || sig_flags.need_quit_handler) {
4367 break;
4368 }
4369 buf = (char *) el_gets(el, &num);
4370
4371 if (!buf && write(1, "", 1) < 0)
4372 return; /* quit */
4373
4374 if (buf) {
4375 if (buf[strlen(buf)-1] == '\n')
4376 buf[strlen(buf)-1] = '\0';
4377
4379 }
4380 }
4381 }
4382
4383 /* Stall until a quit signal is given */
4385}
Prototypes for public functions only of internal interest,.
int load_pbx_variables(void)
void threadstorage_init(void)
Definition: threadstorage.c:35
void ast_process_pending_reloads(void)
Process reload requests received during startup.
Definition: loader.c:1566
int modules_shutdown(void)
Definition: loader.c:1172
int ast_bridging_init(void)
Initialize the bridging system.
Definition: bridge.c:5543
void dnsmgr_start_refresh(void)
Definition: dnsmgr.c:302
int ast_timing_init(void)
Definition: timing.c:289
int ast_device_state_engine_init(void)
Initialize the device state engine in separate thread.
Definition: devicestate.c:618
int ast_term_init(void)
Definition: term.c:165
int load_modules(void)
Definition: loader.c:2508
void ast_cli_channels_init(void)
Definition: main/cli.c:2245
void ast_msg_shutdown(void)
void logger_queue_start(void)
Start the ast_queue_log() logger.
Definition: logger.c:2186
int aco_init(void)
void load_asterisk_conf(void)
Definition: options.c:210
int ast_test_init(void)
Definition: test.c:1482
void close_logger(void)
Definition: logger.c:2245
void ast_stun_init(void)
Initialize the STUN system in Asterisk.
Definition: stun.c:576
void set_asterisk_conf_path(const char *path)
Definition: options.c:200
int astdb_init(void)
Definition: main/db.c:1228
int ast_pj_init(void)
Definition: libasteriskpj.c:45
int load_pbx_functions_cli(void)
int ast_tps_init(void)
void load_astmm_phase_2(void)
Initialize malloc debug phase 2.
Definition: astmm.c:1529
int ast_msg_init(void)
int load_pbx_hangup_handler(void)
int ast_local_init(void)
Initialize the local proxy channel.
Definition: core_local.c:1139
int load_pbx_builtins(void)
int load_pbx_switch(void)
Definition: pbx_switch.c:125
int ast_rtp_engine_init(void)
initializes the rtp engine arrays
Definition: rtp_engine.c:3779
int ast_xmldoc_load_documentation(void)
Load XML documentation. Provided by xmldoc.c.
Definition: xmldoc.c:3047
int ast_named_locks_init(void)
Definition: named_locks.c:52
int ast_channels_init(void)
Definition: channel.c:8007
void clean_time_zones(void)
Definition: localtime.c:1590
void load_astmm_phase_1(void)
Initialize malloc debug phase 1.
Definition: astmm.c:1525
void ast_builtins_init(void)
initialize the _full_cmd string in * each of the builtins.
Definition: main/cli.c:2238
void ast_autoservice_init(void)
Definition: autoservice.c:380
int init_logger(void)
Definition: logger.c:2202
int ast_endpoint_init(void)
Endpoint support initialization.
int dns_core_init(void)
Definition: dns_core.c:614
int load_pbx(void)
Definition: pbx.c:8421
int astobj2_init(void)
Definition: astobj2.c:1169
int load_pbx_app(void)
Definition: pbx_app.c:538
int ast_dns_system_resolver_init(void)
Initializes the resolver.
int ast_ssl_init(void)
int ast_cli_perms_init(int reload)
Definition: main/cli.c:2105
void set_socket_path(const char *path)
Definition: options.c:205
int ast_file_init(void)
Definition: file.c:2051
int ast_refer_init(void)
Definition: refer.c:529
int ast_parking_stasis_init(void)
initializes the rtp engine arrays
Definition: parking.c:53
Access Control of various sorts.
A-Law to Signed linear conversion.
void ast_alaw_init(void)
To init the alaw to slinear conversion stuff, this needs to be run.
Definition: alaw.c:152
void ast_alertpipe_close(int alert_pipe[2])
Close an alert pipe.
Definition: alertpipe.c:79
ssize_t ast_alertpipe_write(int alert_pipe[2])
Write an event to an alert pipe.
Definition: alertpipe.c:120
int ast_alertpipe_init(int alert_pipe[2])
Initialize an alert pipe.
Definition: alertpipe.c:38
ast_alert_status_t ast_alertpipe_read(int alert_pipe[2])
Read an event from an alert pipe.
Definition: alertpipe.c:102
Generic Advice of Charge encode and decode routines.
int ast_aoc_cli_init(void)
enable aoc cli options
Definition: aoc.c:2020
jack_status_t status
Definition: app_jack.c:146
char * text
Definition: app_queue.c:1639
enum queue_result id
Definition: app_queue.c:1638
if(!yyg->yy_init)
Definition: ast_expr2f.c:854
Asterisk version information.
const char * ast_get_build_opts(void)
const char * ast_get_version(void)
Retrieve the Asterisk version string.
const char * ast_get_build_opts_all(void)
Persistent data storage (akin to *doze registry)
int ast_db_put(const char *family, const char *key, const char *value)
Store value addressed by family/key.
Definition: main/db.c:342
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
static int ast_el_add_history(const char *)
Definition: asterisk.c:3146
static char * remotehostname
Definition: asterisk.c:341
static char * handle_stop_gracefully(struct ast_cli_entry *e, int cmd, struct ast_cli_args *a)
Definition: asterisk.c:2382
static void __ast_unregister_atexit(void(*func)(void))
Definition: asterisk.c:1018
static char * cli_complete(EditLine *editline, int ch)
Definition: asterisk.c:2965
int64_t ast_mark(int i, int startstop)
Definition: asterisk.c:874
int main(int argc, char *argv[])
Definition: asterisk.c:3580
static int ast_socket_is_sd
Definition: asterisk.c:313
int ast_shutdown_final(void)
Definition: asterisk.c:1868
static void canary_exit(void)
Definition: asterisk.c:3512
static shutdown_nice_t shuttingdown
Definition: asterisk.c:378
static void check_init(int init_result, const char *name)
Definition: asterisk.c:4070
static void __remote_quit_handler(int num)
Definition: asterisk.c:2149
static void _urg_handler(int num)
Urgent handler.
Definition: asterisk.c:1708
static char * show_license(struct ast_cli_entry *e, int cmd, struct ast_cli_args *a)
Definition: asterisk.c:2587
#define CHAR_T_LIBEDIT
Definition: asterisk.c:2670
static char * handle_show_threads(struct ast_cli_entry *e, int cmd, struct ast_cli_args *a)
Definition: asterisk.c:604
static void ast_run_atexits(int run_cleanups)
Definition: asterisk.c:1004
static int console_state_init(void *ptr)
Definition: asterisk.c:2204
static struct profile_data * prof_data
Definition: asterisk.c:793
static char * handle_stop_when_convenient(struct ast_cli_entry *e, int cmd, struct ast_cli_args *a)
Definition: asterisk.c:2403
static int remoteconsolehandler(const char *s)
Definition: asterisk.c:2313
static struct ast_str * prompt
Definition: asterisk.c:2776
unsigned int need_reload
Definition: asterisk.c:398
static void publish_fully_booted(void)
Definition: asterisk.c:978
static int show_version(void)
Definition: asterisk.c:3379
static void main_atexit(void)
Definition: asterisk.c:3575
static int safe_exec_wait(pid_t pid)
wait for spawned application to complete and unreplace sigchld
Definition: asterisk.c:1193
int ast_add_profile(const char *name, uint64_t scale)
allocates a counter with a given name and scale.
Definition: asterisk.c:799
static void ast_cli_display_match_list(struct ast_vector_string *matches, int max)
Definition: asterisk.c:2938
static void _hup_handler(int num)
Definition: asterisk.c:1717
static char * handle_version(struct ast_cli_entry *e, int cmd, struct ast_cli_args *a)
Definition: asterisk.c:2341
static pthread_t lthread
Definition: asterisk.c:1363
static unsigned int safe_system_level
Keep track of how many threads are currently trying to wait*() on a child process.
Definition: asterisk.c:1098
static void ast_network_puts_mutable(const char *string, int level, int sublevel)
log the string to all attached network console clients
Definition: asterisk.c:1294
static char randompool[256]
Definition: asterisk.c:390
static char * handle_show_sysinfo(struct ast_cli_entry *e, int cmd, struct ast_cli_args *a)
Give an overview of system statistics.
Definition: asterisk.c:670
#define WELCOME_MESSAGE
Welcome message when starting a CLI interface.
Definition: asterisk.c:303
int ast_safe_execvp(int dualfork, const char *file, char *const argv[])
Safely spawn an external program while closing file descriptors.
Definition: asterisk.c:1219
int ast_register_cleanup(void(*func)(void))
Register a function to be executed before Asterisk gracefully exits.
Definition: asterisk.c:1056
static void set_header(char *outbuf, int maxout, char level)
Definition: asterisk.c:2154
static int ast_el_read_char(EditLine *editline, CHAR_T_LIBEDIT *cp)
Definition: asterisk.c:2677
static char * handle_stop_now(struct ast_cli_entry *e, int cmd, struct ast_cli_args *a)
Definition: asterisk.c:2362
static char canary_filename[128]
Definition: asterisk.c:387
#define CMD_MATCHESARRAY
static __inline uint64_t rdtsc(void)
Definition: asterisk.c:867
static struct sigaction child_handler
Definition: asterisk.c:1756
int ast_set_priority(int pri)
We set ourselves to a high priority, that we might pre-empt everything else. If your PBX has heavy ac...
Definition: asterisk.c:1838
static void asterisk_daemon(int isroot, const char *runuser, const char *rungroup)
Definition: asterisk.c:4083
void ast_console_toggle_loglevel(int fd, int level, int state)
enable or disable a logging level to a specified console
Definition: asterisk.c:1248
static char * handle_show_settings(struct ast_cli_entry *e, int cmd, struct ast_cli_args *a)
Give an overview of core settings.
Definition: asterisk.c:467
static int has_priority(void)
Check whether we were set to high(er) priority.
Definition: asterisk.c:1775
#define PF_LOCAL
Definition: asterisk.c:293
unsigned int need_el_end
Definition: asterisk.c:401
void ast_console_toggle_mute(int fd, int silent)
mute or unmute a console from logging
Definition: asterisk.c:1271
static void send_rasterisk_connect_commands(void)
Definition: asterisk.c:2641
unsigned int need_quit
Definition: asterisk.c:399
#define ASTERISK_PROMPT
Definition: asterisk.c:2605
static struct sigaction safe_system_prev_handler
Definition: asterisk.c:1099
static char * handle_bang(struct ast_cli_entry *e, int cmd, struct ast_cli_args *a)
Definition: asterisk.c:2510
static struct sigaction hup_handler
Definition: asterisk.c:1736
static pthread_t mon_sig_flags
Definition: asterisk.c:385
static int fdprint(int fd, const char *s)
Definition: asterisk.c:1075
static pthread_t consolethread
Definition: asterisk.c:384
static EditLine * el
Definition: asterisk.c:340
static void * netconsole(void *vconsole)
Definition: asterisk.c:1425
static int ast_el_initialize(void)
Definition: asterisk.c:3091
static int set_priority_all(int pri)
Set priority on all known threads.
Definition: asterisk.c:1795
static void ast_begin_shutdown(void)
Definition: asterisk.c:1896
static char * handle_restart_now(struct ast_cli_entry *e, int cmd, struct ast_cli_args *a)
Definition: asterisk.c:2424
static char * handle_restart_when_convenient(struct ast_cli_entry *e, int cmd, struct ast_cli_args *a)
Definition: asterisk.c:2466
static int ast_el_read_history(const char *)
Definition: asterisk.c:3178
static char * handle_abort_shutdown(struct ast_cli_entry *e, int cmd, struct ast_cli_args *a)
Definition: asterisk.c:2487
int ast_shutting_down(void)
Definition: asterisk.c:1873
static void _child_handler(int sig)
Definition: asterisk.c:1741
void ast_console_puts_mutable(const char *string, int level)
log the string to the root console, and all attached network console clients
Definition: asterisk.c:1313
#define AST_MAX_CONNECTS
Definition: asterisk.c:296
int ast_pbx_uuid_get(char *pbx_uuid, int length)
Retrieve the PBX UUID.
Definition: asterisk.c:973
void ast_replace_sigchld(void)
Replace the SIGCHLD handler.
Definition: asterisk.c:1101
int ast_cancel_shutdown(void)
Cancel an existing shutdown and return to normal operation.
Definition: asterisk.c:1878
static void ast_network_puts(const char *string)
write the string to all attached console clients
Definition: asterisk.c:1337
static int read_credentials(int fd, char *buffer, size_t size, struct console *con)
read() function supporting the reception of user credentials.
Definition: asterisk.c:1375
#define CHAR_TO_LIBEDIT(c)
Definition: asterisk.c:2671
static int shutdown_pending
Definition: asterisk.c:381
static void _null_sig_handler(int sig)
NULL handler so we can collect the child exit status.
Definition: asterisk.c:1081
static void process_histfile(int(*readwrite)(const char *filename))
Definition: asterisk.c:3194
static struct @297 sig_flags
static int sig_alert_pipe[2]
Definition: asterisk.c:396
struct timeval ast_lastreloadtime
Definition: asterisk.c:337
static const char warranty_lines[]
Definition: asterisk.c:2525
void ast_console_puts(const char *string)
write the string to the root console, and all attached network console clients
Definition: asterisk.c:1353
void ast_unregister_atexit(void(*func)(void))
Unregister a function registered with ast_register_atexit().
Definition: asterisk.c:1061
static int console_print(const char *s)
Definition: asterisk.c:2213
static void quit_handler(int num, shutdown_nice_t niceness, int restart)
Definition: asterisk.c:1908
static History * el_hist
Definition: asterisk.c:339
static char * handle_restart_gracefully(struct ast_cli_entry *e, int cmd, struct ast_cli_args *a)
Definition: asterisk.c:2445
static void * monitor_sig_flags(void *unused)
Definition: asterisk.c:3458
#define COPYRIGHT_TAG
Definition: asterisk.c:300
#define EL_BUF_SIZE
static char * show_warranty(struct ast_cli_entry *e, int cmd, struct ast_cli_args *a)
Definition: asterisk.c:2550
#define MAX_HISTORY_COMMAND_LENGTH
Definition: asterisk.c:3144
void ast_register_thread(char *name)
Definition: asterisk.c:414
static void ast_remotecontrol(char *data)
Definition: asterisk.c:3231
static int restartnow
Definition: asterisk.c:383
static int print_file(int fd, char *desc, const char *filename)
Print the contents of a file.
Definition: asterisk.c:450
void ast_unregister_thread(void *id)
Definition: asterisk.c:430
static void consolehandler(const char *s)
Definition: asterisk.c:2295
static struct ast_cli_entry cli_asterisk_shutdown[]
Shutdown Asterisk CLI commands.
Definition: asterisk.c:2615
int ast_register_atexit(void(*func)(void))
Register a function to be executed before Asterisk exits.
Definition: asterisk.c:1051
shutdown_nice_t
Definition: asterisk.c:356
@ SHUTDOWN_FAST
Definition: asterisk.c:369
@ SHUTDOWN_NORMAL
Definition: asterisk.c:371
@ SHUTDOWN_NICE
Definition: asterisk.c:373
@ SHUTDOWN_REALLY_NICE
Definition: asterisk.c:375
@ SHUTTING_DOWN
Definition: asterisk.c:362
@ SHUTTING_DOWN_FINAL
Definition: asterisk.c:360
@ NOT_SHUTTING_DOWN
Definition: asterisk.c:358
static ast_mutex_t safe_system_lock
Definition: asterisk.c:1094
static pid_t safe_exec_prep(int dualfork)
fork and perform other preparations for spawning applications
Definition: asterisk.c:1132
int ast_safe_system(const char *s)
Safely spawn an OS shell command while closing file descriptors.
Definition: asterisk.c:1232
static int ast_all_zeros(const char *s)
Definition: asterisk.c:2284
#define SHUTDOWN_TIMEOUT
Definition: asterisk.c:1917
static int can_safely_quit(shutdown_nice_t niceness, int restart)
Definition: asterisk.c:1960
static char * cli_prompt(EditLine *editline)
Definition: asterisk.c:2778
static void set_title(char *text)
Set an X-term or screen title.
Definition: asterisk.c:1762
static char * _argv[256]
Definition: asterisk.c:354
static int register_atexit(void(*func)(void), int is_cleanup)
Definition: asterisk.c:1032
static char * handle_clear_profile(struct ast_cli_entry *e, int cmd, struct ast_cli_args *a)
Definition: asterisk.c:943
static int wait_for_channels_to_die(shutdown_nice_t niceness, int seconds)
Definition: asterisk.c:1930
static struct ast_threadstorage console_state
Definition: asterisk.c:2211
static int ast_makesocket(void)
Definition: asterisk.c:1595
#define DEFINE_PROFILE_MIN_MAX_VALUES
Definition: asterisk.c:895
unsigned int need_quit_handler
Definition: asterisk.c:400
static int canary_pid
Definition: asterisk.c:386
static int ast_tryconnect(void)
Definition: asterisk.c:1681
static void * canary_thread(void *unused)
Definition: asterisk.c:3483
static void * listener(void *unused)
Definition: asterisk.c:1515
static struct ast_cli_entry cli_asterisk[]
Definition: asterisk.c:2624
static int fdsend(int fd, const char *s)
Definition: asterisk.c:1069
static int ast_el_write_history(const char *)
Definition: asterisk.c:3168
static void run_startup_commands(void)
Definition: asterisk.c:3522
static int show_cli_help(void)
Definition: asterisk.c:3385
static void ast_el_read_default_histfile(void)
Definition: asterisk.c:3221
static char * handle_show_profile(struct ast_cli_entry *e, int cmd, struct ast_cli_args *a)
Definition: asterisk.c:908
static void env_init(void)
Definition: asterisk.c:3550
static int ast_consock
Definition: asterisk.c:314
struct timeval ast_startuptime
Definition: asterisk.c:336
static void read_pjproject_startup_options(void)
Definition: asterisk.c:3424
static const char license_lines[]
Definition: asterisk.c:2568
void ast_unreplace_sigchld(void)
Restore the SIGCHLD handler.
Definition: asterisk.c:1116
static void really_quit(int num, shutdown_nice_t niceness, int restart)
Definition: asterisk.c:2043
static int ast_socket
Definition: asterisk.c:312
pid_t ast_mainpid
Definition: asterisk.c:315
static void ast_el_write_default_histfile(void)
Definition: asterisk.c:3226
#define AF_LOCAL
Definition: asterisk.c:292
static int multi_thread_safe
Definition: asterisk.c:388
static struct ast_vector_string * ast_el_strtoarr(char *buf)
Definition: asterisk.c:2904
static void __quit_handler(int num)
Definition: asterisk.c:2139
void ast_console_puts_mutable_full(const char *message, int level, int sublevel)
log the string to the console, and all attached console clients
Definition: asterisk.c:1320
static void set_icon(char *text)
Definition: asterisk.c:1768
static void print_intro_message(const char *runuser, const char *rungroup)
Definition: asterisk.c:3562
static struct sigaction ignore_sig_handler
Definition: asterisk.c:1090
static struct sigaction null_sig_handler
Definition: asterisk.c:1085
struct console consoles[AST_MAX_CONNECTS]
Definition: asterisk.c:343
int64_t ast_profile(int i, int64_t delta)
Definition: asterisk.c:833
static struct sigaction urg_handler
Definition: asterisk.c:1713
Asterisk main include file. File version handling, generic pbx functions.
#define sched_setscheduler
Definition: asterisk.h:51
int ast_pbx_init(void)
Definition: pbx.c:8989
#define setpriority
Definition: asterisk.h:50
int ast_fd_init(void)
Definition: astfd.c:370
#define PATH_MAX
Definition: asterisk.h:40
#define ast_alloca(size)
call __builtin_alloca to ensure we get gcc builtin semantics
Definition: astmm.h:288
#define ast_free(a)
Definition: astmm.h:180
#define ast_realloc(p, len)
A wrapper for realloc()
Definition: astmm.h:226
#define ast_strdup(str)
A wrapper for strdup()
Definition: astmm.h:241
#define ast_strdupa(s)
duplicate a string in memory from the stack
Definition: astmm.h:298
void ast_free_ptr(void *ptr)
free() wrapper
Definition: astmm.c:1739
#define ast_asprintf(ret, fmt,...)
A wrapper for asprintf()
Definition: astmm.h:267
#define ast_calloc(num, len)
A wrapper for calloc()
Definition: astmm.h:202
#define ast_log
Definition: astobj2.c:42
static int tmp()
Definition: bt_open.c:389
Bucket File API.
int ast_bucket_init(void)
Initialize bucket support.
Definition: bucket.c:954
const char * ast_build_os
Definition: buildinfo.c:32
const char * ast_build_machine
Definition: buildinfo.c:31
const char * ast_build_hostname
Definition: buildinfo.c:29
const char * ast_build_user
Definition: buildinfo.c:34
const char * ast_build_date
Definition: buildinfo.c:33
const char * ast_build_kernel
Definition: buildinfo.c:30
CallerID (and other GR30) management and generation Includes code and algorithms from the Zapata libr...
void callerid_init(void)
CallerID Initialization.
Definition: callerid.c:116
Call Detail Record API.
int ast_cdr_is_enabled(void)
Return TRUE if CDR subsystem is enabled.
Definition: cdr.c:2923
void ast_cdr_engine_term(void)
Definition: cdr.c:4665
static const char desc[]
Definition: cdr_radius.c:84
static PGresult * result
Definition: cel_pgsql.c:84
static char version[AST_MAX_EXTENSION]
Definition: chan_ooh323.c:391
General Asterisk PBX channel definitions.
void ast_softhangup_all(void)
Soft hangup all active channels.
Definition: channel.c:493
int ast_undestroyed_channels(void)
Definition: channel.c:504
int ast_active_channels(void)
returns number of active/allocated channels
Definition: channel.c:499
Standard Command Line Interface.
#define CLI_SHOWUSAGE
Definition: cli.h:45
#define AST_CLI_COMPLETE_EOF
Definition: cli.h:52
#define CLI_SUCCESS
Definition: cli.h:44
int ast_cli_unregister_multiple(struct ast_cli_entry *e, int len)
Unregister multiple commands.
Definition: clicompat.c:30
#define AST_CLI_DEFINE(fn, txt,...)
Definition: cli.h:197
void ast_cli(int fd, const char *fmt,...)
Definition: clicompat.c:6
int ast_cli_allow_at_shutdown(struct ast_cli_entry *e)
Allow a CLI command to be executed while Asterisk is shutting down.
Definition: main/cli.c:3061
int ast_cli_command_multiple_full(int uid, int gid, int fd, size_t size, const char *s)
Executes multiple CLI commands Interpret strings separated by NULL and execute each one,...
Definition: main/cli.c:3039
ast_cli_command
calling arguments for new-style handlers.
Definition: cli.h:151
@ CLI_INIT
Definition: cli.h:152
@ CLI_GENERATE
Definition: cli.h:153
struct ast_vector_string * ast_cli_completion_vector(const char *text, const char *word)
Generates a vector of strings for CLI completion.
Definition: main/cli.c:2766
#define ast_cli_register_multiple(e, len)
Register multiple commands.
Definition: cli.h:265
Codec API.
int ast_codec_init(void)
Initialize codec support within the core.
Definition: codec.c:250
int ast_codec_builtin_init(void)
Initialize built-in codecs within the core.
Device state management.
int devstate_init(void)
Initialize the device state core.
Definition: devicestate.c:896
char buf[BUFSIZE]
Definition: eagi_proxy.c:66
Endpoint abstractions.
void ast_verbose(const char *fmt,...)
Definition: extconf.c:2206
#define min(a, b)
Definition: f2c.h:197
#define max(a, b)
Definition: f2c.h:198
Generic File Format Support. Should be included by clients of the file handling routines....
Media Format API.
int ast_format_init(void)
Initialize media format support.
Definition: format.c:77
Media Format Cache API.
int ast_format_cache_init(void)
Initialize format cache support within the core.
Definition: format_cache.c:364
static const char name[]
Definition: format_mp3.c:68
static int len(struct ast_channel *chan, const char *cmd, char *data, char *buf, size_t buflen)
int ast_manager_check_enabled(void)
Check if AMI is enabled.
Definition: manager.c:2109
int ast_webmanager_check_enabled(void)
Check if AMI/HTTP is enabled.
Definition: manager.c:2114
void ast_manager_publish_event(const char *type, int class_type, struct ast_json *obj)
Publish an event to AMI.
Definition: manager.c:2063
void ast_init_logger_for_socket_console(void)
load logger.conf configuration for console socket connections
Definition: logger.c:713
int ast_option_rtpusedynamic
Definition: options.c:88
int ast_option_maxfiles
Definition: options.c:81
int option_debug
Definition: options.c:69
int ast_verb_sys_level
Definition: options.c:64
int ast_option_maxcalls
Definition: options.c:79
int ast_option_pjproject_log_level
Definition: options.c:74
double ast_option_maxload
Definition: options.c:77
unsigned int ast_option_rtpptdynamic
Definition: options.c:89
int option_verbose
Definition: options.c:67
struct ast_flags ast_options
Definition: options.c:61
unsigned int option_dtmfminduration
Definition: options.c:83
int ast_option_pjproject_cache_pools
Definition: options.c:75
long option_minmemfree
Definition: options.c:86
int option_trace
Definition: options.c:71
@ AST_OPT_FLAG_HIGH_PRIORITY
Definition: options.h:48
@ AST_OPT_FLAG_GENERIC_PLC
Definition: options.h:100
@ AST_OPT_FLAG_TRANSCODE_VIA_SLIN
Definition: options.h:60
@ AST_OPT_FLAG_EXEC_INCLUDES
Definition: options.h:40
@ AST_OPT_FLAG_NO_COLOR
Definition: options.h:56
@ AST_OPT_FLAG_NO_FORK
Definition: options.h:42
@ AST_OPT_FLAG_TRANSMIT_SILENCE
Definition: options.h:74
@ AST_OPT_FLAG_ALWAYS_FORK
Definition: options.h:82
@ AST_OPT_FLAG_QUIET
Definition: options.h:44
@ AST_OPT_FLAG_GENERIC_PLC_ON_EQUAL_CODECS
Definition: options.h:102
@ AST_OPT_FLAG_MUTE
Definition: options.h:84
@ AST_OPT_FLAG_TIMESTAMP
Definition: options.h:68
@ AST_OPT_FLAG_EXEC
Definition: options.h:54
@ AST_OPT_FLAG_CACHE_RECORD_FILES
Definition: options.h:66
@ AST_OPT_FLAG_FULLY_BOOTED
Definition: options.h:58
@ AST_OPT_FLAG_INIT_KEYS
Definition: options.h:50
@ AST_OPT_FLAG_CONSOLE
Definition: options.h:46
@ AST_OPT_FLAG_FORCE_BLACK_BACKGROUND
Definition: options.h:94
@ AST_OPT_FLAG_LIGHT_BACKGROUND
Definition: options.h:90
@ AST_OPT_FLAG_REMOTE
Definition: options.h:52
@ AST_OPT_FLAG_DUMP_CORE
Definition: options.h:64
@ AST_OPT_FLAG_RECONNECT
Definition: options.h:72
static ENTRY retval
Definition: hsearch.c:50
static char prefix[MAX_PREFIX]
Definition: http.c:144
General Asterisk channel definitions for image handling.
int ast_image_init(void)
Initialize image stuff Initializes all the various image stuff. Basically just registers the cli stuf...
Definition: image.c:212
Application convenience functions, designed to give consistent look and feel to Asterisk apps.
int app_init(void)
Initialize the application core.
Definition: main/app.c:3365
void ast_close_fds_above_n(int n)
Common routine for child processes, to close all fds prior to exec(2)
Definition: main/app.c:3202
int setenv(const char *name, const char *value, int overwrite)
int getloadavg(double *list, int nelem)
char * strsep(char **str, const char *delims)
Configuration File Parser.
struct ast_config * ast_config_load2(const char *filename, const char *who_asked, struct ast_flags flags)
Load a config file.
Definition: main/config.c:3321
#define CONFIG_STATUS_FILEMISSING
int ast_realtime_enabled(void)
Check if there's any realtime engines loaded.
Definition: main/config.c:3544
#define CONFIG_STATUS_FILEUNCHANGED
#define CONFIG_STATUS_FILEINVALID
void ast_config_destroy(struct ast_config *cfg)
Destroys a config.
Definition: extconf.c:1289
struct ast_variable * ast_variable_browse(const struct ast_config *config, const char *category_name)
Definition: extconf.c:1215
@ CONFIG_FLAG_NOCACHE
@ CONFIG_FLAG_NOREALTIME
int register_config_cli(void)
Exposed initialization method for core process.
Definition: main/config.c:4236
#define VERBOSE_PREFIX_3
void ast_verb_console_unregister(void)
Unregister this thread's console verbosity level.
Definition: logger.c:2662
void ast_verb_console_register(int *level)
Register this thread's console verbosity level pointer.
Definition: logger.c:2646
#define NUMLOGLEVELS
#define ast_debug(level,...)
Log a DEBUG message.
#define VERBOSE_PREFIX_10
#define VERBOSE_PREFIX_6
int ast_is_logger_initialized(void)
Test if logger is initialized.
Definition: logger.c:2175
#define VERBOSE_PREFIX_2
#define VERBOSE_PREFIX_8
#define VERBOSE_PREFIX_7
#define VERBOSE_PREFIX_4
#define __LOG_VERBOSE
#define VERBOSE_PREFIX_5
#define VERBOSE_PREFIX_1
#define LOG_ERROR
#define VERBOSE_PREFIX_9
#define ast_verb(level,...)
#define LOG_WARNING
int ast_verb_console_get(void)
Get this thread's console verbosity level.
Definition: logger.c:2673
const char * ast_logger_get_dateformat(void)
Get the logger configured date format.
Definition: logger.c:2927
#define VERBOSE_MAGIC2LEVEL(x)
#define VERBOSE_HASMAGIC(x)
I/O Management (derived from Cheops-NG)
int ast_get_termcols(int fd)
Columns of Terminal.
Definition: io.c:373
int ast_sd_notify(const char *state)
a wrapper for sd_notify(): notify systemd of any state changes.
Definition: io.c:392
int ast_sd_get_fd_un(int type, const char *path)
Find a listening AF_LOCAL file descriptor provided by socket activation.
Definition: io.c:454
Asterisk JSON abstraction layer.
void ast_json_unref(struct ast_json *value)
Decrease refcount on value. If refcount reaches zero, value is freed.
Definition: json.c:73
struct ast_json * ast_json_pack(char const *format,...)
Helper for creating complex JSON values.
Definition: json.c:612
int ast_json_init(void)
Initialize the JSON library.
Definition: json.c:726
A set of macros to manage forward-linked lists.
#define AST_RWLIST_REMOVE_CURRENT
Definition: linkedlists.h:570
#define AST_RWLIST_RDLOCK(head)
Read locks a list.
Definition: linkedlists.h:78
#define AST_LIST_HEAD_STATIC(name, type)
Defines a structure to be used to hold a list of specified type, statically initialized.
Definition: linkedlists.h:291
#define AST_RWLIST_TRAVERSE_SAFE_BEGIN
Definition: linkedlists.h:545
#define AST_RWLIST_WRLOCK(head)
Write locks a list.
Definition: linkedlists.h:52
#define AST_RWLIST_UNLOCK(head)
Attempts to unlock a read/write based list.
Definition: linkedlists.h:151
#define AST_RWLIST_HEAD_STATIC(name, type)
Defines a structure to be used to hold a read/write list of specified type, statically initialized.
Definition: linkedlists.h:333
#define AST_LIST_ENTRY(type)
Declare a forward link structure inside a list entry.
Definition: linkedlists.h:410
#define AST_RWLIST_TRAVERSE_SAFE_END
Definition: linkedlists.h:617
#define AST_LIST_TRAVERSE_SAFE_END
Closes a safe loop traversal block.
Definition: linkedlists.h:615
#define AST_LIST_LOCK(head)
Locks a list.
Definition: linkedlists.h:40
#define AST_RWLIST_TRAVERSE
Definition: linkedlists.h:494
#define AST_LIST_INSERT_HEAD(head, elm, field)
Inserts a list entry at the head of a list.
Definition: linkedlists.h:711
#define AST_LIST_TRAVERSE_SAFE_BEGIN(head, var, field)
Loops safely over (traverses) the entries in a list.
Definition: linkedlists.h:529
#define AST_LIST_REMOVE_CURRENT(field)
Removes the current entry from a list during a traversal.
Definition: linkedlists.h:557
#define AST_RWLIST_INSERT_HEAD
Definition: linkedlists.h:718
#define AST_LIST_REMOVE_HEAD(head, field)
Removes and returns the head entry from a list.
Definition: linkedlists.h:833
#define AST_LIST_UNLOCK(head)
Attempts to unlock a list.
Definition: linkedlists.h:140
#define AST_RWLIST_ENTRY
Definition: linkedlists.h:415
struct ast_tm * ast_localtime(const struct timeval *timep, struct ast_tm *p_tm, const char *zone)
Timezone-independent version of localtime_r(3).
Definition: localtime.c:1739
int ast_strftime(char *buf, size_t len, const char *format, const struct ast_tm *tm)
Special version of strftime(3) that handles fractions of a second. Takes the same arguments as strfti...
Definition: localtime.c:2524
Asterisk locking-related definitions:
#define AST_PTHREADT_NULL
Definition: lock.h:66
#define ast_mutex_unlock(a)
Definition: lock.h:190
#define ast_mutex_lock(a)
Definition: lock.h:189
#define AST_MUTEX_DEFINE_STATIC(mutex)
Definition: lock.h:520
static char * levels[NUMLOGLEVELS]
Logging channels used in the Asterisk logging system.
Definition: logger.c:214
static char hostname[MAXHOSTNAMELEN]
Definition: logger.c:119
#define WEXITSTATUS(status)
#define WIFEXITED(status)
int errno
The AMI - Asterisk Manager Interface - is a TCP protocol created to manage Asterisk with third-party ...
#define EVENT_FLAG_SYSTEM
Definition: manager.h:75
An in-memory media cache.
int ast_media_cache_init(void)
Initialize the media cache.
Definition: media_cache.c:671
Asterisk module definitions.
enum ast_module_reload_result ast_module_reload(const char *name)
Reload asterisk modules.
Definition: loader.c:1721
Asterisk MWI API.
int mwi_init(void)
Initialize the mwi core.
Definition: mwi.c:507
Wrapper for network related headers, masking differences between various operating systems....
#define MAXHOSTNAMELEN
Definition: network.h:69
Options provided by main asterisk program.
#define ast_opt_dump_core
Definition: options.h:119
#define ast_opt_remote
Definition: options.h:114
int ast_language_is_prefix
The following variable controls the layout of localized sound files. If 0, use the historical layout ...
Definition: file.c:67
#define MAX_PJ_LOG_MAX_LEVEL
Definition: options.h:141
#define ast_opt_exec
Definition: options.h:115
#define ast_opt_reconnect
Definition: options.h:123
#define DEFAULT_PJPROJECT_CACHE_POOLS
Definition: options.h:178
#define ast_opt_console
Definition: options.h:111
#define ast_opt_hide_connect
Definition: options.h:132
#define ast_opt_mute
Definition: options.h:127
#define ast_opt_high_priority
Definition: options.h:112
#define ast_opt_timestamp
Definition: options.h:122
#define ast_opt_always_fork
Definition: options.h:126
#define ast_opt_no_fork
Definition: options.h:109
#define ast_opt_hide_messaging_ami_events
Definition: options.h:137
#define ast_opt_sounds_search_custom
Definition: options.h:138
#define DEFAULT_PJ_LOG_MAX_LEVEL
Definition: options.h:149
#define ast_opt_cache_media_frames
Definition: options.h:121
char ast_defaultlanguage[]
Definition: options.c:98
Asterisk file paths, configured in asterisk.conf.
const char * ast_config_AST_KEY_DIR
Definition: options.c:161
const char * ast_config_AST_CACHE_DIR
Definition: options.c:150
const char * ast_config_AST_RUN_GROUP
Definition: options.c:169
const char * ast_config_AST_SOCKET
Definition: options.c:167
const char * ast_config_AST_RUN_USER
Definition: options.c:168
const char * ast_config_AST_CTL_PERMISSIONS
Definition: options.c:172
const char * ast_config_AST_CTL_GROUP
Definition: options.c:174
const char * ast_config_AST_MODULE_DIR
Definition: options.c:153
const char * ast_config_AST_PID
Definition: options.c:166
const char * ast_config_AST_RUN_DIR
Definition: options.c:162
const char * ast_config_AST_DATA_DIR
Definition: options.c:158
const char * ast_config_AST_CONFIG_DIR
Definition: options.c:151
const char * ast_config_AST_SPOOL_DIR
Definition: options.c:154
const char * ast_config_AST_AGI_DIR
Definition: options.c:160
const char * ast_config_AST_VAR_DIR
Definition: options.c:157
const char * ast_config_AST_SYSTEM_NAME
Definition: options.c:170
const char * ast_config_AST_SBIN_DIR
Definition: options.c:163
const char * ast_config_AST_CONFIG_FILE
Definition: options.c:152
const char * ast_config_AST_LOG_DIR
Definition: options.c:159
const char * ast_config_AST_CTL_OWNER
Definition: options.c:173
const char * ast_config_AST_DB
Definition: options.c:165
Core PBX routines and definitions.
Call Pickup API.
int ast_pickup_init(void)
Initialize pickup.
Definition: pickup.c:399
#define ast_poll(a, b, c)
Definition: poll-compat.h:88
Presence state management.
int ast_presence_state_engine_init(void)
static int total
Definition: res_adsi.c:970
#define NULL
Definition: resample.c:96
Pluggable RTP Architecture.
#define AST_RTP_PT_LAST_REASSIGN
Definition: rtp_engine.h:95
#define AST_RTP_MAX_PT
Definition: rtp_engine.h:83
#define AST_RTP_PT_FIRST_DYNAMIC
Definition: rtp_engine.h:92
Scheduler Routines (derived from cheops)
Security Event Reporting API.
int ast_security_stasis_init(void)
initializes stasis topic/event types for ast_security_topic and ast_security_event_type
#define FD_SET(fd, fds)
Definition: select.h:58
#define ast_FDMAX
Definition: select.h:41
unsigned int ast_FD_SETSIZE
Definition: poll.c:86
static int ast_select(int nfds, ast_fdset *rfds, ast_fdset *wfds, ast_fdset *efds, struct timeval *tvp)
Waits for activity on a group of channels.
Definition: select.h:79
#define FD_ZERO(a)
Definition: select.h:49
Sorcery Data Access Layer API.
int ast_sorcery_init(void)
Initialize the sorcery API.
Definition: sorcery.c:387
Stasis Message Bus API. See Stasis Message Bus API for detailed documentation.
int stasis_init(void)
Initialize the Stasis subsystem.
Definition: stasis.c:3061
Endpoint abstractions.
int ast_endpoint_stasis_init(void)
Initialization function for endpoint stasis support.
int ast_stasis_system_init(void)
Initialize the stasis system topic and message types.
int ast_str_append(struct ast_str **buf, ssize_t max_len, const char *fmt,...)
Append to a thread local dynamic string.
Definition: strings.h:1139
char * ast_str_buffer(const struct ast_str *buf)
Returns the string buffer within the ast_str buf.
Definition: strings.h:761
#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 attribute_pure ast_true(const char *val)
Make sure something is true. Determine if a string containing a boolean value is "true"....
Definition: utils.c:2199
static force_inline int attribute_pure ast_strlen_zero(const char *s)
Definition: strings.h:65
int attribute_pure ast_false(const char *val)
Make sure something is false. Determine if a string containing a boolean value is "false"....
Definition: utils.c:2216
void ast_str_reset(struct ast_str *buf)
Reset the content of a dynamic string. Useful before a series of ast_str_append.
Definition: strings.h:693
#define ast_str_create(init_len)
Create a malloc'ed dynamic length string.
Definition: strings.h:659
int ast_str_set(struct ast_str **buf, ssize_t max_len, const char *fmt,...)
Set a dynamic string using variable arguments.
Definition: strings.h:1113
void ast_copy_string(char *dst, const char *src, size_t size)
Size-limited null-terminating string copy.
Definition: strings.h:425
char * ast_strip(char *s)
Strip leading/trailing whitespace from a string.
Definition: strings.h:223
int is_cleanup
Definition: asterisk.c:330
void(* func)(void)
Definition: asterisk.c:329
struct ast_atexit::@298 list
descriptor for a cli entry.
Definition: cli.h:171
int args
This gets set in ast_cli_register()
Definition: cli.h:185
char * command
Definition: cli.h:186
const char * usage
Definition: cli.h:177
Structure used to handle boolean flags.
Definition: utils.h:199
Abstract JSON element (object, array, string, int, ...).
Support for dynamic strings.
Definition: strings.h:623
Structure for variables, used for configurations and for channel variables.
struct ast_variable * next
String vector definitions.
Definition: vector.h:55
int mute
Definition: asterisk.c:320
int uid
Definition: asterisk.c:321
int gid
Definition: asterisk.c:322
int p[2]
Definition: asterisk.c:318
int fd
Definition: asterisk.c:317
int option_verbose
Definition: asterisk.c:325
pthread_t t
Definition: asterisk.c:319
int levels[NUMLOGLEVELS]
Definition: asterisk.c:323
Definition: search.h:40
int max_size
Definition: asterisk.c:789
struct profile_entry e[0]
Definition: asterisk.c:790
Definition: asterisk.c:779
int64_t events
Definition: asterisk.c:784
int64_t mark
Definition: asterisk.c:782
const char * name
Definition: asterisk.c:780
int64_t value
Definition: asterisk.c:783
uint64_t scale
Definition: asterisk.c:781
Definition: sched.c:76
TTY/TDD Generation support.
void tdd_init(void)
Definition: tdd.c:94
Handy terminal functions for vt* terms.
#define COLOR_BRGREEN
Definition: term.h:55
const char * term_quit(void)
Definition: term.c:412
#define COLOR_GRAY
Definition: term.h:51
int ast_term_color_code(struct ast_str **str, int fgcolor, int bgcolor)
Append a color sequence to an ast_str.
Definition: term.c:296
const char * ast_term_reset(void)
Returns the terminal reset code.
Definition: term.c:357
#define COLOR_WHITE
Definition: term.h:64
const char * ast_term_color(int fgcolor, int bgcolor)
Return a color sequence string.
Definition: term.c:341
const char * term_end(void)
Definition: term.c:407
#define COLOR_BLACK
Definition: term.h:50
#define COLORIZE(fg, bg, str)
Definition: term.h:72
#define COLORIZE_FMT
Shortcut macros for coloring a set of text.
Definition: term.h:71
Test Framework API.
static struct test_val a
static struct test_val c
#define AST_THREADSTORAGE_CUSTOM(a, b, c)
Define a thread storage variable, with custom initialization and cleanup.
void * ast_threadstorage_get(struct ast_threadstorage *ts, size_t init_size)
Retrieve thread storage.
struct timeval ast_tvsub(struct timeval a, struct timeval b)
Returns the difference of two timevals a - b.
Definition: extconf.c:2297
struct timeval ast_tvnow(void)
Returns current timeval. Meant to replace calls to gettimeofday().
Definition: time.h:159
Support for translation of data formats. translate.c.
int ast_translate_init(void)
Initialize the translation matrix and index to format conversion table.
Definition: translate.c:1675
u-Law to Signed linear conversion
void ast_ulaw_init(void)
Set up mu-law conversion table.
Definition: ulaw.c:173
UTF-8 information and validation functions.
int ast_utf8_init(void)
Register UTF-8 tests.
Definition: utf8.c:919
static int inbuf(struct baseio *bio, FILE *fi)
utility used by inchar(), for base_encode()
Definition: utils.c:590
Utility functions.
#define ast_test_flag(p, flag)
Definition: utils.h:63
#define RAII_VAR(vartype, varname, initval, dtor)
Declare a variable that will call a destructor function when it goes out of scope.
Definition: utils.h:941
#define ast_assert(a)
Definition: utils.h:739
#define ast_pthread_create_background(a, b, c, d)
Definition: utils.h:592
char * ast_eid_to_str(char *s, int maxlen, struct ast_eid *eid)
Convert an EID to a string.
Definition: utils.c:2839
int ast_get_tid(void)
Get current thread ID.
Definition: utils.c:2752
#define ast_clear_flag(p, flag)
Definition: utils.h:77
int ast_utils_init(void)
Definition: utils.c:2617
#define ast_pthread_create_detached(a, b, c, d)
Definition: utils.h:588
#define ast_fd_set_flags(fd, flags)
Set flags on the given file descriptor.
Definition: utils.h:1039
#define ast_pthread_create_detached_background(a, b, c, d)
Definition: utils.h:597
#define ast_set_flag(p, flag)
Definition: utils.h:70
#define ARRAY_LEN(a)
Definition: utils.h:666
struct ast_eid ast_eid_default
Global EID.
Definition: options.c:93
Universally unique identifier support.
#define AST_UUID_STR_LEN
Definition: uuid.h:27
void ast_uuid_init(void)
Initialize the UUID system.
Definition: uuid.c:192
char * ast_uuid_generate_str(char *buf, size_t size)
Generate a UUID string.
Definition: uuid.c:141
#define AST_VECTOR_SIZE(vec)
Get the number of elements in a vector.
Definition: vector.h:609
#define AST_VECTOR_PTR_FREE(vec)
Deallocates this vector pointer.
Definition: vector.h:189
#define AST_VECTOR_APPEND(vec, elem)
Append an element to a vector, growing the vector if needed.
Definition: vector.h:256
#define AST_VECTOR_CALLBACK_VOID(vec, callback,...)
Execute a callback on every element in a vector disregarding callback return.
Definition: vector.h:862
#define AST_VECTOR_GET(vec, idx)
Get an element from a vector.
Definition: vector.h:680
Asterisk XML Documentation API.