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