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