Add CEL local optimization record type
[asterisk/asterisk.git] / main / asterisk.c
1 /*
2  * Asterisk -- An open source telephony toolkit.
3  *
4  * Copyright (C) 1999 - 2012, 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 - 2012, Digium, Inc.
57  * Asterisk is a <a href="http://www.digium.com/en/company/view-policy.php?id=Trademark-Policy">registered trademark</a>
58  * of <a href="http://www.digium.com">Digium, Inc</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 http://www.asterisk.org Asterisk Homepage
74  * \li http://wiki.asterisk.org Asterisk Wiki
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 http://www.freenode.net 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 ASTERISK_FILE_VERSION(__FILE__, "$Revision$")
153
154 #include "asterisk/_private.h"
155
156 #undef sched_setscheduler
157 #undef setpriority
158 #include <sys/time.h>
159 #include <fcntl.h>
160 #include <signal.h>
161 #include <sched.h>
162 #include <sys/un.h>
163 #include <sys/wait.h>
164 #include <ctype.h>
165 #include <sys/resource.h>
166 #include <grp.h>
167 #include <pwd.h>
168 #include <sys/stat.h>
169 #if defined(HAVE_SYSINFO)
170 #include <sys/sysinfo.h>
171 #elif defined(HAVE_SYSCTL)
172 #include <sys/param.h>
173 #include <sys/sysctl.h>
174 #if !defined(__OpenBSD__)
175 #include <sys/vmmeter.h>
176 #if defined(__FreeBSD__)
177 #include <vm/vm_param.h>
178 #endif
179 #endif
180 #if defined(HAVE_SWAPCTL)
181 #include <sys/swap.h>
182 #endif
183 #endif
184 #include <regex.h>
185 #include <histedit.h>
186
187 #if defined(SOLARIS)
188 int daemon(int, int);  /* defined in libresolv of all places */
189 #include <sys/loadavg.h>
190 #endif
191
192 #ifdef linux
193 #include <sys/prctl.h>
194 #ifdef HAVE_CAP
195 #include <sys/capability.h>
196 #endif /* HAVE_CAP */
197 #endif /* linux */
198
199 /* we define here the variables so to better agree on the prototype */
200 #include "asterisk/paths.h"
201 #include "asterisk/network.h"
202 #include "asterisk/cli.h"
203 #include "asterisk/channel.h"
204 #include "asterisk/translate.h"
205 #include "asterisk/features.h"
206 #include "asterisk/acl.h"
207 #include "asterisk/ulaw.h"
208 #include "asterisk/alaw.h"
209 #include "asterisk/callerid.h"
210 #include "asterisk/image.h"
211 #include "asterisk/tdd.h"
212 #include "asterisk/term.h"
213 #include "asterisk/manager.h"
214 #include "asterisk/cdr.h"
215 #include "asterisk/cel.h"
216 #include "asterisk/pbx.h"
217 #include "asterisk/enum.h"
218 #include "asterisk/http.h"
219 #include "asterisk/udptl.h"
220 #include "asterisk/app.h"
221 #include "asterisk/lock.h"
222 #include "asterisk/utils.h"
223 #include "asterisk/file.h"
224 #include "asterisk/io.h"
225 #include "editline/histedit.h"
226 #include "asterisk/config.h"
227 #include "asterisk/ast_version.h"
228 #include "asterisk/linkedlists.h"
229 #include "asterisk/devicestate.h"
230 #include "asterisk/presencestate.h"
231 #include "asterisk/module.h"
232 #include "asterisk/dsp.h"
233 #include "asterisk/buildinfo.h"
234 #include "asterisk/xmldoc.h"
235 #include "asterisk/poll-compat.h"
236 #include "asterisk/ccss.h"
237 #include "asterisk/test.h"
238 #include "asterisk/rtp_engine.h"
239 #include "asterisk/format.h"
240 #include "asterisk/aoc.h"
241 #include "asterisk/uuid.h"
242 #include "asterisk/sorcery.h"
243 #include "asterisk/stasis.h"
244 #include "asterisk/json.h"
245 #include "asterisk/stasis_endpoints.h"
246 #include "asterisk/stasis_system.h"
247 #include "asterisk/security_events.h"
248
249 #include "../defaults.h"
250
251 /*** DOCUMENTATION
252         <managerEvent language="en_US" name="FullyBooted">
253                 <managerEventInstance class="EVENT_FLAG_SYSTEM">
254                         <synopsis>Raised when all Asterisk initialization procedures have finished.</synopsis>
255                         <syntax>
256                                 <parameter name="Status">
257                                         <para>Informational message</para>
258                                 </parameter>
259                         </syntax>
260                 </managerEventInstance>
261         </managerEvent>
262         <managerEvent language="en_US" name="Shutdown">
263                 <managerEventInstance class="EVENT_FLAG_SYSTEM">
264                         <synopsis>Raised when Asterisk is shutdown or restarted.</synopsis>
265                         <syntax>
266                                 <parameter name="Shutdown">
267                                         <para>Whether the shutdown is proceeding cleanly (all channels
268                                         were hungup successfully) or uncleanly (channels will be
269                                         terminated)</para>
270                                         <enumlist>
271                                                 <enum name="Uncleanly"/>
272                                                 <enum name="Cleanly"/>
273                                         </enumlist>
274                                 </parameter>
275                                 <parameter name="Restart">
276                                         <para>Whether or not a restart will occur.</para>
277                                         <enumlist>
278                                                 <enum name="True"/>
279                                                 <enum name="False"/>
280                                         </enumlist>
281                                 </parameter>
282                         </syntax>
283                 </managerEventInstance>
284         </managerEvent>
285  ***/
286
287 #ifndef AF_LOCAL
288 #define AF_LOCAL AF_UNIX
289 #define PF_LOCAL PF_UNIX
290 #endif
291
292 #define AST_MAX_CONNECTS 128
293 #define NUM_MSGS 64
294
295 /*! Default minimum DTMF digit length - 80ms */
296 #define AST_MIN_DTMF_DURATION 80
297
298
299 /*! \brief Welcome message when starting a CLI interface */
300 #define WELCOME_MESSAGE \
301     ast_verbose("Asterisk %s, Copyright (C) 1999 - 2012 Digium, Inc. and others.\n" \
302                 "Created by Mark Spencer <markster@digium.com>\n" \
303                 "Asterisk comes with ABSOLUTELY NO WARRANTY; type 'core show warranty' for details.\n" \
304                 "This is free software, with components licensed under the GNU General Public\n" \
305                 "License version 2 and other licenses; you are welcome to redistribute it under\n" \
306                 "certain conditions. Type 'core show license' for details.\n" \
307                 "=========================================================================\n", ast_get_version()) \
308
309 /*! \defgroup main_options Main Configuration Options
310  * \brief Main configuration options from asterisk.conf or OS command line on starting Asterisk.
311  * \arg \ref Config_ast "asterisk.conf"
312  * \note Some of them can be changed in the CLI
313  */
314 /*! @{ */
315
316 struct ast_flags ast_options = { AST_DEFAULT_OPTIONS };
317 struct ast_flags ast_compat = { 0 };
318
319 int option_verbose;                             /*!< Verbosity level */
320 int option_debug;                               /*!< Debug level */
321 double option_maxload;                          /*!< Max load avg on system */
322 int option_maxcalls;                            /*!< Max number of active calls */
323 int option_maxfiles;                            /*!< Max number of open file handles (files, sockets) */
324 unsigned int option_dtmfminduration;            /*!< Minimum duration of DTMF. */
325 #if defined(HAVE_SYSINFO)
326 long option_minmemfree;                         /*!< Minimum amount of free system memory - stop accepting calls if free memory falls below this watermark */
327 #endif
328
329 /*! @} */
330
331 struct ast_eid ast_eid_default;
332
333 /* XXX tmpdir is a subdir of the spool directory, and no way to remap it */
334 char record_cache_dir[AST_CACHE_DIR_LEN] = DEFAULT_TMP_DIR;
335
336 static int ast_socket = -1;             /*!< UNIX Socket for allowing remote control */
337 static int ast_consock = -1;            /*!< UNIX Socket for controlling another asterisk */
338 pid_t ast_mainpid;
339 struct console {
340         int fd;                         /*!< File descriptor */
341         int p[2];                       /*!< Pipe */
342         pthread_t t;                    /*!< Thread of handler */
343         int mute;                       /*!< Is the console muted for logs */
344         int uid;                        /*!< Remote user ID. */
345         int gid;                        /*!< Remote group ID. */
346         int levels[NUMLOGLEVELS];       /*!< Which log levels are enabled for the console */
347 };
348
349 struct ast_atexit {
350         void (*func)(void);
351         int is_cleanup;
352         AST_LIST_ENTRY(ast_atexit) list;
353 };
354
355 static AST_LIST_HEAD_STATIC(atexits, ast_atexit);
356
357 struct timeval ast_startuptime;
358 struct timeval ast_lastreloadtime;
359
360 static History *el_hist;
361 static EditLine *el;
362 static char *remotehostname;
363
364 struct console consoles[AST_MAX_CONNECTS];
365
366 char defaultlanguage[MAX_LANGUAGE] = DEFAULT_LANGUAGE;
367
368 static int ast_el_add_history(char *);
369 static int ast_el_read_history(char *);
370 static int ast_el_write_history(char *);
371
372 struct _cfg_paths {
373         char config_dir[PATH_MAX];
374         char module_dir[PATH_MAX];
375         char spool_dir[PATH_MAX];
376         char monitor_dir[PATH_MAX];
377         char recording_dir[PATH_MAX];
378         char var_dir[PATH_MAX];
379         char data_dir[PATH_MAX];
380         char log_dir[PATH_MAX];
381         char agi_dir[PATH_MAX];
382         char run_dir[PATH_MAX];
383         char key_dir[PATH_MAX];
384
385         char config_file[PATH_MAX];
386         char db_path[PATH_MAX];
387         char sbin_dir[PATH_MAX];
388         char pid_path[PATH_MAX];
389         char socket_path[PATH_MAX];
390         char run_user[PATH_MAX];
391         char run_group[PATH_MAX];
392         char system_name[128];
393 };
394
395 static struct _cfg_paths cfg_paths;
396
397 const char *ast_config_AST_CONFIG_DIR   = cfg_paths.config_dir;
398 const char *ast_config_AST_CONFIG_FILE  = cfg_paths.config_file;
399 const char *ast_config_AST_MODULE_DIR   = cfg_paths.module_dir;
400 const char *ast_config_AST_SPOOL_DIR    = cfg_paths.spool_dir;
401 const char *ast_config_AST_MONITOR_DIR  = cfg_paths.monitor_dir;
402 const char *ast_config_AST_RECORDING_DIR        = cfg_paths.recording_dir;
403 const char *ast_config_AST_VAR_DIR      = cfg_paths.var_dir;
404 const char *ast_config_AST_DATA_DIR     = cfg_paths.data_dir;
405 const char *ast_config_AST_LOG_DIR      = cfg_paths.log_dir;
406 const char *ast_config_AST_AGI_DIR      = cfg_paths.agi_dir;
407 const char *ast_config_AST_KEY_DIR      = cfg_paths.key_dir;
408 const char *ast_config_AST_RUN_DIR      = cfg_paths.run_dir;
409 const char *ast_config_AST_SBIN_DIR = cfg_paths.sbin_dir;
410
411 const char *ast_config_AST_DB           = cfg_paths.db_path;
412 const char *ast_config_AST_PID          = cfg_paths.pid_path;
413 const char *ast_config_AST_SOCKET       = cfg_paths.socket_path;
414 const char *ast_config_AST_RUN_USER     = cfg_paths.run_user;
415 const char *ast_config_AST_RUN_GROUP    = cfg_paths.run_group;
416 const char *ast_config_AST_SYSTEM_NAME  = cfg_paths.system_name;
417
418 static char ast_config_AST_CTL_PERMISSIONS[PATH_MAX];
419 static char ast_config_AST_CTL_OWNER[PATH_MAX] = "\0";
420 static char ast_config_AST_CTL_GROUP[PATH_MAX] = "\0";
421 static char ast_config_AST_CTL[PATH_MAX] = "asterisk.ctl";
422
423 extern unsigned int ast_FD_SETSIZE;
424
425 static char *_argv[256];
426 typedef enum {
427         NOT_SHUTTING_DOWN = -2,
428         SHUTTING_DOWN = -1,
429         /* Valid values for quit_handler niceness below: */
430         SHUTDOWN_FAST,
431         SHUTDOWN_NORMAL,
432         SHUTDOWN_NICE,
433         SHUTDOWN_REALLY_NICE
434 } shutdown_nice_t;
435 static shutdown_nice_t shuttingdown = NOT_SHUTTING_DOWN;
436 static int restartnow;
437 static pthread_t consolethread = AST_PTHREADT_NULL;
438 static pthread_t mon_sig_flags;
439 static int canary_pid = 0;
440 static char canary_filename[128];
441 static int multi_thread_safe;
442
443 static char randompool[256];
444
445 static int sig_alert_pipe[2] = { -1, -1 };
446 static struct {
447          unsigned int need_reload:1;
448          unsigned int need_quit:1;
449          unsigned int need_quit_handler:1;
450 } sig_flags;
451
452 #if !defined(LOW_MEMORY)
453 struct file_version {
454         AST_RWLIST_ENTRY(file_version) list;
455         const char *file;
456         char *version;
457 };
458
459 static AST_RWLIST_HEAD_STATIC(file_versions, file_version);
460
461 void ast_register_file_version(const char *file, const char *version)
462 {
463         struct file_version *new;
464         char *work;
465         size_t version_length;
466
467         work = ast_strdupa(version);
468         work = ast_strip(ast_strip_quoted(work, "$", "$"));
469         version_length = strlen(work) + 1;
470
471         if (!(new = ast_calloc(1, sizeof(*new) + version_length)))
472                 return;
473
474         new->file = file;
475         new->version = (char *) new + sizeof(*new);
476         memcpy(new->version, work, version_length);
477         AST_RWLIST_WRLOCK(&file_versions);
478         AST_RWLIST_INSERT_HEAD(&file_versions, new, list);
479         AST_RWLIST_UNLOCK(&file_versions);
480 }
481
482 void ast_unregister_file_version(const char *file)
483 {
484         struct file_version *find;
485
486         AST_RWLIST_WRLOCK(&file_versions);
487         AST_RWLIST_TRAVERSE_SAFE_BEGIN(&file_versions, find, list) {
488                 if (!strcasecmp(find->file, file)) {
489                         AST_RWLIST_REMOVE_CURRENT(list);
490                         break;
491                 }
492         }
493         AST_RWLIST_TRAVERSE_SAFE_END;
494         AST_RWLIST_UNLOCK(&file_versions);
495
496         if (find)
497                 ast_free(find);
498 }
499
500 char *ast_complete_source_filename(const char *partial, int n)
501 {
502         struct file_version *find;
503         size_t len = strlen(partial);
504         int count = 0;
505         char *res = NULL;
506
507         AST_RWLIST_RDLOCK(&file_versions);
508         AST_RWLIST_TRAVERSE(&file_versions, find, list) {
509                 if (!strncasecmp(find->file, partial, len) && ++count > n) {
510                         res = ast_strdup(find->file);
511                         break;
512                 }
513         }
514         AST_RWLIST_UNLOCK(&file_versions);
515         return res;
516 }
517
518 /*! \brief Find version for given module name */
519 const char *ast_file_version_find(const char *file)
520 {
521         struct file_version *iterator;
522
523         AST_RWLIST_WRLOCK(&file_versions);
524         AST_RWLIST_TRAVERSE(&file_versions, iterator, list) {
525                 if (!strcasecmp(iterator->file, file))
526                         break;
527         }
528         AST_RWLIST_UNLOCK(&file_versions);
529         if (iterator)
530                 return iterator->version;
531         return NULL;
532 }
533
534 struct thread_list_t {
535         AST_RWLIST_ENTRY(thread_list_t) list;
536         char *name;
537         pthread_t id;
538         int lwp;
539 };
540
541 static AST_RWLIST_HEAD_STATIC(thread_list, thread_list_t);
542
543 void ast_register_thread(char *name)
544 {
545         struct thread_list_t *new = ast_calloc(1, sizeof(*new));
546
547         if (!new)
548                 return;
549
550         ast_assert(multi_thread_safe);
551         new->id = pthread_self();
552         new->lwp = ast_get_tid();
553         new->name = name; /* steal the allocated memory for the thread name */
554         AST_RWLIST_WRLOCK(&thread_list);
555         AST_RWLIST_INSERT_HEAD(&thread_list, new, list);
556         AST_RWLIST_UNLOCK(&thread_list);
557 }
558
559 void ast_unregister_thread(void *id)
560 {
561         struct thread_list_t *x;
562
563         AST_RWLIST_WRLOCK(&thread_list);
564         AST_RWLIST_TRAVERSE_SAFE_BEGIN(&thread_list, x, list) {
565                 if ((void *) x->id == id) {
566                         AST_RWLIST_REMOVE_CURRENT(list);
567                         break;
568                 }
569         }
570         AST_RWLIST_TRAVERSE_SAFE_END;
571         AST_RWLIST_UNLOCK(&thread_list);
572         if (x) {
573                 ast_free(x->name);
574                 ast_free(x);
575         }
576 }
577
578 /*! \brief Give an overview of core settings */
579 static char *handle_show_settings(struct ast_cli_entry *e, int cmd, struct ast_cli_args *a)
580 {
581         char buf[BUFSIZ];
582         struct ast_tm tm;
583         char eid_str[128];
584
585         switch (cmd) {
586         case CLI_INIT:
587                 e->command = "core show settings";
588                 e->usage = "Usage: core show settings\n"
589                            "       Show core misc settings";
590                 return NULL;
591         case CLI_GENERATE:
592                 return NULL;
593         }
594
595         ast_eid_to_str(eid_str, sizeof(eid_str), &ast_eid_default);
596
597         ast_cli(a->fd, "\nPBX Core settings\n");
598         ast_cli(a->fd, "-----------------\n");
599         ast_cli(a->fd, "  Version:                     %s\n", ast_get_version());
600         ast_cli(a->fd, "  Build Options:               %s\n", S_OR(AST_BUILDOPTS, "(none)"));
601         if (option_maxcalls)
602                 ast_cli(a->fd, "  Maximum calls:               %d (Current %d)\n", option_maxcalls, ast_active_channels());
603         else
604                 ast_cli(a->fd, "  Maximum calls:               Not set\n");
605         if (option_maxfiles)
606                 ast_cli(a->fd, "  Maximum open file handles:   %d\n", option_maxfiles);
607         else
608                 ast_cli(a->fd, "  Maximum open file handles:   Not set\n");
609         ast_cli(a->fd, "  Verbosity:                   %d\n", option_verbose);
610         ast_cli(a->fd, "  Debug level:                 %d\n", option_debug);
611         ast_cli(a->fd, "  Maximum load average:        %lf\n", option_maxload);
612 #if defined(HAVE_SYSINFO)
613         ast_cli(a->fd, "  Minimum free memory:         %ld MB\n", option_minmemfree);
614 #endif
615         if (ast_localtime(&ast_startuptime, &tm, NULL)) {
616                 ast_strftime(buf, sizeof(buf), "%H:%M:%S", &tm);
617                 ast_cli(a->fd, "  Startup time:                %s\n", buf);
618         }
619         if (ast_localtime(&ast_lastreloadtime, &tm, NULL)) {
620                 ast_strftime(buf, sizeof(buf), "%H:%M:%S", &tm);
621                 ast_cli(a->fd, "  Last reload time:            %s\n", buf);
622         }
623         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);
624         ast_cli(a->fd, "  System name:                 %s\n", ast_config_AST_SYSTEM_NAME);
625         ast_cli(a->fd, "  Entity ID:                   %s\n", eid_str);
626         ast_cli(a->fd, "  Default language:            %s\n", defaultlanguage);
627         ast_cli(a->fd, "  Language prefix:             %s\n", ast_language_is_prefix ? "Enabled" : "Disabled");
628         ast_cli(a->fd, "  User name and group:         %s/%s\n", ast_config_AST_RUN_USER, ast_config_AST_RUN_GROUP);
629         ast_cli(a->fd, "  Executable includes:         %s\n", ast_test_flag(&ast_options, AST_OPT_FLAG_EXEC_INCLUDES) ? "Enabled" : "Disabled");
630         ast_cli(a->fd, "  Transcode via SLIN:          %s\n", ast_test_flag(&ast_options, AST_OPT_FLAG_TRANSCODE_VIA_SLIN) ? "Enabled" : "Disabled");
631         ast_cli(a->fd, "  Internal timing:             %s\n", ast_test_flag(&ast_options, AST_OPT_FLAG_INTERNAL_TIMING) ? "Enabled" : "Disabled");
632         ast_cli(a->fd, "  Transmit silence during rec: %s\n", ast_test_flag(&ast_options, AST_OPT_FLAG_TRANSMIT_SILENCE) ? "Enabled" : "Disabled");
633         ast_cli(a->fd, "  Generic PLC:                 %s\n", ast_test_flag(&ast_options, AST_OPT_FLAG_GENERIC_PLC) ? "Enabled" : "Disabled");
634         ast_cli(a->fd, "  Min DTMF duration::          %u\n", option_dtmfminduration);
635
636         ast_cli(a->fd, "\n* Subsystems\n");
637         ast_cli(a->fd, "  -------------\n");
638         ast_cli(a->fd, "  Manager (AMI):               %s\n", check_manager_enabled() ? "Enabled" : "Disabled");
639         ast_cli(a->fd, "  Web Manager (AMI/HTTP):      %s\n", check_webmanager_enabled() ? "Enabled" : "Disabled");
640         ast_cli(a->fd, "  Call data records:           %s\n", ast_cdr_is_enabled() ? "Enabled" : "Disabled");
641         ast_cli(a->fd, "  Realtime Architecture (ARA): %s\n", ast_realtime_enabled() ? "Enabled" : "Disabled");
642
643         /*! \todo we could check musiconhold, voicemail, smdi, adsi, queues  */
644
645         ast_cli(a->fd, "\n* Directories\n");
646         ast_cli(a->fd, "  -------------\n");
647         ast_cli(a->fd, "  Configuration file:          %s\n", ast_config_AST_CONFIG_FILE);
648         ast_cli(a->fd, "  Configuration directory:     %s\n", ast_config_AST_CONFIG_DIR);
649         ast_cli(a->fd, "  Module directory:            %s\n", ast_config_AST_MODULE_DIR);
650         ast_cli(a->fd, "  Spool directory:             %s\n", ast_config_AST_SPOOL_DIR);
651         ast_cli(a->fd, "  Log directory:               %s\n", ast_config_AST_LOG_DIR);
652         ast_cli(a->fd, "  Run/Sockets directory:       %s\n", ast_config_AST_RUN_DIR);
653         ast_cli(a->fd, "  PID file:                    %s\n", ast_config_AST_PID);
654         ast_cli(a->fd, "  VarLib directory:            %s\n", ast_config_AST_VAR_DIR);
655         ast_cli(a->fd, "  Data directory:              %s\n", ast_config_AST_DATA_DIR);
656         ast_cli(a->fd, "  ASTDB:                       %s\n", ast_config_AST_DB);
657         ast_cli(a->fd, "  IAX2 Keys directory:         %s\n", ast_config_AST_KEY_DIR);
658         ast_cli(a->fd, "  AGI Scripts directory:       %s\n", ast_config_AST_AGI_DIR);
659         ast_cli(a->fd, "\n\n");
660         return CLI_SUCCESS;
661 }
662
663 static char *handle_show_threads(struct ast_cli_entry *e, int cmd, struct ast_cli_args *a)
664 {
665         int count = 0;
666         struct thread_list_t *cur;
667         switch (cmd) {
668         case CLI_INIT:
669                 e->command = "core show threads";
670                 e->usage =
671                         "Usage: core show threads\n"
672                         "       List threads currently active in the system.\n";
673                 return NULL;
674         case CLI_GENERATE:
675                 return NULL;
676         }
677
678         AST_RWLIST_RDLOCK(&thread_list);
679         AST_RWLIST_TRAVERSE(&thread_list, cur, list) {
680                 ast_cli(a->fd, "%p %d %s\n", (void *)cur->id, cur->lwp, cur->name);
681                 count++;
682         }
683         AST_RWLIST_UNLOCK(&thread_list);
684         ast_cli(a->fd, "%d threads listed.\n", count);
685         return CLI_SUCCESS;
686 }
687
688 #if defined (HAVE_SYSCTL) && defined(HAVE_SWAPCTL)
689 /*
690  * swapmode is rewritten by Tobias Weingartner <weingart@openbsd.org>
691  * to be based on the new swapctl(2) system call.
692  */
693 static int swapmode(int *used, int *total)
694 {
695         struct swapent *swdev;
696         int nswap, rnswap, i;
697
698         nswap = swapctl(SWAP_NSWAP, 0, 0);
699         if (nswap == 0)
700                 return 0;
701
702         swdev = ast_calloc(nswap, sizeof(*swdev));
703         if (swdev == NULL)
704                 return 0;
705
706         rnswap = swapctl(SWAP_STATS, swdev, nswap);
707         if (rnswap == -1) {
708                 ast_free(swdev);
709                 return 0;
710         }
711
712         /* if rnswap != nswap, then what? */
713
714         /* Total things up */
715         *total = *used = 0;
716         for (i = 0; i < nswap; i++) {
717                 if (swdev[i].se_flags & SWF_ENABLE) {
718                         *used += (swdev[i].se_inuse / (1024 / DEV_BSIZE));
719                         *total += (swdev[i].se_nblks / (1024 / DEV_BSIZE));
720                 }
721         }
722         ast_free(swdev);
723         return 1;
724 }
725 #elif defined(HAVE_SYSCTL) && !defined(HAVE_SYSINFO)
726 static int swapmode(int *used, int *total)
727 {
728         *used = *total = 0;
729         return 1;
730 }
731 #endif
732
733 #if defined(HAVE_SYSINFO) || defined(HAVE_SYSCTL)
734 /*! \brief Give an overview of system statistics */
735 static char *handle_show_sysinfo(struct ast_cli_entry *e, int cmd, struct ast_cli_args *a)
736 {
737         uint64_t physmem, freeram;
738         uint64_t freeswap = 0;
739         int nprocs = 0;
740         long uptime = 0;
741         int totalswap = 0;
742 #if defined(HAVE_SYSINFO)
743         struct sysinfo sys_info;
744         sysinfo(&sys_info);
745         uptime = sys_info.uptime / 3600;
746         physmem = sys_info.totalram * sys_info.mem_unit;
747         freeram = (sys_info.freeram * sys_info.mem_unit) / 1024;
748         totalswap = (sys_info.totalswap * sys_info.mem_unit) / 1024;
749         freeswap = (sys_info.freeswap * sys_info.mem_unit) / 1024;
750         nprocs = sys_info.procs;
751 #elif defined(HAVE_SYSCTL)
752         static int pageshift;
753         struct vmtotal vmtotal;
754         struct timeval  boottime;
755         time_t  now;
756         int mib[2], pagesize, usedswap = 0;
757         size_t len;
758         /* calculate the uptime by looking at boottime */
759         time(&now);
760         mib[0] = CTL_KERN;
761         mib[1] = KERN_BOOTTIME;
762         len = sizeof(boottime);
763         if (sysctl(mib, 2, &boottime, &len, NULL, 0) != -1) {
764                 uptime = now - boottime.tv_sec;
765         }
766         uptime = uptime/3600;
767         /* grab total physical memory  */
768         mib[0] = CTL_HW;
769 #if defined(HW_PHYSMEM64)
770         mib[1] = HW_PHYSMEM64;
771 #else
772         mib[1] = HW_PHYSMEM;
773 #endif
774         len = sizeof(physmem);
775         sysctl(mib, 2, &physmem, &len, NULL, 0);
776
777         pagesize = getpagesize();
778         pageshift = 0;
779         while (pagesize > 1) {
780                 pageshift++;
781                 pagesize >>= 1;
782         }
783
784         /* we only need the amount of log(2)1024 for our conversion */
785         pageshift -= 10;
786
787         /* grab vm totals */
788         mib[0] = CTL_VM;
789         mib[1] = VM_METER;
790         len = sizeof(vmtotal);
791         sysctl(mib, 2, &vmtotal, &len, NULL, 0);
792         freeram = (vmtotal.t_free << pageshift);
793         /* generate swap usage and totals */
794         swapmode(&usedswap, &totalswap);
795         freeswap = (totalswap - usedswap);
796         /* grab number of processes */
797 #if defined(__OpenBSD__)
798         mib[0] = CTL_KERN;
799         mib[1] = KERN_NPROCS;
800         len = sizeof(nprocs);
801         sysctl(mib, 2, &nprocs, &len, NULL, 0);
802 #endif
803 #endif
804
805         switch (cmd) {
806         case CLI_INIT:
807                 e->command = "core show sysinfo";
808                 e->usage =
809                         "Usage: core show sysinfo\n"
810                         "       List current system information.\n";
811                 return NULL;
812         case CLI_GENERATE:
813                 return NULL;
814         }
815
816         ast_cli(a->fd, "\nSystem Statistics\n");
817         ast_cli(a->fd, "-----------------\n");
818         ast_cli(a->fd, "  System Uptime:             %lu hours\n", uptime);
819         ast_cli(a->fd, "  Total RAM:                 %" PRIu64 " KiB\n", physmem / 1024);
820         ast_cli(a->fd, "  Free RAM:                  %" PRIu64 " KiB\n", freeram);
821 #if defined(HAVE_SYSINFO)
822         ast_cli(a->fd, "  Buffer RAM:                %" PRIu64 " KiB\n", ((uint64_t) sys_info.bufferram * sys_info.mem_unit) / 1024);
823 #endif
824 #if defined (HAVE_SYSCTL) || defined(HAVE_SWAPCTL)
825         ast_cli(a->fd, "  Total Swap Space:          %u KiB\n", totalswap);
826         ast_cli(a->fd, "  Free Swap Space:           %" PRIu64 " KiB\n\n", freeswap);
827 #endif
828         ast_cli(a->fd, "  Number of Processes:       %d \n\n", nprocs);
829         return CLI_SUCCESS;
830 }
831 #endif
832
833 struct profile_entry {
834         const char *name;
835         uint64_t        scale;  /* if non-zero, values are scaled by this */
836         int64_t mark;
837         int64_t value;
838         int64_t events;
839 };
840
841 struct profile_data {
842         int entries;
843         int max_size;
844         struct profile_entry e[0];
845 };
846
847 static struct profile_data *prof_data;
848
849 /*! \brief allocates a counter with a given name and scale.
850  * \return Returns the identifier of the counter.
851  */
852 int ast_add_profile(const char *name, uint64_t scale)
853 {
854         int l = sizeof(struct profile_data);
855         int n = 10;     /* default entries */
856
857         if (prof_data == NULL) {
858                 prof_data = ast_calloc(1, l + n*sizeof(struct profile_entry));
859                 if (prof_data == NULL)
860                         return -1;
861                 prof_data->entries = 0;
862                 prof_data->max_size = n;
863         }
864         if (prof_data->entries >= prof_data->max_size) {
865                 void *p;
866                 n = prof_data->max_size + 20;
867                 p = ast_realloc(prof_data, l + n*sizeof(struct profile_entry));
868                 if (p == NULL)
869                         return -1;
870                 prof_data = p;
871                 prof_data->max_size = n;
872         }
873         n = prof_data->entries++;
874         prof_data->e[n].name = ast_strdup(name);
875         prof_data->e[n].value = 0;
876         prof_data->e[n].events = 0;
877         prof_data->e[n].mark = 0;
878         prof_data->e[n].scale = scale;
879         return n;
880 }
881
882 int64_t ast_profile(int i, int64_t delta)
883 {
884         if (!prof_data || i < 0 || i > prof_data->entries)      /* invalid index */
885                 return 0;
886         if (prof_data->e[i].scale > 1)
887                 delta /= prof_data->e[i].scale;
888         prof_data->e[i].value += delta;
889         prof_data->e[i].events++;
890         return prof_data->e[i].value;
891 }
892
893 /* The RDTSC instruction was introduced on the Pentium processor and is not
894  * implemented on certain clones, like the Cyrix 586. Hence, the previous
895  * expectation of __i386__ was in error. */
896 #if defined ( __i686__) && (defined(__FreeBSD__) || defined(linux))
897 #if defined(__FreeBSD__)
898 #include <machine/cpufunc.h>
899 #elif defined(linux)
900 static __inline uint64_t
901 rdtsc(void)
902 {
903         uint64_t rv;
904
905         __asm __volatile(".byte 0x0f, 0x31" : "=A" (rv));
906         return (rv);
907 }
908 #endif
909 #else   /* supply a dummy function on other platforms */
910 static __inline uint64_t
911 rdtsc(void)
912 {
913         return 0;
914 }
915 #endif
916
917 int64_t ast_mark(int i, int startstop)
918 {
919         if (!prof_data || i < 0 || i > prof_data->entries) /* invalid index */
920                 return 0;
921         if (startstop == 1)
922                 prof_data->e[i].mark = rdtsc();
923         else {
924                 prof_data->e[i].mark = (rdtsc() - prof_data->e[i].mark);
925                 if (prof_data->e[i].scale > 1)
926                         prof_data->e[i].mark /= prof_data->e[i].scale;
927                 prof_data->e[i].value += prof_data->e[i].mark;
928                 prof_data->e[i].events++;
929         }
930         return prof_data->e[i].mark;
931 }
932
933 #define DEFINE_PROFILE_MIN_MAX_VALUES min = 0; \
934         max = prof_data->entries;\
935         if  (a->argc > 3) { /* specific entries */ \
936                 if (isdigit(a->argv[3][0])) { \
937                         min = atoi(a->argv[3]); \
938                         if (a->argc == 5 && strcmp(a->argv[4], "-")) \
939                                 max = atoi(a->argv[4]); \
940                 } else \
941                         search = a->argv[3]; \
942         } \
943         if (max > prof_data->entries) \
944                 max = prof_data->entries;
945
946 static char *handle_show_profile(struct ast_cli_entry *e, int cmd, struct ast_cli_args *a)
947 {
948         int i, min, max;
949         const char *search = NULL;
950         switch (cmd) {
951         case CLI_INIT:
952                 e->command = "core show profile";
953                 e->usage = "Usage: core show profile\n"
954                            "       show profile information";
955                 return NULL;
956         case CLI_GENERATE:
957                 return NULL;
958         }
959
960         if (prof_data == NULL)
961                 return 0;
962
963         DEFINE_PROFILE_MIN_MAX_VALUES;
964         ast_cli(a->fd, "profile values (%d, allocated %d)\n-------------------\n",
965                 prof_data->entries, prof_data->max_size);
966         ast_cli(a->fd, "%6s   %8s  %10s %12s %12s  %s\n", "ID", "Scale", "Events",
967                         "Value", "Average", "Name");
968         for (i = min; i < max; i++) {
969                 struct profile_entry *entry = &prof_data->e[i];
970                 if (!search || strstr(entry->name, search))
971                     ast_cli(a->fd, "%6d: [%8ld] %10ld %12lld %12lld  %s\n",
972                         i,
973                         (long)entry->scale,
974                         (long)entry->events, (long long)entry->value,
975                         (long long)(entry->events ? entry->value / entry->events : entry->value),
976                         entry->name);
977         }
978         return CLI_SUCCESS;
979 }
980
981 static char *handle_clear_profile(struct ast_cli_entry *e, int cmd, struct ast_cli_args *a)
982 {
983         int i, min, max;
984         const char *search = NULL;
985         switch (cmd) {
986         case CLI_INIT:
987                 e->command = "core clear profile";
988                 e->usage = "Usage: core clear profile\n"
989                            "       clear profile information";
990                 return NULL;
991         case CLI_GENERATE:
992                 return NULL;
993         }
994
995         if (prof_data == NULL)
996                 return 0;
997
998         DEFINE_PROFILE_MIN_MAX_VALUES;
999         for (i= min; i < max; i++) {
1000                 if (!search || strstr(prof_data->e[i].name, search)) {
1001                         prof_data->e[i].value = 0;
1002                         prof_data->e[i].events = 0;
1003                 }
1004         }
1005         return CLI_SUCCESS;
1006 }
1007 #undef DEFINE_PROFILE_MIN_MAX_VALUES
1008
1009 /*! \brief CLI command to list module versions */
1010 static char *handle_show_version_files(struct ast_cli_entry *e, int cmd, struct ast_cli_args *a)
1011 {
1012 #define FORMAT "%-25.25s %-40.40s\n"
1013         struct file_version *iterator;
1014         regex_t regexbuf;
1015         int havepattern = 0;
1016         int havename = 0;
1017         int count_files = 0;
1018         char *ret = NULL;
1019         int matchlen, which = 0;
1020         struct file_version *find;
1021
1022         switch (cmd) {
1023         case CLI_INIT:
1024                 e->command = "core show file version [like]";
1025                 e->usage =
1026                         "Usage: core show file version [like <pattern>]\n"
1027                         "       Lists the revision numbers of the files used to build this copy of Asterisk.\n"
1028                         "       Optional regular expression pattern is used to filter the file list.\n";
1029                 return NULL;
1030         case CLI_GENERATE:
1031                 matchlen = strlen(a->word);
1032                 if (a->pos != 3)
1033                         return NULL;
1034                 AST_RWLIST_RDLOCK(&file_versions);
1035                 AST_RWLIST_TRAVERSE(&file_versions, find, list) {
1036                         if (!strncasecmp(a->word, find->file, matchlen) && ++which > a->n) {
1037                                 ret = ast_strdup(find->file);
1038                                 break;
1039                         }
1040                 }
1041                 AST_RWLIST_UNLOCK(&file_versions);
1042                 return ret;
1043         }
1044
1045
1046         switch (a->argc) {
1047         case 6:
1048                 if (!strcasecmp(a->argv[4], "like")) {
1049                         if (regcomp(&regexbuf, a->argv[5], REG_EXTENDED | REG_NOSUB))
1050                                 return CLI_SHOWUSAGE;
1051                         havepattern = 1;
1052                 } else
1053                         return CLI_SHOWUSAGE;
1054                 break;
1055         case 5:
1056                 havename = 1;
1057                 break;
1058         case 4:
1059                 break;
1060         default:
1061                 return CLI_SHOWUSAGE;
1062         }
1063
1064         ast_cli(a->fd, FORMAT, "File", "Revision");
1065         ast_cli(a->fd, FORMAT, "----", "--------");
1066         AST_RWLIST_RDLOCK(&file_versions);
1067         AST_RWLIST_TRAVERSE(&file_versions, iterator, list) {
1068                 if (havename && strcasecmp(iterator->file, a->argv[4]))
1069                         continue;
1070
1071                 if (havepattern && regexec(&regexbuf, iterator->file, 0, NULL, 0))
1072                         continue;
1073
1074                 ast_cli(a->fd, FORMAT, iterator->file, iterator->version);
1075                 count_files++;
1076                 if (havename)
1077                         break;
1078         }
1079         AST_RWLIST_UNLOCK(&file_versions);
1080         if (!havename) {
1081                 ast_cli(a->fd, "%d files listed.\n", count_files);
1082         }
1083
1084         if (havepattern)
1085                 regfree(&regexbuf);
1086
1087         return CLI_SUCCESS;
1088 #undef FORMAT
1089 }
1090
1091 #endif /* ! LOW_MEMORY */
1092
1093 static void publish_fully_booted(void)
1094 {
1095         RAII_VAR(struct ast_json *, json_object, NULL, ast_json_unref);
1096
1097         json_object = ast_json_pack("{s: s}",
1098                         "Status", "Fully Booted");
1099         ast_manager_publish_event("FullyBooted", EVENT_FLAG_SYSTEM, json_object);
1100 }
1101
1102 static void ast_run_atexits(int run_cleanups)
1103 {
1104         struct ast_atexit *ae;
1105
1106         AST_LIST_LOCK(&atexits);
1107         while ((ae = AST_LIST_REMOVE_HEAD(&atexits, list))) {
1108                 if (ae->func && (!ae->is_cleanup || run_cleanups)) {
1109                         ae->func();
1110                 }
1111                 ast_free(ae);
1112         }
1113         AST_LIST_UNLOCK(&atexits);
1114 }
1115
1116 static void __ast_unregister_atexit(void (*func)(void))
1117 {
1118         struct ast_atexit *ae;
1119
1120         AST_LIST_TRAVERSE_SAFE_BEGIN(&atexits, ae, list) {
1121                 if (ae->func == func) {
1122                         AST_LIST_REMOVE_CURRENT(list);
1123                         ast_free(ae);
1124                         break;
1125                 }
1126         }
1127         AST_LIST_TRAVERSE_SAFE_END;
1128 }
1129
1130 static int register_atexit(void (*func)(void), int is_cleanup)
1131 {
1132         struct ast_atexit *ae;
1133
1134         ae = ast_calloc(1, sizeof(*ae));
1135         if (!ae) {
1136                 return -1;
1137         }
1138         ae->func = func;
1139         ae->is_cleanup = is_cleanup;
1140
1141         AST_LIST_LOCK(&atexits);
1142         __ast_unregister_atexit(func);
1143         AST_LIST_INSERT_HEAD(&atexits, ae, list);
1144         AST_LIST_UNLOCK(&atexits);
1145
1146         return 0;
1147 }
1148
1149 int ast_register_atexit(void (*func)(void))
1150 {
1151         return register_atexit(func, 0);
1152 }
1153
1154 int ast_register_cleanup(void (*func)(void))
1155 {
1156         return register_atexit(func, 1);
1157 }
1158
1159 void ast_unregister_atexit(void (*func)(void))
1160 {
1161         AST_LIST_LOCK(&atexits);
1162         __ast_unregister_atexit(func);
1163         AST_LIST_UNLOCK(&atexits);
1164 }
1165
1166 /* Sending commands from consoles back to the daemon requires a terminating NULL */
1167 static int fdsend(int fd, const char *s)
1168 {
1169         return write(fd, s, strlen(s) + 1);
1170 }
1171
1172 /* Sending messages from the daemon back to the display requires _excluding_ the terminating NULL */
1173 static int fdprint(int fd, const char *s)
1174 {
1175         return write(fd, s, strlen(s));
1176 }
1177
1178 /*! \brief NULL handler so we can collect the child exit status */
1179 static void _null_sig_handler(int sig)
1180 {
1181 }
1182
1183 static struct sigaction null_sig_handler = {
1184         .sa_handler = _null_sig_handler,
1185         .sa_flags = SA_RESTART,
1186 };
1187
1188 static struct sigaction ignore_sig_handler = {
1189         .sa_handler = SIG_IGN,
1190 };
1191
1192 AST_MUTEX_DEFINE_STATIC(safe_system_lock);
1193 /*! \brief Keep track of how many threads are currently trying to wait*() on
1194  *  a child process
1195  */
1196 static unsigned int safe_system_level = 0;
1197 static struct sigaction safe_system_prev_handler;
1198
1199 void ast_replace_sigchld(void)
1200 {
1201         unsigned int level;
1202
1203         ast_mutex_lock(&safe_system_lock);
1204         level = safe_system_level++;
1205
1206         /* only replace the handler if it has not already been done */
1207         if (level == 0) {
1208                 sigaction(SIGCHLD, &null_sig_handler, &safe_system_prev_handler);
1209         }
1210
1211         ast_mutex_unlock(&safe_system_lock);
1212 }
1213
1214 void ast_unreplace_sigchld(void)
1215 {
1216         unsigned int level;
1217
1218         ast_mutex_lock(&safe_system_lock);
1219         level = --safe_system_level;
1220
1221         /* only restore the handler if we are the last one */
1222         if (level == 0) {
1223                 sigaction(SIGCHLD, &safe_system_prev_handler, NULL);
1224         }
1225
1226         ast_mutex_unlock(&safe_system_lock);
1227 }
1228
1229 int ast_safe_system(const char *s)
1230 {
1231         pid_t pid;
1232         int res;
1233         struct rusage rusage;
1234         int status;
1235
1236 #if defined(HAVE_WORKING_FORK) || defined(HAVE_WORKING_VFORK)
1237         ast_replace_sigchld();
1238
1239 #ifdef HAVE_WORKING_FORK
1240         pid = fork();
1241 #else
1242         pid = vfork();
1243 #endif
1244
1245         if (pid == 0) {
1246 #ifdef HAVE_CAP
1247                 cap_t cap = cap_from_text("cap_net_admin-eip");
1248
1249                 if (cap_set_proc(cap)) {
1250                         /* Careful with order! Logging cannot happen after we close FDs */
1251                         ast_log(LOG_WARNING, "Unable to remove capabilities.\n");
1252                 }
1253                 cap_free(cap);
1254 #endif
1255 #ifdef HAVE_WORKING_FORK
1256                 if (ast_opt_high_priority)
1257                         ast_set_priority(0);
1258                 /* Close file descriptors and launch system command */
1259                 ast_close_fds_above_n(STDERR_FILENO);
1260 #endif
1261                 execl("/bin/sh", "/bin/sh", "-c", s, (char *) NULL);
1262                 _exit(1);
1263         } else if (pid > 0) {
1264                 for (;;) {
1265                         res = wait4(pid, &status, 0, &rusage);
1266                         if (res > -1) {
1267                                 res = WIFEXITED(status) ? WEXITSTATUS(status) : -1;
1268                                 break;
1269                         } else if (errno != EINTR)
1270                                 break;
1271                 }
1272         } else {
1273                 ast_log(LOG_WARNING, "Fork failed: %s\n", strerror(errno));
1274                 res = -1;
1275         }
1276
1277         ast_unreplace_sigchld();
1278 #else /* !defined(HAVE_WORKING_FORK) && !defined(HAVE_WORKING_VFORK) */
1279         res = -1;
1280 #endif
1281
1282         return res;
1283 }
1284
1285 /*!
1286  * \brief enable or disable a logging level to a specified console
1287  */
1288 void ast_console_toggle_loglevel(int fd, int level, int state)
1289 {
1290         int x;
1291
1292         if (level >= NUMLOGLEVELS) {
1293                 level = NUMLOGLEVELS - 1;
1294         }
1295
1296         for (x = 0;x < AST_MAX_CONNECTS; x++) {
1297                 if (fd == consoles[x].fd) {
1298                         /*
1299                          * Since the logging occurs when levels are false, set to
1300                          * flipped iinput because this function accepts 0 as off and 1 as on
1301                          */
1302                         consoles[x].levels[level] = state ? 0 : 1;
1303                         return;
1304                 }
1305         }
1306 }
1307
1308 /*!
1309  * \brief mute or unmute a console from logging
1310  */
1311 void ast_console_toggle_mute(int fd, int silent)
1312 {
1313         int x;
1314         for (x = 0;x < AST_MAX_CONNECTS; x++) {
1315                 if (fd == consoles[x].fd) {
1316                         if (consoles[x].mute) {
1317                                 consoles[x].mute = 0;
1318                                 if (!silent)
1319                                         ast_cli(fd, "Console is not muted anymore.\n");
1320                         } else {
1321                                 consoles[x].mute = 1;
1322                                 if (!silent)
1323                                         ast_cli(fd, "Console is muted.\n");
1324                         }
1325                         return;
1326                 }
1327         }
1328         ast_cli(fd, "Couldn't find remote console.\n");
1329 }
1330
1331 /*!
1332  * \brief log the string to all attached console clients
1333  */
1334 static void ast_network_puts_mutable(const char *string, int level)
1335 {
1336         int x;
1337         for (x = 0;x < AST_MAX_CONNECTS; x++) {
1338                 if (consoles[x].mute)
1339                         continue;
1340                 if (consoles[x].fd > -1) {
1341                         if (!consoles[x].levels[level])
1342                                 fdprint(consoles[x].p[1], string);
1343                 }
1344         }
1345 }
1346
1347 /*!
1348  * \brief log the string to the console, and all attached
1349  * console clients
1350  */
1351 void ast_console_puts_mutable(const char *string, int level)
1352 {
1353         fputs(string, stdout);
1354         fflush(stdout);
1355         ast_network_puts_mutable(string, level);
1356 }
1357
1358 /*!
1359  * \brief write the string to all attached console clients
1360  */
1361 static void ast_network_puts(const char *string)
1362 {
1363         int x;
1364         for (x = 0; x < AST_MAX_CONNECTS; x++) {
1365                 if (consoles[x].fd > -1)
1366                         fdprint(consoles[x].p[1], string);
1367         }
1368 }
1369
1370 /*!
1371  * \brief write the string to the console, and all attached
1372  * console clients
1373  */
1374 void ast_console_puts(const char *string)
1375 {
1376         fputs(string, stdout);
1377         fflush(stdout);
1378         ast_network_puts(string);
1379 }
1380
1381 static void network_verboser(const char *s)
1382 {
1383         ast_network_puts_mutable(s, __LOG_VERBOSE);
1384 }
1385
1386 static pthread_t lthread;
1387
1388 /*!
1389  * \brief read() function supporting the reception of user credentials.
1390  *
1391  * \param fd Socket file descriptor.
1392  * \param buffer Receive buffer.
1393  * \param size 'buffer' size.
1394  * \param con Console structure to set received credentials
1395  * \retval -1 on error
1396  * \retval the number of bytes received on success.
1397  */
1398 static int read_credentials(int fd, char *buffer, size_t size, struct console *con)
1399 {
1400 #if defined(SO_PEERCRED)
1401 #ifdef HAVE_STRUCT_SOCKPEERCRED_UID
1402 #define HAVE_STRUCT_UCRED_UID
1403         struct sockpeercred cred;
1404 #else
1405         struct ucred cred;
1406 #endif
1407         socklen_t len = sizeof(cred);
1408 #endif
1409 #if defined(HAVE_GETPEEREID)
1410         uid_t uid;
1411         gid_t gid;
1412 #else
1413         int uid, gid;
1414 #endif
1415         int result;
1416
1417         result = read(fd, buffer, size);
1418         if (result < 0) {
1419                 return result;
1420         }
1421
1422 #if defined(SO_PEERCRED) && (defined(HAVE_STRUCT_UCRED_UID) || defined(HAVE_STRUCT_UCRED_CR_UID))
1423         if (getsockopt(fd, SOL_SOCKET, SO_PEERCRED, &cred, &len)) {
1424                 return result;
1425         }
1426 #if defined(HAVE_STRUCT_UCRED_UID)
1427         uid = cred.uid;
1428         gid = cred.gid;
1429 #else /* defined(HAVE_STRUCT_UCRED_CR_UID) */
1430         uid = cred.cr_uid;
1431         gid = cred.cr_gid;
1432 #endif /* defined(HAVE_STRUCT_UCRED_UID) */
1433
1434 #elif defined(HAVE_GETPEEREID)
1435         if (getpeereid(fd, &uid, &gid)) {
1436                 return result;
1437         }
1438 #else
1439         return result;
1440 #endif
1441         con->uid = uid;
1442         con->gid = gid;
1443
1444         return result;
1445 }
1446
1447 static void *netconsole(void *vconsole)
1448 {
1449         struct console *con = vconsole;
1450         char hostname[MAXHOSTNAMELEN] = "";
1451         char inbuf[512];
1452         char outbuf[512];
1453         const char * const end_buf = inbuf + sizeof(inbuf);
1454         char *start_read = inbuf;
1455         int res;
1456         struct pollfd fds[2];
1457
1458         if (gethostname(hostname, sizeof(hostname)-1))
1459                 ast_copy_string(hostname, "<Unknown>", sizeof(hostname));
1460         snprintf(outbuf, sizeof(outbuf), "%s/%ld/%s\n", hostname, (long)ast_mainpid, ast_get_version());
1461         fdprint(con->fd, outbuf);
1462         for (;;) {
1463                 fds[0].fd = con->fd;
1464                 fds[0].events = POLLIN;
1465                 fds[0].revents = 0;
1466                 fds[1].fd = con->p[0];
1467                 fds[1].events = POLLIN;
1468                 fds[1].revents = 0;
1469
1470                 res = ast_poll(fds, 2, -1);
1471                 if (res < 0) {
1472                         if (errno != EINTR)
1473                                 ast_log(LOG_WARNING, "poll returned < 0: %s\n", strerror(errno));
1474                         continue;
1475                 }
1476                 if (fds[0].revents) {
1477                         int cmds_read, bytes_read;
1478                         if ((bytes_read = read_credentials(con->fd, start_read, end_buf - start_read, con)) < 1) {
1479                                 break;
1480                         }
1481                         /* XXX This will only work if it is the first command, and I'm not sure fixing it is worth the effort. */
1482                         if (strncmp(inbuf, "cli quit after ", 15) == 0) {
1483                                 ast_cli_command_multiple_full(con->uid, con->gid, con->fd, bytes_read - 15, inbuf + 15);
1484                                 break;
1485                         }
1486                         /* ast_cli_command_multiple_full will only process individual commands terminated by a
1487                          * NULL and not trailing partial commands. */
1488                         if (!(cmds_read = ast_cli_command_multiple_full(con->uid, con->gid, con->fd, bytes_read + start_read - inbuf, inbuf))) {
1489                                 /* No commands were read. We either have a short read on the first command
1490                                  * with space left, or a command that is too long */
1491                                 if (start_read + bytes_read < end_buf) {
1492                                         start_read += bytes_read;
1493                                 } else {
1494                                         ast_log(LOG_ERROR, "Command too long! Skipping\n");
1495                                         start_read = inbuf;
1496                                 }
1497                                 continue;
1498                         }
1499                         if (start_read[bytes_read - 1] == '\0') {
1500                                 /* The read ended on a command boundary, start reading again at the head of inbuf */
1501                                 start_read = inbuf;
1502                                 continue;
1503                         }
1504                         /* If we get this far, we have left over characters that have not been processed.
1505                          * Advance to the character after the last command read by ast_cli_command_multiple_full.
1506                          * We are guaranteed to have at least cmds_read NULLs */
1507                         while (cmds_read-- && (start_read = strchr(start_read, '\0'))) {
1508                                 start_read++;
1509                         }
1510                         memmove(inbuf, start_read, end_buf - start_read);
1511                         start_read = end_buf - start_read + inbuf;
1512                 }
1513                 if (fds[1].revents) {
1514                         res = read_credentials(con->p[0], outbuf, sizeof(outbuf), con);
1515                         if (res < 1) {
1516                                 ast_log(LOG_ERROR, "read returned %d\n", res);
1517                                 break;
1518                         }
1519                         res = write(con->fd, outbuf, res);
1520                         if (res < 1)
1521                                 break;
1522                 }
1523         }
1524         if (!ast_opt_hide_connect) {
1525                 ast_verb(3, "Remote UNIX connection disconnected\n");
1526         }
1527         close(con->fd);
1528         close(con->p[0]);
1529         close(con->p[1]);
1530         con->fd = -1;
1531
1532         return NULL;
1533 }
1534
1535 static void *listener(void *unused)
1536 {
1537         struct sockaddr_un sunaddr;
1538         int s;
1539         socklen_t len;
1540         int x;
1541         int flags;
1542         struct pollfd fds[1];
1543         for (;;) {
1544                 if (ast_socket < 0)
1545                         return NULL;
1546                 fds[0].fd = ast_socket;
1547                 fds[0].events = POLLIN;
1548                 s = ast_poll(fds, 1, -1);
1549                 pthread_testcancel();
1550                 if (s < 0) {
1551                         if (errno != EINTR)
1552                                 ast_log(LOG_WARNING, "poll returned error: %s\n", strerror(errno));
1553                         continue;
1554                 }
1555                 len = sizeof(sunaddr);
1556                 s = accept(ast_socket, (struct sockaddr *)&sunaddr, &len);
1557                 if (s < 0) {
1558                         if (errno != EINTR)
1559                                 ast_log(LOG_WARNING, "Accept returned %d: %s\n", s, strerror(errno));
1560                 } else {
1561 #if !defined(SO_PASSCRED)
1562                         {
1563 #else
1564                         int sckopt = 1;
1565                         /* turn on socket credentials passing. */
1566                         if (setsockopt(s, SOL_SOCKET, SO_PASSCRED, &sckopt, sizeof(sckopt)) < 0) {
1567                                 ast_log(LOG_WARNING, "Unable to turn on socket credentials passing\n");
1568                         } else {
1569 #endif
1570                                 for (x = 0; x < AST_MAX_CONNECTS; x++) {
1571                                         if (consoles[x].fd >= 0) {
1572                                                 continue;
1573                                         }
1574                                         if (socketpair(AF_LOCAL, SOCK_STREAM, 0, consoles[x].p)) {
1575                                                 ast_log(LOG_ERROR, "Unable to create pipe: %s\n", strerror(errno));
1576                                                 consoles[x].fd = -1;
1577                                                 fdprint(s, "Server failed to create pipe\n");
1578                                                 close(s);
1579                                                 break;
1580                                         }
1581                                         flags = fcntl(consoles[x].p[1], F_GETFL);
1582                                         fcntl(consoles[x].p[1], F_SETFL, flags | O_NONBLOCK);
1583                                         consoles[x].fd = s;
1584                                         consoles[x].mute = 1; /* Default is muted, we will un-mute if necessary */
1585                                         /* Default uid and gid to -2, so then in cli.c/cli_has_permissions() we will be able
1586                                            to know if the user didn't send the credentials. */
1587                                         consoles[x].uid = -2;
1588                                         consoles[x].gid = -2;
1589                                         if (ast_pthread_create_detached_background(&consoles[x].t, NULL, netconsole, &consoles[x])) {
1590                                                 ast_log(LOG_ERROR, "Unable to spawn thread to handle connection: %s\n", strerror(errno));
1591                                                 close(consoles[x].p[0]);
1592                                                 close(consoles[x].p[1]);
1593                                                 consoles[x].fd = -1;
1594                                                 fdprint(s, "Server failed to spawn thread\n");
1595                                                 close(s);
1596                                         }
1597                                         break;
1598                                 }
1599                                 if (x >= AST_MAX_CONNECTS) {
1600                                         fdprint(s, "No more connections allowed\n");
1601                                         ast_log(LOG_WARNING, "No more connections allowed\n");
1602                                         close(s);
1603                                 } else if ((consoles[x].fd > -1) && (!ast_opt_hide_connect)) {
1604                                         ast_verb(3, "Remote UNIX connection\n");
1605                                 }
1606                         }
1607                 }
1608         }
1609         return NULL;
1610 }
1611
1612 static int ast_makesocket(void)
1613 {
1614         struct sockaddr_un sunaddr;
1615         int res;
1616         int x;
1617         uid_t uid = -1;
1618         gid_t gid = -1;
1619
1620         for (x = 0; x < AST_MAX_CONNECTS; x++)
1621                 consoles[x].fd = -1;
1622         unlink(ast_config_AST_SOCKET);
1623         ast_socket = socket(PF_LOCAL, SOCK_STREAM, 0);
1624         if (ast_socket < 0) {
1625                 ast_log(LOG_WARNING, "Unable to create control socket: %s\n", strerror(errno));
1626                 return -1;
1627         }
1628         memset(&sunaddr, 0, sizeof(sunaddr));
1629         sunaddr.sun_family = AF_LOCAL;
1630         ast_copy_string(sunaddr.sun_path, ast_config_AST_SOCKET, sizeof(sunaddr.sun_path));
1631         res = bind(ast_socket, (struct sockaddr *)&sunaddr, sizeof(sunaddr));
1632         if (res) {
1633                 ast_log(LOG_WARNING, "Unable to bind socket to %s: %s\n", ast_config_AST_SOCKET, strerror(errno));
1634                 close(ast_socket);
1635                 ast_socket = -1;
1636                 return -1;
1637         }
1638         res = listen(ast_socket, 2);
1639         if (res < 0) {
1640                 ast_log(LOG_WARNING, "Unable to listen on socket %s: %s\n", ast_config_AST_SOCKET, strerror(errno));
1641                 close(ast_socket);
1642                 ast_socket = -1;
1643                 return -1;
1644         }
1645         if (ast_register_verbose(network_verboser)) {
1646                 ast_log(LOG_WARNING, "Unable to register network verboser?\n");
1647         }
1648
1649         if (ast_pthread_create_background(&lthread, NULL, listener, NULL)) {
1650                 ast_log(LOG_WARNING, "Unable to create listener thread.\n");
1651                 close(ast_socket);
1652                 return -1;
1653         }
1654
1655         if (!ast_strlen_zero(ast_config_AST_CTL_OWNER)) {
1656                 struct passwd *pw;
1657                 if ((pw = getpwnam(ast_config_AST_CTL_OWNER)) == NULL)
1658                         ast_log(LOG_WARNING, "Unable to find uid of user %s\n", ast_config_AST_CTL_OWNER);
1659                 else
1660                         uid = pw->pw_uid;
1661         }
1662
1663         if (!ast_strlen_zero(ast_config_AST_CTL_GROUP)) {
1664                 struct group *grp;
1665                 if ((grp = getgrnam(ast_config_AST_CTL_GROUP)) == NULL)
1666                         ast_log(LOG_WARNING, "Unable to find gid of group %s\n", ast_config_AST_CTL_GROUP);
1667                 else
1668                         gid = grp->gr_gid;
1669         }
1670
1671         if (chown(ast_config_AST_SOCKET, uid, gid) < 0)
1672                 ast_log(LOG_WARNING, "Unable to change ownership of %s: %s\n", ast_config_AST_SOCKET, strerror(errno));
1673
1674         if (!ast_strlen_zero(ast_config_AST_CTL_PERMISSIONS)) {
1675                 int p1;
1676                 mode_t p;
1677                 sscanf(ast_config_AST_CTL_PERMISSIONS, "%30o", &p1);
1678                 p = p1;
1679                 if ((chmod(ast_config_AST_SOCKET, p)) < 0)
1680                         ast_log(LOG_WARNING, "Unable to change file permissions of %s: %s\n", ast_config_AST_SOCKET, strerror(errno));
1681         }
1682
1683         return 0;
1684 }
1685
1686 static int ast_tryconnect(void)
1687 {
1688         struct sockaddr_un sunaddr;
1689         int res;
1690         ast_consock = socket(PF_LOCAL, SOCK_STREAM, 0);
1691         if (ast_consock < 0) {
1692                 fprintf(stderr, "Unable to create socket: %s\n", strerror(errno));
1693                 return 0;
1694         }
1695         memset(&sunaddr, 0, sizeof(sunaddr));
1696         sunaddr.sun_family = AF_LOCAL;
1697         ast_copy_string(sunaddr.sun_path, ast_config_AST_SOCKET, sizeof(sunaddr.sun_path));
1698         res = connect(ast_consock, (struct sockaddr *)&sunaddr, sizeof(sunaddr));
1699         if (res) {
1700                 close(ast_consock);
1701                 ast_consock = -1;
1702                 return 0;
1703         } else
1704                 return 1;
1705 }
1706
1707 /*! \brief Urgent handler
1708  *
1709  * Called by soft_hangup to interrupt the poll, read, or other
1710  * system call.  We don't actually need to do anything though.
1711  * Remember: Cannot EVER ast_log from within a signal handler
1712  */
1713 static void _urg_handler(int num)
1714 {
1715         return;
1716 }
1717
1718 static struct sigaction urg_handler = {
1719         .sa_handler = _urg_handler,
1720         .sa_flags = SA_RESTART,
1721 };
1722
1723 static void _hup_handler(int num)
1724 {
1725         int a = 0, save_errno = errno;
1726         printf("Received HUP signal -- Reloading configs\n");
1727         if (restartnow)
1728                 execvp(_argv[0], _argv);
1729         sig_flags.need_reload = 1;
1730         if (sig_alert_pipe[1] != -1) {
1731                 if (write(sig_alert_pipe[1], &a, sizeof(a)) < 0) {
1732                         fprintf(stderr, "hup_handler: write() failed: %s\n", strerror(errno));
1733                 }
1734         }
1735         errno = save_errno;
1736 }
1737
1738 static struct sigaction hup_handler = {
1739         .sa_handler = _hup_handler,
1740         .sa_flags = SA_RESTART,
1741 };
1742
1743 static void _child_handler(int sig)
1744 {
1745         /* Must not ever ast_log or ast_verbose within signal handler */
1746         int n, status, save_errno = errno;
1747
1748         /*
1749          * Reap all dead children -- not just one
1750          */
1751         for (n = 0; wait4(-1, &status, WNOHANG, NULL) > 0; n++)
1752                 ;
1753         if (n == 0 && option_debug)
1754                 printf("Huh?  Child handler, but nobody there?\n");
1755         errno = save_errno;
1756 }
1757
1758 static struct sigaction child_handler = {
1759         .sa_handler = _child_handler,
1760         .sa_flags = SA_RESTART,
1761 };
1762
1763 /*! \brief Set maximum open files */
1764 static void set_ulimit(int value)
1765 {
1766         struct rlimit l = {0, 0};
1767
1768         if (value <= 0) {
1769                 ast_log(LOG_WARNING, "Unable to change max files open to invalid value %i\n",value);
1770                 return;
1771         }
1772
1773         l.rlim_cur = value;
1774         l.rlim_max = value;
1775
1776         if (setrlimit(RLIMIT_NOFILE, &l)) {
1777                 ast_log(LOG_WARNING, "Unable to disable core size resource limit: %s\n",strerror(errno));
1778                 return;
1779         }
1780
1781         ast_log(LOG_NOTICE, "Setting max files open to %d\n",value);
1782
1783         return;
1784 }
1785
1786 /*! \brief Set an X-term or screen title */
1787 static void set_title(char *text)
1788 {
1789         if (getenv("TERM") && strstr(getenv("TERM"), "xterm"))
1790                 fprintf(stdout, "\033]2;%s\007", text);
1791 }
1792
1793 static void set_icon(char *text)
1794 {
1795         if (getenv("TERM") && strstr(getenv("TERM"), "xterm"))
1796                 fprintf(stdout, "\033]1;%s\007", text);
1797 }
1798
1799 /*! \brief We set ourselves to a high priority, that we might pre-empt
1800  * everything else.  If your PBX has heavy activity on it, this is a
1801  * good thing.
1802  */
1803 int ast_set_priority(int pri)
1804 {
1805         struct sched_param sched;
1806         memset(&sched, 0, sizeof(sched));
1807 #ifdef __linux__
1808         if (pri) {
1809                 sched.sched_priority = 10;
1810                 if (sched_setscheduler(0, SCHED_RR, &sched)) {
1811                         ast_log(LOG_WARNING, "Unable to set high priority\n");
1812                         return -1;
1813                 } else
1814                         ast_verb(1, "Set to realtime thread\n");
1815         } else {
1816                 sched.sched_priority = 0;
1817                 /* According to the manpage, these parameters can never fail. */
1818                 sched_setscheduler(0, SCHED_OTHER, &sched);
1819         }
1820 #else
1821         if (pri) {
1822                 if (setpriority(PRIO_PROCESS, 0, -10) == -1) {
1823                         ast_log(LOG_WARNING, "Unable to set high priority\n");
1824                         return -1;
1825                 } else
1826                         ast_verb(1, "Set to high priority\n");
1827         } else {
1828                 /* According to the manpage, these parameters can never fail. */
1829                 setpriority(PRIO_PROCESS, 0, 0);
1830         }
1831 #endif
1832         return 0;
1833 }
1834
1835 static int can_safely_quit(shutdown_nice_t niceness, int restart);
1836 static void really_quit(int num, shutdown_nice_t niceness, int restart);
1837
1838 static void quit_handler(int num, shutdown_nice_t niceness, int restart)
1839 {
1840         if (can_safely_quit(niceness, restart)) {
1841                 really_quit(num, niceness, restart);
1842                 /* No one gets here. */
1843         }
1844         /* It wasn't our time. */
1845 }
1846
1847 static int can_safely_quit(shutdown_nice_t niceness, int restart)
1848 {
1849         /* Check if someone else isn't already doing this. */
1850         ast_mutex_lock(&safe_system_lock);
1851         if (shuttingdown != NOT_SHUTTING_DOWN && niceness >= shuttingdown) {
1852                 /* Already in progress and other request was less nice. */
1853                 ast_mutex_unlock(&safe_system_lock);
1854                 ast_verbose("Ignoring asterisk %s request, already in progress.\n", restart ? "restart" : "shutdown");
1855                 return 0;
1856         }
1857         shuttingdown = niceness;
1858         ast_mutex_unlock(&safe_system_lock);
1859
1860         /* Try to get as many CDRs as possible submitted to the backend engines
1861          * (if in batch mode). really_quit happens to call it again when running
1862          * the atexit handlers, otherwise this would be a bit early. */
1863         ast_cdr_engine_term();
1864
1865         /* Shutdown the message queue for the technology agnostic message channel.
1866          * This has to occur before we pause shutdown pending ast_undestroyed_channels. */
1867         ast_msg_shutdown();
1868
1869         if (niceness == SHUTDOWN_NORMAL) {
1870                 time_t s, e;
1871                 /* Begin shutdown routine, hanging up active channels */
1872                 ast_begin_shutdown(1);
1873                 if (option_verbose && ast_opt_console) {
1874                         ast_verbose("Beginning asterisk %s....\n", restart ? "restart" : "shutdown");
1875                 }
1876                 time(&s);
1877                 for (;;) {
1878                         time(&e);
1879                         /* Wait up to 15 seconds for all channels to go away */
1880                         if ((e - s) > 15 || !ast_undestroyed_channels() || shuttingdown != niceness) {
1881                                 break;
1882                         }
1883                         /* Sleep 1/10 of a second */
1884                         usleep(100000);
1885                 }
1886         } else if (niceness >= SHUTDOWN_NICE) {
1887                 if (niceness != SHUTDOWN_REALLY_NICE) {
1888                         ast_begin_shutdown(0);
1889                 }
1890                 if (option_verbose && ast_opt_console) {
1891                         ast_verb(0, "Waiting for inactivity to perform %s...\n", restart ? "restart" : "halt");
1892                 }
1893                 for (;;) {
1894                         if (!ast_undestroyed_channels() || shuttingdown != niceness) {
1895                                 break;
1896                         }
1897                         sleep(1);
1898                 }
1899         }
1900
1901         /* Re-acquire lock and check if someone changed the niceness, in which
1902          * case someone else has taken over the shutdown.
1903          */
1904         ast_mutex_lock(&safe_system_lock);
1905         if (shuttingdown != niceness) {
1906                 if (shuttingdown == NOT_SHUTTING_DOWN && option_verbose && ast_opt_console) {
1907                         ast_verb(0, "Asterisk %s cancelled.\n", restart ? "restart" : "shutdown");
1908                 }
1909                 ast_mutex_unlock(&safe_system_lock);
1910                 return 0;
1911         }
1912         shuttingdown = SHUTTING_DOWN;
1913         ast_mutex_unlock(&safe_system_lock);
1914
1915         return 1;
1916 }
1917
1918 /*! Called when exiting is certain. */
1919 static void really_quit(int num, shutdown_nice_t niceness, int restart)
1920 {
1921         int active_channels;
1922         RAII_VAR(struct ast_json *, json_object, NULL, ast_json_unref);
1923         int run_cleanups = niceness >= SHUTDOWN_NICE;
1924
1925         if (run_cleanups) {
1926                 ast_module_shutdown();
1927         }
1928
1929         if (ast_opt_console || (ast_opt_remote && !ast_opt_exec)) {
1930                 char filename[80] = "";
1931                 if (getenv("HOME")) {
1932                         snprintf(filename, sizeof(filename), "%s/.asterisk_history", getenv("HOME"));
1933                 }
1934                 if (!ast_strlen_zero(filename)) {
1935                         ast_el_write_history(filename);
1936                 }
1937                 if (consolethread == AST_PTHREADT_NULL || consolethread == pthread_self()) {
1938                         /* Only end if we are the consolethread, otherwise there's a race with that thread. */
1939                         if (el != NULL) {
1940                                 el_end(el);
1941                         }
1942                         if (el_hist != NULL) {
1943                                 history_end(el_hist);
1944                         }
1945                 } else if (mon_sig_flags == pthread_self()) {
1946                         if (consolethread != AST_PTHREADT_NULL) {
1947                                 pthread_kill(consolethread, SIGURG);
1948                         }
1949                 }
1950         }
1951         active_channels = ast_active_channels();
1952         /* Don't publish messages if we're a remote console - we won't have all of the Stasis
1953          * topics or message types
1954          */
1955         if (!ast_opt_remote) {
1956                 json_object = ast_json_pack("{s: s, s: s}",
1957                                 "Shutdown", active_channels ? "Uncleanly" : "Cleanly",
1958                                 "Restart", restart ? "True" : "False");
1959                 ast_manager_publish_event("Shutdown", EVENT_FLAG_SYSTEM, json_object);
1960         }
1961         ast_verb(0, "Asterisk %s ending (%d).\n",
1962                 active_channels ? "uncleanly" : "cleanly", num);
1963
1964         ast_verb(0, "Executing last minute cleanups\n");
1965         ast_run_atexits(run_cleanups);
1966
1967         ast_debug(1, "Asterisk ending (%d).\n", num);
1968         if (ast_socket > -1) {
1969                 pthread_cancel(lthread);
1970                 close(ast_socket);
1971                 ast_socket = -1;
1972                 unlink(ast_config_AST_SOCKET);
1973         }
1974         if (ast_consock > -1)
1975                 close(ast_consock);
1976         if (!ast_opt_remote)
1977                 unlink(ast_config_AST_PID);
1978         printf("%s", term_quit());
1979         if (restart) {
1980                 int i;
1981                 ast_verb(0, "Preparing for Asterisk restart...\n");
1982                 /* Mark all FD's for closing on exec */
1983                 for (i = 3; i < 32768; i++) {
1984                         fcntl(i, F_SETFD, FD_CLOEXEC);
1985                 }
1986                 ast_verb(0, "Asterisk is now restarting...\n");
1987                 restartnow = 1;
1988
1989                 /* close logger */
1990                 close_logger();
1991                 clean_time_zones();
1992
1993                 /* If there is a consolethread running send it a SIGHUP
1994                    so it can execvp, otherwise we can do it ourselves */
1995                 if ((consolethread != AST_PTHREADT_NULL) && (consolethread != pthread_self())) {
1996                         pthread_kill(consolethread, SIGHUP);
1997                         /* Give the signal handler some time to complete */
1998                         sleep(2);
1999                 } else
2000                         execvp(_argv[0], _argv);
2001
2002         } else {
2003                 /* close logger */
2004                 close_logger();
2005                 clean_time_zones();
2006         }
2007
2008         exit(0);
2009 }
2010
2011 static void __quit_handler(int num)
2012 {
2013         int a = 0;
2014         sig_flags.need_quit = 1;
2015         if (sig_alert_pipe[1] != -1) {
2016                 if (write(sig_alert_pipe[1], &a, sizeof(a)) < 0) {
2017                         fprintf(stderr, "quit_handler: write() failed: %s\n", strerror(errno));
2018                 }
2019         }
2020         /* There is no need to restore the signal handler here, since the app
2021          * is going to exit */
2022 }
2023
2024 static void __remote_quit_handler(int num)
2025 {
2026         sig_flags.need_quit = 1;
2027 }
2028
2029 static const char *fix_header(char *outbuf, int maxout, const char *s, char *cmp)
2030 {
2031         const char *c;
2032
2033         if (!strncmp(s, cmp, strlen(cmp))) {
2034                 c = s + strlen(cmp);
2035                 term_color(outbuf, cmp, COLOR_GRAY, 0, maxout);
2036                 return c;
2037         }
2038         return NULL;
2039 }
2040
2041 /* These gymnastics are due to platforms which designate char as unsigned by
2042  * default. Level is the negative character -- offset by 1, because \0 is the
2043  * EOS delimiter. */
2044 #define VERBOSE_MAGIC2LEVEL(x) (((char) -*(signed char *) (x)) - 1)
2045 #define VERBOSE_HASMAGIC(x)     (*(signed char *) (x) < 0)
2046
2047 static void console_verboser(const char *s)
2048 {
2049         char tmp[80];
2050         const char *c = NULL;
2051         char level = 0;
2052
2053         if (VERBOSE_HASMAGIC(s)) {
2054                 level = VERBOSE_MAGIC2LEVEL(s);
2055                 s++;
2056                 if (level > option_verbose) {
2057                         return;
2058                 }
2059         }
2060
2061         if ((c = fix_header(tmp, sizeof(tmp), s, VERBOSE_PREFIX_4)) ||
2062             (c = fix_header(tmp, sizeof(tmp), s, VERBOSE_PREFIX_3)) ||
2063             (c = fix_header(tmp, sizeof(tmp), s, VERBOSE_PREFIX_2)) ||
2064             (c = fix_header(tmp, sizeof(tmp), s, VERBOSE_PREFIX_1))) {
2065                 fputs(tmp, stdout);
2066                 fputs(c, stdout);
2067         } else {
2068                 fputs(s, stdout);
2069         }
2070
2071         fflush(stdout);
2072
2073         /* Wake up a poll()ing console */
2074         if (ast_opt_console && consolethread != AST_PTHREADT_NULL) {
2075                 pthread_kill(consolethread, SIGURG);
2076         }
2077 }
2078
2079 static int ast_all_zeros(char *s)
2080 {
2081         while (*s) {
2082                 if (*s > 32)
2083                         return 0;
2084                 s++;
2085         }
2086         return 1;
2087 }
2088
2089 static void consolehandler(char *s)
2090 {
2091         printf("%s", term_end());
2092         fflush(stdout);
2093
2094         /* Called when readline data is available */
2095         if (!ast_all_zeros(s))
2096                 ast_el_add_history(s);
2097         /* The real handler for bang */
2098         if (s[0] == '!') {
2099                 if (s[1])
2100                         ast_safe_system(s+1);
2101                 else
2102                         ast_safe_system(getenv("SHELL") ? getenv("SHELL") : "/bin/sh");
2103         } else
2104                 ast_cli_command(STDOUT_FILENO, s);
2105 }
2106
2107 static int remoteconsolehandler(char *s)
2108 {
2109         int ret = 0;
2110
2111         /* Called when readline data is available */
2112         if (!ast_all_zeros(s))
2113                 ast_el_add_history(s);
2114         /* The real handler for bang */
2115         if (s[0] == '!') {
2116                 if (s[1])
2117                         ast_safe_system(s+1);
2118                 else
2119                         ast_safe_system(getenv("SHELL") ? getenv("SHELL") : "/bin/sh");
2120                 ret = 1;
2121         } else if (strncasecmp(s, "core set verbose ", 17) == 0) {
2122                 int old_verbose = option_verbose;
2123                 if (strncasecmp(s + 17, "atleast ", 8) == 0) {
2124                         int tmp;
2125                         if (sscanf(s + 25, "%d", &tmp) != 1) {
2126                                 fprintf(stderr, "Usage: core set verbose [atleast] <level>\n");
2127                         } else {
2128                                 if (tmp > option_verbose) {
2129                                         option_verbose = tmp;
2130                                 }
2131                                 if (old_verbose != option_verbose) {
2132                                         fprintf(stdout, "Set remote console verbosity from %d to %d\n", old_verbose, option_verbose);
2133                                 } else {
2134                                         fprintf(stdout, "Verbosity level unchanged.\n");
2135                                 }
2136                         }
2137                 } else {
2138                         if (sscanf(s + 17, "%d", &option_verbose) != 1) {
2139                                 fprintf(stderr, "Usage: core set verbose [atleast] <level>\n");
2140                         } else {
2141                                 if (old_verbose != option_verbose) {
2142                                         fprintf(stdout, "Set remote console verbosity to %d\n", option_verbose);
2143                                 } else {
2144                                         fprintf(stdout, "Verbosity level unchanged.\n");
2145                                 }
2146                         }
2147                 }
2148                 ret = 1;
2149         } else if ((strncasecmp(s, "quit", 4) == 0 || strncasecmp(s, "exit", 4) == 0) &&
2150             (s[4] == '\0' || isspace(s[4]))) {
2151                 quit_handler(0, SHUTDOWN_FAST, 0);
2152                 ret = 1;
2153         }
2154
2155         return ret;
2156 }
2157
2158 static char *handle_version(struct ast_cli_entry *e, int cmd, struct ast_cli_args *a)
2159 {
2160         switch (cmd) {
2161         case CLI_INIT:
2162                 e->command = "core show version";
2163                 e->usage =
2164                         "Usage: core show version\n"
2165                         "       Shows Asterisk version information.\n";
2166                 return NULL;
2167         case CLI_GENERATE:
2168                 return NULL;
2169         }
2170
2171         if (a->argc != 3)
2172                 return CLI_SHOWUSAGE;
2173         ast_cli(a->fd, "Asterisk %s built by %s @ %s on a %s running %s on %s\n",
2174                 ast_get_version(), ast_build_user, ast_build_hostname,
2175                 ast_build_machine, ast_build_os, ast_build_date);
2176         return CLI_SUCCESS;
2177 }
2178
2179 #if 0
2180 static int handle_quit(int fd, int argc, char *argv[])
2181 {
2182         if (argc != 1)
2183                 return RESULT_SHOWUSAGE;
2184         quit_handler(0, SHUTDOWN_NORMAL, 0);
2185         return RESULT_SUCCESS;
2186 }
2187 #endif
2188
2189 static char *handle_stop_now(struct ast_cli_entry *e, int cmd, struct ast_cli_args *a)
2190 {
2191         switch (cmd) {
2192         case CLI_INIT:
2193                 e->command = "core stop now";
2194                 e->usage =
2195                         "Usage: core stop now\n"
2196                         "       Shuts down a running Asterisk immediately, hanging up all active calls .\n";
2197                 return NULL;
2198         case CLI_GENERATE:
2199                 return NULL;
2200         }
2201
2202         if (a->argc != e->args)
2203                 return CLI_SHOWUSAGE;
2204         quit_handler(0, SHUTDOWN_NORMAL, 0 /* not restart */);
2205         return CLI_SUCCESS;
2206 }
2207
2208 static char *handle_stop_gracefully(struct ast_cli_entry *e, int cmd, struct ast_cli_args *a)
2209 {
2210         switch (cmd) {
2211         case CLI_INIT:
2212                 e->command = "core stop gracefully";
2213                 e->usage =
2214                         "Usage: core stop gracefully\n"
2215                         "       Causes Asterisk to not accept new calls, and exit when all\n"
2216                         "       active calls have terminated normally.\n";
2217                 return NULL;
2218         case CLI_GENERATE:
2219                 return NULL;
2220         }
2221
2222         if (a->argc != e->args)
2223                 return CLI_SHOWUSAGE;
2224         quit_handler(0, SHUTDOWN_NICE, 0 /* no restart */);
2225         return CLI_SUCCESS;
2226 }
2227
2228 static char *handle_stop_when_convenient(struct ast_cli_entry *e, int cmd, struct ast_cli_args *a)
2229 {
2230         switch (cmd) {
2231         case CLI_INIT:
2232                 e->command = "core stop when convenient";
2233                 e->usage =
2234                         "Usage: core stop when convenient\n"
2235                         "       Causes Asterisk to perform a shutdown when all active calls have ended.\n";
2236                 return NULL;
2237         case CLI_GENERATE:
2238                 return NULL;
2239         }
2240
2241         if (a->argc != e->args)
2242                 return CLI_SHOWUSAGE;
2243         ast_cli(a->fd, "Waiting for inactivity to perform halt\n");
2244         quit_handler(0, SHUTDOWN_REALLY_NICE, 0 /* don't restart */);
2245         return CLI_SUCCESS;
2246 }
2247
2248 static char *handle_restart_now(struct ast_cli_entry *e, int cmd, struct ast_cli_args *a)
2249 {
2250         switch (cmd) {
2251         case CLI_INIT:
2252                 e->command = "core restart now";
2253                 e->usage =
2254                         "Usage: core restart now\n"
2255                         "       Causes Asterisk to hangup all calls and exec() itself performing a cold\n"
2256                         "       restart.\n";
2257                 return NULL;
2258         case CLI_GENERATE:
2259                 return NULL;
2260         }
2261
2262         if (a->argc != e->args)
2263                 return CLI_SHOWUSAGE;
2264         quit_handler(0, SHUTDOWN_NORMAL, 1 /* restart */);
2265         return CLI_SUCCESS;
2266 }
2267
2268 static char *handle_restart_gracefully(struct ast_cli_entry *e, int cmd, struct ast_cli_args *a)
2269 {
2270         switch (cmd) {
2271         case CLI_INIT:
2272                 e->command = "core restart gracefully";
2273                 e->usage =
2274                         "Usage: core restart gracefully\n"
2275                         "       Causes Asterisk to stop accepting new calls and exec() itself performing a cold\n"
2276                         "       restart when all active calls have ended.\n";
2277                 return NULL;
2278         case CLI_GENERATE:
2279                 return NULL;
2280         }
2281
2282         if (a->argc != e->args)
2283                 return CLI_SHOWUSAGE;
2284         quit_handler(0, SHUTDOWN_NICE, 1 /* restart */);
2285         return CLI_SUCCESS;
2286 }
2287
2288 static char *handle_restart_when_convenient(struct ast_cli_entry *e, int cmd, struct ast_cli_args *a)
2289 {
2290         switch (cmd) {
2291         case CLI_INIT:
2292                 e->command = "core restart when convenient";
2293                 e->usage =
2294                         "Usage: core restart when convenient\n"
2295                         "       Causes Asterisk to perform a cold restart when all active calls have ended.\n";
2296                 return NULL;
2297         case CLI_GENERATE:
2298                 return NULL;
2299         }
2300
2301         if (a->argc != e->args)
2302                 return CLI_SHOWUSAGE;
2303         ast_cli(a->fd, "Waiting for inactivity to perform restart\n");
2304         quit_handler(0, SHUTDOWN_REALLY_NICE, 1 /* restart */);
2305         return CLI_SUCCESS;
2306 }
2307
2308 static char *handle_abort_shutdown(struct ast_cli_entry *e, int cmd, struct ast_cli_args *a)
2309 {
2310         int aborting_shutdown = 0;
2311
2312         switch (cmd) {
2313         case CLI_INIT:
2314                 e->command = "core abort shutdown";
2315                 e->usage =
2316                         "Usage: core abort shutdown\n"
2317                         "       Causes Asterisk to abort an executing shutdown or restart, and resume normal\n"
2318                         "       call operations.\n";
2319                 return NULL;
2320         case CLI_GENERATE:
2321                 return NULL;
2322         }
2323
2324         if (a->argc != e->args)
2325                 return CLI_SHOWUSAGE;
2326
2327         ast_mutex_lock(&safe_system_lock);
2328         if (shuttingdown >= SHUTDOWN_FAST) {
2329                 aborting_shutdown = 1;
2330                 shuttingdown = NOT_SHUTTING_DOWN;
2331         }
2332         ast_mutex_unlock(&safe_system_lock);
2333
2334         if (aborting_shutdown) {
2335                 ast_cancel_shutdown();
2336         }
2337         return CLI_SUCCESS;
2338 }
2339
2340 static char *handle_bang(struct ast_cli_entry *e, int cmd, struct ast_cli_args *a)
2341 {
2342         switch (cmd) {
2343         case CLI_INIT:
2344                 e->command = "!";
2345                 e->usage =
2346                         "Usage: !<command>\n"
2347                         "       Executes a given shell command\n";
2348                 return NULL;
2349         case CLI_GENERATE:
2350                 return NULL;
2351         }
2352
2353         return CLI_SUCCESS;
2354 }
2355 static const char warranty_lines[] = {
2356         "\n"
2357         "                           NO WARRANTY\n"
2358         "\n"
2359         "BECAUSE THE PROGRAM IS LICENSED FREE OF CHARGE, THERE IS NO WARRANTY\n"
2360         "FOR THE PROGRAM, TO THE EXTENT PERMITTED BY APPLICABLE LAW.  EXCEPT WHEN\n"
2361         "OTHERWISE STATED IN WRITING THE COPYRIGHT HOLDERS AND/OR OTHER PARTIES\n"
2362         "PROVIDE THE PROGRAM \"AS IS\" WITHOUT WARRANTY OF ANY KIND, EITHER EXPRESSED\n"
2363         "OR IMPLIED, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF\n"
2364         "MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE.  THE ENTIRE RISK AS\n"
2365         "TO THE QUALITY AND PERFORMANCE OF THE PROGRAM IS WITH YOU.  SHOULD THE\n"
2366         "PROGRAM PROVE DEFECTIVE, YOU ASSUME THE COST OF ALL NECESSARY SERVICING,\n"
2367         "REPAIR OR CORRECTION.\n"
2368         "\n"
2369         "IN NO EVENT UNLESS REQUIRED BY APPLICABLE LAW OR AGREED TO IN WRITING\n"
2370         "WILL ANY COPYRIGHT HOLDER, OR ANY OTHER PARTY WHO MAY MODIFY AND/OR\n"
2371         "REDISTRIBUTE THE PROGRAM AS PERMITTED ABOVE, BE LIABLE TO YOU FOR DAMAGES,\n"
2372         "INCLUDING ANY GENERAL, SPECIAL, INCIDENTAL OR CONSEQUENTIAL DAMAGES ARISING\n"
2373         "OUT OF THE USE OR INABILITY TO USE THE PROGRAM (INCLUDING BUT NOT LIMITED\n"
2374         "TO LOSS OF DATA OR DATA BEING RENDERED INACCURATE OR LOSSES SUSTAINED BY\n"
2375         "YOU OR THIRD PARTIES OR A FAILURE OF THE PROGRAM TO OPERATE WITH ANY OTHER\n"
2376         "PROGRAMS), EVEN IF SUCH HOLDER OR OTHER PARTY HAS BEEN ADVISED OF THE\n"
2377         "POSSIBILITY OF SUCH DAMAGES.\n"
2378 };
2379
2380 static char *show_warranty(struct ast_cli_entry *e, int cmd, struct ast_cli_args *a)
2381 {
2382         switch (cmd) {
2383         case CLI_INIT:
2384                 e->command = "core show warranty";
2385                 e->usage =
2386                         "Usage: core show warranty\n"
2387                         "       Shows the warranty (if any) for this copy of Asterisk.\n";
2388                 return NULL;
2389         case CLI_GENERATE:
2390                 return NULL;
2391         }
2392
2393         ast_cli(a->fd, "%s", warranty_lines);
2394
2395         return CLI_SUCCESS;
2396 }
2397
2398 static const char license_lines[] = {
2399         "\n"
2400         "This program is free software; you can redistribute it and/or modify\n"
2401         "it under the terms of the GNU General Public License version 2 as\n"
2402         "published by the Free Software Foundation.\n"
2403         "\n"
2404         "This program also contains components licensed under other licenses.\n"
2405         "They include:\n"
2406         "\n"
2407         "This program is distributed in the hope that it will be useful,\n"
2408         "but WITHOUT ANY WARRANTY; without even the implied warranty of\n"
2409         "MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the\n"
2410         "GNU General Public License for more details.\n"
2411         "\n"
2412         "You should have received a copy of the GNU General Public License\n"
2413         "along with this program; if not, write to the Free Software\n"
2414         "Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA\n"
2415 };
2416
2417 static char *show_license(struct ast_cli_entry *e, int cmd, struct ast_cli_args *a)
2418 {
2419         switch (cmd) {
2420         case CLI_INIT:
2421                 e->command = "core show license";
2422                 e->usage =
2423                         "Usage: core show license\n"
2424                         "       Shows the license(s) for this copy of Asterisk.\n";
2425                 return NULL;
2426         case CLI_GENERATE:
2427                 return NULL;
2428         }
2429
2430         ast_cli(a->fd, "%s", license_lines);
2431
2432         return CLI_SUCCESS;
2433 }
2434
2435 #define ASTERISK_PROMPT "*CLI> "
2436
2437 #define ASTERISK_PROMPT2 "%s*CLI> "
2438
2439 /*!
2440  * \brief Shutdown Asterisk CLI commands.
2441  *
2442  * \note These CLI commands cannot be unregistered at shutdown
2443  * because one of them is likely the reason for the shutdown.
2444  * The CLI generates a warning if a command is in-use when it is
2445  * unregistered.
2446  */
2447 static struct ast_cli_entry cli_asterisk_shutdown[] = {
2448         AST_CLI_DEFINE(handle_stop_now, "Shut down Asterisk immediately"),
2449         AST_CLI_DEFINE(handle_stop_gracefully, "Gracefully shut down Asterisk"),
2450         AST_CLI_DEFINE(handle_stop_when_convenient, "Shut down Asterisk at empty call volume"),
2451         AST_CLI_DEFINE(handle_restart_now, "Restart Asterisk immediately"),
2452         AST_CLI_DEFINE(handle_restart_gracefully, "Restart Asterisk gracefully"),
2453         AST_CLI_DEFINE(handle_restart_when_convenient, "Restart Asterisk at empty call volume"),
2454 };
2455
2456 static struct ast_cli_entry cli_asterisk[] = {
2457         AST_CLI_DEFINE(handle_abort_shutdown, "Cancel a running shutdown"),
2458         AST_CLI_DEFINE(show_warranty, "Show the warranty (if any) for this copy of Asterisk"),
2459         AST_CLI_DEFINE(show_license, "Show the license(s) for this copy of Asterisk"),
2460         AST_CLI_DEFINE(handle_version, "Display version info"),
2461         AST_CLI_DEFINE(handle_bang, "Execute a shell command"),
2462 #if !defined(LOW_MEMORY)
2463         AST_CLI_DEFINE(handle_show_version_files, "List versions of files used to build Asterisk"),
2464         AST_CLI_DEFINE(handle_show_threads, "Show running threads"),
2465 #if defined(HAVE_SYSINFO) || defined(HAVE_SYSCTL)
2466         AST_CLI_DEFINE(handle_show_sysinfo, "Show System Information"),
2467 #endif
2468         AST_CLI_DEFINE(handle_show_profile, "Display profiling info"),
2469         AST_CLI_DEFINE(handle_show_settings, "Show some core settings"),
2470         AST_CLI_DEFINE(handle_clear_profile, "Clear profiling info"),
2471 #endif /* ! LOW_MEMORY */
2472 };
2473
2474 struct el_read_char_state_struct {
2475         unsigned int line_full:1;
2476         unsigned int prev_line_full:1;
2477         char prev_line_verbosity;
2478 };
2479
2480 static int el_read_char_state_init(void *ptr)
2481 {
2482         struct el_read_char_state_struct *state = ptr;
2483         state->line_full = 1;
2484         state->prev_line_full = 1;
2485         state->prev_line_verbosity = 0;
2486         return 0;
2487 }
2488
2489 AST_THREADSTORAGE_CUSTOM(el_read_char_state, el_read_char_state_init, ast_free_ptr);
2490
2491 static int ast_el_read_char(EditLine *editline, char *cp)
2492 {
2493         int num_read = 0;
2494         int lastpos = 0;
2495         struct pollfd fds[2];
2496         int res;
2497         int max;
2498 #define EL_BUF_SIZE 512
2499         char buf[EL_BUF_SIZE];
2500         struct el_read_char_state_struct *state = ast_threadstorage_get(&el_read_char_state, sizeof(*state));
2501
2502         for (;;) {
2503                 max = 1;
2504                 fds[0].fd = ast_consock;
2505                 fds[0].events = POLLIN;
2506                 if (!ast_opt_exec) {
2507                         fds[1].fd = STDIN_FILENO;
2508                         fds[1].events = POLLIN;
2509                         max++;
2510                 }
2511                 res = ast_poll(fds, max, -1);
2512                 if (res < 0) {
2513                         if (sig_flags.need_quit || sig_flags.need_quit_handler)
2514                                 break;
2515                         if (errno == EINTR)
2516                                 continue;
2517                         fprintf(stderr, "poll failed: %s\n", strerror(errno));
2518                         break;
2519                 }
2520
2521                 if (!ast_opt_exec && fds[1].revents) {
2522                         num_read = read(STDIN_FILENO, cp, 1);
2523                         if (num_read < 1) {
2524                                 break;
2525                         } else {
2526                                 return (num_read);
2527                         }
2528                 }
2529                 if (fds[0].revents) {
2530                         char level = 0;
2531                         char *curline = buf, *nextline;
2532                         res = read(ast_consock, buf, sizeof(buf) - 1);
2533                         /* if the remote side disappears exit */
2534                         if (res < 1) {
2535                                 fprintf(stderr, "\nDisconnected from Asterisk server\n");
2536                                 if (!ast_opt_reconnect) {
2537                                         quit_handler(0, SHUTDOWN_FAST, 0);
2538                                 } else {
2539                                         int tries;
2540                                         int reconnects_per_second = 20;
2541                                         fprintf(stderr, "Attempting to reconnect for 30 seconds\n");
2542                                         for (tries = 0; tries < 30 * reconnects_per_second; tries++) {
2543                                                 if (ast_tryconnect()) {
2544                                                         fprintf(stderr, "Reconnect succeeded after %.3f seconds\n", 1.0 / reconnects_per_second * tries);
2545                                                         printf("%s", term_quit());
2546                                                         WELCOME_MESSAGE;
2547                                                         if (!ast_opt_mute)
2548                                                                 fdsend(ast_consock, "logger mute silent");
2549                                                         else
2550                                                                 printf("log and verbose output currently muted ('logger mute' to unmute)\n");
2551                                                         break;
2552                                                 } else
2553                                                         usleep(1000000 / reconnects_per_second);
2554                                         }
2555                                         if (tries >= 30 * reconnects_per_second) {
2556                                                 fprintf(stderr, "Failed to reconnect for 30 seconds.  Quitting.\n");
2557                                                 quit_handler(0, SHUTDOWN_FAST, 0);
2558                                         }
2559                                 }
2560                                 continue;
2561                         }
2562
2563                         buf[res] = '\0';
2564
2565                         /* Write over the CLI prompt */
2566                         if (!ast_opt_exec && !lastpos) {
2567                                 if (write(STDOUT_FILENO, "\r\e[0K", 5) < 0) {
2568                                 }
2569                         }
2570
2571                         do {
2572                                 state->prev_line_full = state->line_full;
2573                                 if ((nextline = strchr(curline, '\n'))) {
2574                                         state->line_full = 1;
2575                                         nextline++;
2576                                 } else {
2577                                         state->line_full = 0;
2578                                         nextline = strchr(curline, '\0');
2579                                 }
2580
2581                                 if (state->prev_line_full && VERBOSE_HASMAGIC(curline)) {
2582                                         level = VERBOSE_MAGIC2LEVEL(curline);
2583                                         curline++;
2584                                 } else if (state->prev_line_full && !VERBOSE_HASMAGIC(curline)) {
2585                                         /* Non-verbose output */
2586                                         level = 0;
2587                                 } else {
2588                                         level = state->prev_line_verbosity;
2589                                 }
2590                                 if ((!state->prev_line_full && state->prev_line_verbosity <= option_verbose) || (state->prev_line_full && level <= option_verbose)) {
2591                                         if (write(STDOUT_FILENO, curline, nextline - curline) < 0) {
2592                                         }
2593                                 }
2594
2595                                 state->prev_line_verbosity = level;
2596                                 curline = nextline;
2597                         } while (!ast_strlen_zero(curline));
2598
2599                         if ((res < EL_BUF_SIZE - 1) && ((buf[res-1] == '\n') || (buf[res-2] == '\n'))) {
2600                                 *cp = CC_REFRESH;
2601                                 return(1);
2602                         } else
2603                                 lastpos = 1;
2604                 }
2605         }
2606
2607         *cp = '\0';
2608         return (0);
2609 }
2610
2611 static struct ast_str *prompt = NULL;
2612
2613 static char *cli_prompt(EditLine *editline)
2614 {
2615         char tmp[100];
2616         char *pfmt;
2617         int color_used = 0;
2618         static int cli_prompt_changes = 0;
2619         struct passwd *pw;
2620         struct group *gr;
2621
2622         if (prompt == NULL) {
2623                 prompt = ast_str_create(100);
2624         } else if (!cli_prompt_changes) {
2625                 return ast_str_buffer(prompt);
2626         } else {
2627                 ast_str_reset(prompt);
2628         }
2629
2630         if ((pfmt = getenv("ASTERISK_PROMPT"))) {
2631                 char *t = pfmt;
2632                 struct timeval ts = ast_tvnow();
2633                 while (*t != '\0') {
2634                         if (*t == '%') {
2635                                 char hostname[MAXHOSTNAMELEN] = "";
2636                                 int i, which;
2637                                 struct ast_tm tm = { 0, };
2638                                 int fgcolor = COLOR_WHITE, bgcolor = COLOR_BLACK;
2639
2640                                 t++;
2641                                 switch (*t) {
2642                                 case 'C': /* color */
2643                                         t++;
2644                                         if (sscanf(t, "%30d;%30d%n", &fgcolor, &bgcolor, &i) == 2) {
2645                                                 ast_term_color_code(&prompt, fgcolor, bgcolor);
2646                                                 t += i - 1;
2647                                         } else if (sscanf(t, "%30d%n", &fgcolor, &i) == 1) {
2648                                                 ast_term_color_code(&prompt, fgcolor, 0);
2649                                                 t += i - 1;
2650                                         }
2651
2652                                         /* If the color has been reset correctly, then there's no need to reset it later */
2653                                         color_used = ((fgcolor == COLOR_WHITE) && (bgcolor == COLOR_BLACK)) ? 0 : 1;
2654                                         break;
2655                                 case 'd': /* date */
2656                                         if (ast_localtime(&ts, &tm, NULL)) {
2657                                                 ast_strftime(tmp, sizeof(tmp), "%Y-%m-%d", &tm);
2658                                                 ast_str_append(&prompt, 0, "%s", tmp);
2659                                                 cli_prompt_changes++;
2660                                         }
2661                                         break;
2662                                 case 'g': /* group */
2663                                         if ((gr = getgrgid(getgid()))) {
2664                                                 ast_str_append(&prompt, 0, "%s", gr->gr_name);
2665                                         }
2666                                         break;
2667                                 case 'h': /* hostname */
2668                                         if (!gethostname(hostname, sizeof(hostname) - 1)) {
2669                                                 ast_str_append(&prompt, 0, "%s", hostname);
2670                                         } else {
2671                                                 ast_str_append(&prompt, 0, "%s", "localhost");
2672                                         }
2673                                         break;
2674                                 case 'H': /* short hostname */
2675                                         if (!gethostname(hostname, sizeof(hostname) - 1)) {
2676                                                 char *dotptr;
2677                                                 if ((dotptr = strchr(hostname, '.'))) {
2678                                                         *dotptr = '\0';
2679                                                 }
2680                                                 ast_str_append(&prompt, 0, "%s", hostname);
2681                                         } else {
2682                                                 ast_str_append(&prompt, 0, "%s", "localhost");
2683                                         }
2684                                         break;
2685 #ifdef HAVE_GETLOADAVG
2686                                 case 'l': /* load avg */
2687                                         t++;
2688                                         if (sscanf(t, "%30d", &which) == 1 && which > 0 && which <= 3) {
2689                                                 double list[3];
2690                                                 getloadavg(list, 3);
2691                                                 ast_str_append(&prompt, 0, "%.2f", list[which - 1]);
2692                                                 cli_prompt_changes++;
2693                                         }
2694                                         break;
2695 #endif
2696                                 case 's': /* Asterisk system name (from asterisk.conf) */
2697                                         ast_str_append(&prompt, 0, "%s", ast_config_AST_SYSTEM_NAME);
2698                                         break;
2699                                 case 't': /* time */
2700                                         if (ast_localtime(&ts, &tm, NULL)) {
2701                                                 ast_strftime(tmp, sizeof(tmp), "%H:%M:%S", &tm);
2702                                                 ast_str_append(&prompt, 0, "%s", tmp);
2703                                                 cli_prompt_changes++;
2704                                         }
2705                                         break;
2706                                 case 'u': /* username */
2707                                         if ((pw = getpwuid(getuid()))) {
2708                                                 ast_str_append(&prompt, 0, "%s", pw->pw_name);
2709                                         }
2710                                         break;
2711                                 case '#': /* process console or remote? */
2712                                         ast_str_append(&prompt, 0, "%c", ast_opt_remote ? '>' : '#');
2713                                         break;
2714                                 case '%': /* literal % */
2715                                         ast_str_append(&prompt, 0, "%c", '%');
2716                                         break;
2717                                 case '\0': /* % is last character - prevent bug */
2718                                         t--;
2719                                         break;
2720                                 }
2721                         } else {
2722                                 ast_str_append(&prompt, 0, "%c", *t);
2723                         }
2724                         t++;
2725                 }
2726                 if (color_used) {
2727                         /* Force colors back to normal at end */
2728                         ast_term_color_code(&prompt, 0, 0);
2729                 }
2730         } else if (remotehostname) {
2731                 ast_str_set(&prompt, 0, ASTERISK_PROMPT2, remotehostname);
2732         } else {
2733                 ast_str_set(&prompt, 0, "%s", ASTERISK_PROMPT);
2734         }
2735
2736         return ast_str_buffer(prompt);
2737 }
2738
2739 static char **ast_el_strtoarr(char *buf)
2740 {
2741         char **match_list = NULL, **match_list_tmp, *retstr;
2742         size_t match_list_len;
2743         int matches = 0;
2744
2745         match_list_len = 1;
2746         while ( (retstr = strsep(&buf, " ")) != NULL) {
2747
2748                 if (!strcmp(retstr, AST_CLI_COMPLETE_EOF))
2749                         break;
2750                 if (matches + 1 >= match_list_len) {
2751                         match_list_len <<= 1;
2752                         if ((match_list_tmp = ast_realloc(match_list, match_list_len * sizeof(char *)))) {
2753                                 match_list = match_list_tmp;
2754                         } else {
2755                                 if (match_list)
2756                                         ast_free(match_list);
2757                                 return (char **) NULL;
2758                         }
2759                 }
2760
2761                 match_list[matches++] = ast_strdup(retstr);
2762         }
2763
2764         if (!match_list)
2765                 return (char **) NULL;
2766
2767         if (matches >= match_list_len) {
2768                 if ((match_list_tmp = ast_realloc(match_list, (match_list_len + 1) * sizeof(char *)))) {
2769                         match_list = match_list_tmp;
2770                 } else {
2771                         if (match_list)
2772                                 ast_free(match_list);
2773                         return (char **) NULL;
2774                 }
2775         }
2776
2777         match_list[matches] = (char *) NULL;
2778
2779         return match_list;
2780 }
2781
2782 static int ast_el_sort_compare(const void *i1, const void *i2)
2783 {
2784         char *s1, *s2;
2785
2786         s1 = ((char **)i1)[0];
2787         s2 = ((char **)i2)[0];
2788
2789         return strcasecmp(s1, s2);
2790 }
2791
2792 static int ast_cli_display_match_list(char **matches, int len, int max)
2793 {
2794         int i, idx, limit, count;
2795         int screenwidth = 0;
2796         int numoutput = 0, numoutputline = 0;
2797
2798         screenwidth = ast_get_termcols(STDOUT_FILENO);
2799
2800         /* find out how many entries can be put on one line, with two spaces between strings */
2801         limit = screenwidth / (max + 2);
2802         if (limit == 0)
2803                 limit = 1;
2804
2805         /* how many lines of output */
2806         count = len / limit;
2807         if (count * limit < len)
2808                 count++;
2809
2810         idx = 1;
2811
2812         qsort(&matches[0], (size_t)(len), sizeof(char *), ast_el_sort_compare);
2813
2814         for (; count > 0; count--) {
2815                 numoutputline = 0;
2816                 for (i = 0; i < limit && matches[idx]; i++, idx++) {
2817
2818                         /* Don't print dupes */
2819                         if ( (matches[idx+1] != NULL && strcmp(matches[idx], matches[idx+1]) == 0 ) ) {
2820                                 i--;
2821                                 ast_free(matches[idx]);
2822                                 matches[idx] = NULL;
2823                                 continue;
2824                         }
2825
2826                         numoutput++;
2827                         numoutputline++;
2828                         fprintf(stdout, "%-*s  ", max, matches[idx]);
2829                         ast_free(matches[idx]);
2830                         matches[idx] = NULL;
2831                 }
2832                 if (numoutputline > 0)
2833                         fprintf(stdout, "\n");
2834         }
2835
2836         return numoutput;
2837 }
2838
2839
2840 static char *cli_complete(EditLine *editline, int ch)
2841 {
2842         int len = 0;
2843         char *ptr;
2844         int nummatches = 0;
2845         char **matches;
2846         int retval = CC_ERROR;
2847         char buf[2048], savechr;
2848         int res;
2849
2850         LineInfo *lf = (LineInfo *)el_line(editline);
2851
2852         savechr = *(char *)lf->cursor;
2853         *(char *)lf->cursor = '\0';
2854         ptr = (char *)lf->cursor;
2855         if (ptr) {
2856                 while (ptr > lf->buffer) {
2857                         if (isspace(*ptr)) {
2858                                 ptr++;
2859                                 break;
2860                         }
2861                         ptr--;
2862                 }
2863         }
2864
2865         len = lf->cursor - ptr;
2866
2867         if (ast_opt_remote) {
2868                 snprintf(buf, sizeof(buf), "_COMMAND NUMMATCHES \"%s\" \"%s\"", lf->buffer, ptr);
2869                 fdsend(ast_consock, buf);
2870                 if ((res = read(ast_consock, buf, sizeof(buf) - 1)) < 0) {
2871                         return (char*)(CC_ERROR);
2872                 }
2873                 buf[res] = '\0';
2874                 nummatches = atoi(buf);
2875
2876                 if (nummatches > 0) {
2877                         char *mbuf;
2878                         int mlen = 0, maxmbuf = 2048;
2879                         /* Start with a 2048 byte buffer */
2880                         if (!(mbuf = ast_malloc(maxmbuf))) {
2881                                 *((char *) lf->cursor) = savechr;
2882                                 return (char *)(CC_ERROR);
2883                         }
2884                         snprintf(buf, sizeof(buf), "_COMMAND MATCHESARRAY \"%s\" \"%s\"", lf->buffer, ptr);
2885                         fdsend(ast_consock, buf);
2886                         res = 0;
2887                         mbuf[0] = '\0';
2888                         while (!strstr(mbuf, AST_CLI_COMPLETE_EOF) && res != -1) {
2889                                 if (mlen + 1024 > maxmbuf) {
2890                                         /* Every step increment buffer 1024 bytes */
2891                                         maxmbuf += 1024;
2892                                         if (!(mbuf = ast_realloc(mbuf, maxmbuf))) {
2893                                                 *((char *) lf->cursor) = savechr;
2894                                                 return (char *)(CC_ERROR);
2895                                         }
2896                                 }
2897                                 /* Only read 1024 bytes at a time */
2898                                 res = read(ast_consock, mbuf + mlen, 1024);
2899                                 if (res > 0)
2900                                         mlen += res;
2901                         }
2902                         mbuf[mlen] = '\0';
2903
2904                         matches = ast_el_strtoarr(mbuf);
2905                         ast_free(mbuf);
2906                 } else
2907                         matches = (char **) NULL;
2908         } else {
2909                 char **p, *oldbuf=NULL;
2910                 nummatches = 0;
2911                 matches = ast_cli_completion_matches((char *)lf->buffer,ptr);
2912                 for (p = matches; p && *p; p++) {
2913                         if (!oldbuf || strcmp(*p,oldbuf))
2914                                 nummatches++;
2915                         oldbuf = *p;
2916                 }
2917         }
2918
2919         if (matches) {
2920                 int i;
2921                 int matches_num, maxlen, match_len;
2922
2923                 if (matches[0][0] != '\0') {
2924                         el_deletestr(editline, (int) len);
2925                         el_insertstr(editline, matches[0]);
2926                         retval = CC_REFRESH;
2927                 }
2928
2929                 if (nummatches == 1) {
2930                         /* Found an exact match */
2931                         el_insertstr(editline, " ");
2932                         retval = CC_REFRESH;
2933                 } else {
2934                         /* Must be more than one match */
2935                         for (i = 1, maxlen = 0; matches[i]; i++) {
2936                                 match_len = strlen(matches[i]);
2937                                 if (match_len > maxlen)
2938                                         maxlen = match_len;
2939                         }
2940                         matches_num = i - 1;
2941                         if (matches_num >1) {
2942                                 fprintf(stdout, "\n");
2943                                 ast_cli_display_match_list(matches, nummatches, maxlen);
2944                                 retval = CC_REDISPLAY;
2945                         } else {
2946                                 el_insertstr(editline," ");
2947                                 retval = CC_REFRESH;
2948                         }
2949                 }
2950                 for (i = 0; matches[i]; i++)
2951                         ast_free(matches[i]);
2952                 ast_free(matches);
2953         }
2954
2955         *((char *) lf->cursor) = savechr;
2956
2957         return (char *)(long)retval;
2958 }
2959
2960 static int ast_el_initialize(void)
2961 {
2962         HistEvent ev;
2963         char *editor, *editrc = getenv("EDITRC");
2964
2965         if (!(editor = getenv("AST_EDITMODE"))) {
2966                 if (!(editor = getenv("AST_EDITOR"))) {
2967                         editor = "emacs";
2968                 }
2969         }
2970
2971         if (el != NULL)
2972                 el_end(el);
2973         if (el_hist != NULL)
2974                 history_end(el_hist);
2975
2976         el = el_init("asterisk", stdin, stdout, stderr);
2977         el_set(el, EL_PROMPT, cli_prompt);
2978
2979         el_set(el, EL_EDITMODE, 1);
2980         el_set(el, EL_EDITOR, editor);
2981         el_hist = history_init();
2982         if (!el || !el_hist)
2983                 return -1;
2984
2985         /* setup history with 100 entries */
2986         history(el_hist, &ev, H_SETSIZE, 100);
2987
2988         el_set(el, EL_HIST, history, el_hist);
2989
2990         el_set(el, EL_ADDFN, "ed-complete", "Complete argument", cli_complete);
2991         /* Bind <tab> to command completion */
2992         el_set(el, EL_BIND, "^I", "ed-complete", NULL);
2993         /* Bind ? to command completion */
2994         el_set(el, EL_BIND, "?", "ed-complete", NULL);
2995         /* Bind ^D to redisplay */
2996         el_set(el, EL_BIND, "^D", "ed-redisplay", NULL);
2997         /* Bind Delete to delete char left */
2998         el_set(el, EL_BIND, "\\e[3~", "ed-delete-next-char", NULL);
2999         /* Bind Home and End to move to line start and end */
3000         el_set(el, EL_BIND, "\\e[1~", "ed-move-to-beg", NULL);
3001         el_set(el, EL_BIND, "\\e[4~", "ed-move-to-end", NULL);
3002         /* Bind C-left and C-right to move by word (not all terminals) */
3003         el_set(el, EL_BIND, "\\eOC", "vi-next-word", NULL);
3004         el_set(el, EL_BIND, "\\eOD", "vi-prev-word", NULL);
3005
3006         if (editrc) {
3007                 el_source(el, editrc);
3008         }
3009
3010         return 0;
3011 }
3012
3013 #define MAX_HISTORY_COMMAND_LENGTH 256
3014
3015 static int ast_el_add_history(char *buf)
3016 {
3017         HistEvent ev;
3018
3019         if (el_hist == NULL || el == NULL)
3020                 ast_el_initialize();
3021         if (strlen(buf) > (MAX_HISTORY_COMMAND_LENGTH - 1))
3022                 return 0;
3023         return (history(el_hist, &ev, H_ENTER, ast_strip(ast_strdupa(buf))));
3024 }
3025
3026 static int ast_el_write_history(char *filename)
3027 {
3028         HistEvent ev;
3029
3030         if (el_hist == NULL || el == NULL)
3031                 ast_el_initialize();
3032
3033         return (history(el_hist, &ev, H_SAVE, filename));
3034 }
3035
3036 static int ast_el_read_history(char *filename)
3037 {
3038         HistEvent ev;
3039
3040         if (el_hist == NULL || el == NULL) {
3041                 ast_el_initialize();
3042         }
3043
3044         return history(el_hist, &ev, H_LOAD, filename);
3045 }
3046
3047 static void ast_remotecontrol(char *data)
3048 {
3049         char buf[80];
3050         int res;
3051         char filename[80] = "";
3052         char *hostname;
3053         char *cpid;
3054         char *version;
3055         int pid;
3056         char *stringp = NULL;
3057
3058         char *ebuf;
3059         int num = 0;
3060
3061         memset(&sig_flags, 0, sizeof(sig_flags));
3062         signal(SIGINT, __remote_quit_handler);
3063         signal(SIGTERM, __remote_quit_handler);
3064         signal(SIGHUP, __remote_quit_handler);
3065
3066         if (read(ast_consock, buf, sizeof(buf)) < 0) {
3067                 ast_log(LOG_ERROR, "read() failed: %s\n", strerror(errno));
3068                 return;
3069         }
3070         if (data) {
3071                 char prefix[] = "cli quit after ";
3072                 char *tmp = ast_alloca(strlen(data) + strlen(prefix) + 1);
3073                 sprintf(tmp, "%s%s", prefix, data);
3074                 if (write(ast_consock, tmp, strlen(tmp) + 1) < 0) {
3075                         ast_log(LOG_ERROR, "write() failed: %s\n", strerror(errno));
3076                         if (sig_flags.need_quit || sig_flags.need_quit_handler) {
3077                                 return;
3078                         }
3079                 }
3080         }
3081         stringp = buf;
3082         hostname = strsep(&stringp, "/");
3083         cpid = strsep(&stringp, "/");
3084         version = strsep(&stringp, "\n");
3085         if (!version)
3086                 version = "<Version Unknown>";
3087         stringp = hostname;
3088         strsep(&stringp, ".");
3089         if (cpid)
3090                 pid = atoi(cpid);
3091         else
3092                 pid = -1;
3093         if (!data) {
3094                 if (!ast_opt_mute) {
3095                         fdsend(ast_consock, "logger mute silent");
3096                 } else {
3097                         printf("log and verbose output currently muted ('logger mute' to unmute)\n");
3098                 }
3099         }
3100
3101         if (ast_opt_exec && data) {  /* hack to print output then exit if asterisk -rx is used */
3102                 int linefull = 1, prev_linefull = 1, prev_line_verbose = 0;
3103                 struct pollfd fds;
3104                 fds.fd = ast_consock;
3105                 fds.events = POLLIN;
3106                 fds.revents = 0;
3107
3108                 while (ast_poll(&fds, 1, 60000) > 0) {
3109                         char buffer[512] = "", *curline = buffer, *nextline;
3110                         int not_written = 1;
3111
3112                         if (sig_flags.need_quit || sig_flags.need_quit_handler) {
3113                                 break;
3114                         }
3115
3116                         if (read(ast_consock, buffer, sizeof(buffer) - 1) <= 0) {
3117                                 break;
3118                         }
3119
3120                         do {
3121                                 prev_linefull = linefull;
3122                                 if ((nextline = strchr(curline, '\n'))) {
3123                                         linefull = 1;
3124                                         nextline++;
3125                                 } else {
3126                                         linefull = 0;
3127                                         nextline = strchr(curline, '\0');
3128                                 }
3129
3130                                 /* Skip verbose lines */
3131                                 /* Prev line full? | Line is verbose | Last line verbose? | Print
3132                                  * TRUE            | TRUE*           | TRUE               | FALSE
3133                                  * TRUE            | TRUE*           | FALSE              | FALSE
3134                                  * TRUE            | FALSE*          | TRUE               | TRUE
3135                                  * TRUE            | FALSE*          | FALSE              | TRUE
3136                                  * FALSE           | TRUE            | TRUE*              | FALSE
3137                                  * FALSE           | TRUE            | FALSE*             | TRUE
3138                                  * FALSE           | FALSE           | TRUE*              | FALSE
3139                                  * FALSE           | FALSE           | FALSE*             | TRUE
3140                                  */
3141                                 if ((!prev_linefull && !prev_line_verbose) || (prev_linefull && *curline > 0)) {
3142                                         prev_line_verbose = 0;
3143                                         not_written = 0;
3144                                         if (write(STDOUT_FILENO, curline, nextline - curline) < 0) {
3145                                                 ast_log(LOG_WARNING, "write() failed: %s\n", strerror(errno));
3146                                         }
3147                                 } else {
3148                                         prev_line_verbose = 1;
3149                                 }
3150                                 curline = nextline;
3151                         } while (!ast_strlen_zero(curline));
3152
3153                         /* No non-verbose output in 60 seconds. */
3154                         if (not_written) {
3155                                 break;
3156                         }
3157                 }
3158                 return;
3159         }
3160
3161         ast_verbose("Connected to Asterisk %s currently running on %s (pid = %d)\n", version, hostname, pid);
3162         remotehostname = hostname;
3163         if (getenv("HOME"))
3164                 snprintf(filename, sizeof(filename), "%s/.asterisk_history", getenv("HOME"));
3165         if (el_hist == NULL || el == NULL)
3166                 ast_el_initialize();
3167
3168         el_set(el, EL_GETCFN, ast_el_read_char);
3169
3170         if (!ast_strlen_zero(filename))
3171                 ast_el_read_history(filename);
3172
3173         for (;;) {
3174                 ebuf = (char *)el_gets(el, &num);
3175
3176                 if (sig_flags.need_quit || sig_flags.need_quit_handler) {
3177                         break;
3178                 }
3179
3180                 if (!ebuf && write(1, "", 1) < 0)
3181                         break;
3182
3183                 if (!ast_strlen_zero(ebuf)) {
3184                         if (ebuf[strlen(ebuf)-1] == '\n')
3185                                 ebuf[strlen(ebuf)-1] = '\0';
3186                         if (!remoteconsolehandler(ebuf)) {
3187                                 res = write(ast_consock, ebuf, strlen(ebuf) + 1);
3188                                 if (res < 1) {
3189                                         ast_log(LOG_WARNING, "Unable to write: %s\n", strerror(errno));
3190                                         break;
3191                                 }
3192                         }
3193                 }
3194         }
3195         printf("\nDisconnected from Asterisk server\n");
3196 }
3197
3198 static int show_version(void)
3199 {
3200         printf("Asterisk %s\n", ast_get_version());
3201         return 0;
3202 }
3203
3204 static int show_cli_help(void)
3205 {
3206         printf("Asterisk %s, Copyright (C) 1999 - 2012, Digium, Inc. and others.\n", ast_get_version());
3207         printf("Usage: asterisk [OPTIONS]\n");
3208         printf("Valid Options:\n");
3209         printf("   -V              Display version number and exit\n");
3210         printf("   -C <configfile> Use an alternate configuration file\n");
3211         printf("   -G <group>      Run as a group other than the caller\n");
3212         printf("   -U <user>       Run as a user other than the caller\n");
3213         printf("   -c              Provide console CLI\n");
3214         printf("   -d              Enable extra debugging\n");
3215 #if HAVE_WORKING_FORK
3216         printf("   -f              Do not fork\n");
3217         printf("   -F              Always fork\n");
3218 #endif
3219         printf("   -g              Dump core in case of a crash\n");
3220         printf("   -h              This help screen\n");
3221         printf("   -i              Initialize crypto keys at startup\n");
3222         printf("   -I              Enable internal timing if DAHDI timer is available\n");
3223         printf("   -L <load>       Limit the maximum load average before rejecting new calls\n");
3224         printf("   -M <value>      Limit the maximum number of calls to the specified value\n");
3225         printf("   -m              Mute debugging and console output on the console\n");
3226         printf("   -n              Disable console colorization\n");
3227         printf("   -p              Run as pseudo-realtime thread\n");
3228         printf("   -q              Quiet mode (suppress output)\n");
3229         printf("   -r              Connect to Asterisk on this machine\n");
3230         printf("   -R              Same as -r, except attempt to reconnect if disconnected\n");
3231         printf("   -s <socket>     Connect to Asterisk via socket <socket> (only valid with -r)\n");
3232         printf("   -t              Record soundfiles in /var/tmp and move them where they\n");
3233         printf("                   belong after they are done\n");
3234         printf("   -T              Display the time in [Mmm dd hh:mm:ss] format for each line\n");
3235         printf("                   of output to the CLI\n");
3236         printf("   -v              Increase verbosity (multiple v's = more verbose)\n");
3237         printf("   -x <cmd>        Execute command <cmd> (implies -r)\n");
3238         printf("   -X              Execute includes by default (allows #exec in asterisk.conf)\n");
3239         printf("   -W              Adjust terminal colors to compensate for a light background\n");
3240         printf("\n");
3241         return 0;
3242 }
3243
3244 static void ast_readconfig(void)
3245 {
3246         struct ast_config *cfg;
3247         struct ast_variable *v;
3248         char *config = DEFAULT_CONFIG_FILE;
3249         char hostname[MAXHOSTNAMELEN] = "";
3250         struct ast_flags config_flags = { CONFIG_FLAG_NOREALTIME };
3251         struct {
3252                 unsigned int dbdir:1;
3253                 unsigned int keydir:1;
3254         } found = { 0, 0 };
3255
3256         /* Set default value */
3257         option_dtmfminduration = AST_MIN_DTMF_DURATION;
3258
3259         if (ast_opt_override_config) {
3260                 cfg = ast_config_load2(ast_config_AST_CONFIG_FILE, "" /* core, can't reload */, config_flags);
3261                 if (cfg == CONFIG_STATUS_FILEMISSING || cfg == CONFIG_STATUS_FILEUNCHANGED || cfg == CONFIG_STATUS_FILEINVALID) {
3262                         fprintf(stderr, "Unable to open specified master config file '%s', using built-in defaults\n", ast_config_AST_CONFIG_FILE);
3263                 }
3264         } else {
3265                 cfg = ast_config_load2(config, "" /* core, can't reload */, config_flags);
3266         }
3267
3268         /* init with buildtime config */
3269         ast_copy_string(cfg_paths.config_dir, DEFAULT_CONFIG_DIR, sizeof(cfg_paths.config_dir));
3270         ast_copy_string(cfg_paths.spool_dir, DEFAULT_SPOOL_DIR, sizeof(cfg_paths.spool_dir));
3271         ast_copy_string(cfg_paths.module_dir, DEFAULT_MODULE_DIR, sizeof(cfg_paths.module_dir));
3272         snprintf(cfg_paths.monitor_dir, sizeof(cfg_paths.monitor_dir), "%s/monitor", cfg_paths.spool_dir);
3273         snprintf(cfg_paths.recording_dir, sizeof(cfg_paths.recording_dir), "%s/recording", cfg_paths.spool_dir);
3274         ast_copy_string(cfg_paths.var_dir, DEFAULT_VAR_DIR, sizeof(cfg_paths.var_dir));
3275         ast_copy_string(cfg_paths.data_dir, DEFAULT_DATA_DIR, sizeof(cfg_paths.data_dir));
3276         ast_copy_string(cfg_paths.log_dir, DEFAULT_LOG_DIR, sizeof(cfg_paths.log_dir));
3277         ast_copy_string(cfg_paths.agi_dir, DEFAULT_AGI_DIR, sizeof(cfg_paths.agi_dir));
3278         ast_copy_string(cfg_paths.db_path, DEFAULT_DB, sizeof(cfg_paths.db_path));
3279         ast_copy_string(cfg_paths.sbin_dir, DEFAULT_SBIN_DIR, sizeof(cfg_paths.sbin_dir));
3280         ast_copy_string(cfg_paths.key_dir, DEFAULT_KEY_DIR, sizeof(cfg_paths.key_dir));
3281         ast_copy_string(cfg_paths.pid_path, DEFAULT_PID, sizeof(cfg_paths.pid_path));
3282         ast_copy_string(cfg_paths.socket_path, DEFAULT_SOCKET, sizeof(cfg_paths.socket_path));
3283         ast_copy_string(cfg_paths.run_dir, DEFAULT_RUN_DIR, sizeof(cfg_paths.run_dir));
3284
3285         ast_set_default_eid(&ast_eid_default);
3286
3287         /* no asterisk.conf? no problem, use buildtime config! */
3288         if (cfg == CONFIG_STATUS_FILEMISSING || cfg == CONFIG_STATUS_FILEUNCHANGED || cfg == CONFIG_STATUS_FILEINVALID) {
3289                 return;
3290         }
3291
3292         for (v = ast_variable_browse(cfg, "files"); v; v = v->next) {
3293                 if (!strcasecmp(v->name, "astctlpermissions"))
3294                         ast_copy_string(ast_config_AST_CTL_PERMISSIONS, v->value, sizeof(ast_config_AST_CTL_PERMISSIONS));
3295                 else if (!strcasecmp(v->name, "astctlowner"))
3296                         ast_copy_string(ast_config_AST_CTL_OWNER, v->value, sizeof(ast_config_AST_CTL_OWNER));
3297                 else if (!strcasecmp(v->name, "astctlgroup"))
3298                         ast_copy_string(ast_config_AST_CTL_GROUP, v->value, sizeof(ast_config_AST_CTL_GROUP));
3299                 else if (!strcasecmp(v->name, "astctl"))
3300                         ast_copy_string(ast_config_AST_CTL, v->value, sizeof(ast_config_AST_CTL));
3301         }
3302
3303         for (v = ast_variable_browse(cfg, "directories"); v; v = v->next) {
3304                 if (!strcasecmp(v->name, "astetcdir")) {
3305                         ast_copy_string(cfg_paths.config_dir, v->value, sizeof(cfg_paths.config_dir));
3306                 } else if (!strcasecmp(v->name, "astspooldir")) {
3307                         ast_copy_string(cfg_paths.spool_dir, v->value, sizeof(cfg_paths.spool_dir));
3308                         snprintf(cfg_paths.monitor_dir, sizeof(cfg_paths.monitor_dir), "%s/monitor", v->value);
3309                         snprintf(cfg_paths.recording_dir, sizeof(cfg_paths.recording_dir), "%s/recording", v->value);
3310                 } else if (!strcasecmp(v->name, "astvarlibdir")) {
3311                         ast_copy_string(cfg_paths.var_dir, v->value, sizeof(cfg_paths.var_dir));
3312                         if (!found.dbdir)
3313                                 snprintf(cfg_paths.db_path, sizeof(cfg_paths.db_path), "%s/astdb", v->value);
3314                 } else if (!strcasecmp(v->name, "astdbdir")) {
3315                         snprintf(cfg_paths.db_path, sizeof(cfg_paths.db_path), "%s/astdb", v->value);
3316                         found.dbdir = 1;
3317                 } else if (!strcasecmp(v->name, "astdatadir")) {
3318                         ast_copy_string(cfg_paths.data_dir, v->value, sizeof(cfg_paths.data_dir));
3319                         if (!found.keydir)
3320                                 snprintf(cfg_paths.key_dir, sizeof(cfg_paths.key_dir), "%s/keys", v->value);
3321                 } else if (!strcasecmp(v->name, "astkeydir")) {
3322                         snprintf(cfg_paths.key_dir, sizeof(cfg_paths.key_dir), "%s/keys", v->value);
3323                         found.keydir = 1;
3324                 } else if (!strcasecmp(v->name, "astlogdir")) {
3325                         ast_copy_string(cfg_paths.log_dir, v->value, sizeof(cfg_paths.log_dir));
3326                 } else if (!strcasecmp(v->name, "astagidir")) {
3327                         ast_copy_string(cfg_paths.agi_dir, v->value, sizeof(cfg_paths.agi_dir));
3328                 } else if (!strcasecmp(v->name, "astrundir")) {
3329                         snprintf(cfg_paths.pid_path, sizeof(cfg_paths.pid_path), "%s/%s", v->value, "asterisk.pid");
3330                         snprintf(cfg_paths.socket_path, sizeof(cfg_paths.socket_path), "%s/%s", v->value, ast_config_AST_CTL);
3331                         ast_copy_string(cfg_paths.run_dir, v->value, sizeof(cfg_paths.run_dir));
3332                 } else if (!strcasecmp(v->name, "astmoddir")) {
3333                         ast_copy_string(cfg_paths.module_dir, v->value, sizeof(cfg_paths.module_dir));
3334                 } else if (!strcasecmp(v->name, "astsbindir")) {
3335                         ast_copy_string(cfg_paths.sbin_dir, v->value, sizeof(cfg_paths.sbin_dir));
3336                 }
3337         }
3338
3339         for (v = ast_variable_browse(cfg, "options"); v; v = v->next) {
3340                 /* verbose level (-v at startup) */
3341                 if (!strcasecmp(v->name, "verbose")) {
3342                         option_verbose = atoi(v->value);
3343                 /* whether or not to force timestamping in CLI verbose output. (-T at startup) */
3344                 } else if (!strcasecmp(v->name, "timestamp")) {
3345                         ast_set2_flag(&ast_options, ast_true(v->value), AST_OPT_FLAG_TIMESTAMP);
3346                 /* whether or not to support #exec in config files */
3347                 } else if (!strcasecmp(v->name, "execincludes")) {
3348                         ast_set2_flag(&ast_options, ast_true(v->value), AST_OPT_FLAG_EXEC_INCLUDES);
3349                 /* debug level (-d at startup) */
3350                 } else if (!strcasecmp(v->name, "debug")) {
3351                         option_debug = 0;
3352                         if (sscanf(v->value, "%30d", &option_debug) != 1) {
3353                                 option_debug = ast_true(v->value);
3354                         }
3355 #if HAVE_WORKING_FORK
3356                 /* Disable forking (-f at startup) */
3357                 } else if (!strcasecmp(v->name, "nofork")) {
3358                         ast_set2_flag(&ast_options, ast_true(v->value), AST_OPT_FLAG_NO_FORK);
3359                 /* Always fork, even if verbose or debug are enabled (-F at startup) */
3360                 } else if (!strcasecmp(v->name, "alwaysfork")) {
3361                         ast_set2_flag(&ast_options, ast_true(v->value), AST_OPT_FLAG_ALWAYS_FORK);
3362 #endif
3363                 /* Run quietly (-q at startup ) */
3364                 } else if (!strcasecmp(v->name, "quiet")) {
3365                         ast_set2_flag(&ast_options, ast_true(v->value), AST_OPT_FLAG_QUIET);
3366                 /* Run as console (-c at startup, implies nofork) */
3367                 } else if (!strcasecmp(v->name, "console")) {
3368                         ast_set2_flag(&ast_options, ast_true(v->value), AST_OPT_FLAG_NO_FORK | AST_OPT_FLAG_CONSOLE);
3369                 /* Run with high priority if the O/S permits (-p at startup) */
3370                 } else if (!strcasecmp(v->name, "highpriority")) {
3371                         ast_set2_flag(&ast_options, ast_true(v->value), AST_OPT_FLAG_HIGH_PRIORITY);
3372                 /* Initialize RSA auth keys (IAX2) (-i at startup) */
3373                 } else if (!strcasecmp(v->name, "initcrypto")) {
3374                         ast_set2_flag(&ast_options, ast_true(v->value), AST_OPT_FLAG_INIT_KEYS);
3375                 /* Disable ANSI colors for console (-c at startup) */
3376                 } else if (!strcasecmp(v->name, "nocolor")) {
3377                         ast_set2_flag(&ast_options, ast_true(v->value), AST_OPT_FLAG_NO_COLOR);
3378                 /* Disable some usage warnings for picky people :p */
3379                 } else if (!strcasecmp(v->name, "dontwarn")) {
3380                         ast_set2_flag(&ast_options, ast_true(v->value), AST_OPT_FLAG_DONT_WARN);
3381                 /* Dump core in case of crash (-g) */
3382                 } else if (!strcasecmp(v->name, "dumpcore")) {
3383                         ast_set2_flag(&ast_options, ast_true(v->value), AST_OPT_FLAG_DUMP_CORE);
3384                 /* Cache recorded sound files to another directory during recording */
3385                 } else if (!strcasecmp(v->name, "cache_record_files")) {
3386                         ast_set2_flag(&ast_options, ast_true(v->value), AST_OPT_FLAG_CACHE_RECORD_FILES);
3387                 /* Specify cache directory */
3388                 }  else if (!strcasecmp(v->name, "record_cache_dir")) {
3389                         ast_copy_string(record_cache_dir, v->value, AST_CACHE_DIR_LEN);
3390                 /* Build transcode paths via SLINEAR, instead of directly */
3391                 } else if (!strcasecmp(v->name, "transcode_via_sln")) {
3392                         ast_set2_flag(&ast_options, ast_true(v->value), AST_OPT_FLAG_TRANSCODE_VIA_SLIN);
3393                 /* Transmit SLINEAR silence while a channel is being recorded or DTMF is being generated on a channel */
3394                 } else if (!strcasecmp(v->name, "transmit_silence_during_record") || !strcasecmp(v->name, "transmit_silence")) {
3395                         ast_set2_flag(&ast_options, ast_true(v->value), AST_OPT_FLAG_TRANSMIT_SILENCE);
3396                 /* Enable internal timing */
3397                 } else if (!strcasecmp(v->name, "internal_timing")) {
3398                         ast_set2_flag(&ast_options, ast_true(v->value), AST_OPT_FLAG_INTERNAL_TIMING);
3399                 } else if (!strcasecmp(v->name, "mindtmfduration")) {
3400                         if (sscanf(v->value, "%30u", &option_dtmfminduration) != 1) {
3401                                 option_dtmfminduration = AST_MIN_DTMF_DURATION;
3402                         }
3403                 } else if (!strcasecmp(v->name, "maxcalls")) {
3404                         if ((sscanf(v->value, "%30d", &option_maxcalls) != 1) || (option_maxcalls < 0)) {
3405                                 option_maxcalls = 0;
3406                         }
3407                 } else if (!strcasecmp(v->name, "maxload")) {
3408                         double test[1];
3409
3410                         if (getloadavg(test, 1) == -1) {
3411                                 ast_log(LOG_ERROR, "Cannot obtain load average on this system. 'maxload' option disabled.\n");
3412                                 option_maxload = 0.0;
3413                         } else if ((sscanf(v->value, "%30lf", &option_maxload) != 1) || (option_maxload < 0.0)) {
3414                                 option_maxload = 0.0;
3415                         }
3416                 /* Set the maximum amount of open files */
3417                 } else if (!strcasecmp(v->name, "maxfiles")) {
3418                         option_maxfiles = atoi(v->value);
3419                         set_ulimit(option_maxfiles);
3420                 /* What user to run as */
3421                 } else if (!strcasecmp(v->name, "runuser")) {
3422                         ast_copy_string(cfg_paths.run_user, v->value, sizeof(cfg_paths.run_user));
3423                 /* What group to run as */
3424                 } else if (!strcasecmp(v->name, "rungroup")) {
3425                         ast_copy_string(cfg_paths.run_group, v->value, sizeof(cfg_paths.run_group));
3426                 } else if (!strcasecmp(v->name, "systemname")) {
3427                         ast_copy_string(cfg_paths.system_name, v->value, sizeof(cfg_paths.system_name));
3428                 } else if (!strcasecmp(v->name, "autosystemname")) {
3429                         if (ast_true(v->value)) {
3430                                 if (!gethostname(hostname, sizeof(hostname) - 1))
3431                                         ast_copy_string(cfg_paths.system_name, hostname, sizeof(cfg_paths.system_name));
3432                                 else {
3433                                         if (ast_strlen_zero(ast_config_AST_SYSTEM_NAME)){
3434                                                 ast_copy_string(cfg_paths.system_name, "localhost", sizeof(cfg_paths.system_name));
3435                                         }
3436                                         ast_log(LOG_ERROR, "Cannot obtain hostname for this system.  Using '%s' instead.\n", ast_config_AST_SYSTEM_NAME);
3437                                 }
3438                         }
3439                 } else if (!strcasecmp(v->name, "languageprefix")) {
3440                         ast_language_is_prefix = ast_true(v->value);
3441                 } else if (!strcasecmp(v->name, "defaultlanguage")) {
3442                         ast_copy_string(defaultlanguage, v->value, MAX_LANGUAGE);
3443                 } else if (!strcasecmp(v->name, "lockmode")) {
3444                         if (!strcasecmp(v->value, "lockfile")) {
3445                                 ast_set_lock_type(AST_LOCK_TYPE_LOCKFILE);
3446                         } else if (!strcasecmp(v->value, "flock")) {
3447                                 ast_set_lock_type(AST_LOCK_TYPE_FLOCK);
3448                         } else {
3449                                 ast_log(LOG_WARNING, "'%s' is not a valid setting for the lockmode option, "
3450                                         "defaulting to 'lockfile'\n", v->value);
3451                                 ast_set_lock_type(AST_LOCK_TYPE_LOCKFILE);
3452                         }
3453 #if defined(HAVE_SYSINFO)
3454                 } else if (!strcasecmp(v->name, "minmemfree")) {
3455                         /* specify the minimum amount of free memory to retain.  Asterisk should stop accepting new calls
3456                          * if the amount of free memory falls below this watermark */
3457                         if ((sscanf(v->value, "%30ld", &option_minmemfree) != 1) || (option_minmemfree < 0)) {
3458                                 option_minmemfree = 0;
3459                         }
3460 #endif
3461                 } else if (!strcasecmp(v->name, "entityid")) {
3462                         struct ast_eid tmp_eid;
3463                         if (!ast_str_to_eid(&tmp_eid, v->value)) {
3464                                 ast_verbose("Successfully set global EID to '%s'\n", v->value);
3465                                 ast_eid_default = tmp_eid;
3466                         } else
3467                                 ast_verbose("Invalid Entity ID '%s' provided\n", v->value);
3468                 } else if (!strcasecmp(v->name, "lightbackground")) {
3469                         ast_set2_flag(&ast_options, ast_true(v->value), AST_OPT_FLAG_LIGHT_BACKGROUND);
3470                 } else if (!strcasecmp(v->name, "forceblackbackground")) {
3471                         ast_set2_flag(&ast_options, ast_true(v->value), AST_OPT_FLAG_FORCE_BLACK_BACKGROUND);
3472                 } else if (!strcasecmp(v->name, "hideconnect")) {
3473                         ast_set2_flag(&ast_options, ast_true(v->value), AST_OPT_FLAG_HIDE_CONSOLE_CONNECT);
3474                 } else if (!strcasecmp(v->name, "lockconfdir")) {
3475                         ast_set2_flag(&ast_options, ast_true(v->value), AST_OPT_FLAG_LOCK_CONFIG_DIR);
3476                 } else if (!strcasecmp(v->name, "stdexten")) {
3477                         /* Choose how to invoke the extensions.conf stdexten */
3478                         if (!strcasecmp(v->value, "gosub")) {
3479                                 ast_clear_flag(&ast_options, AST_OPT_FLAG_STDEXTEN_MACRO);
3480                         } else if (!strcasecmp(v->value, "macro")) {
3481                                 ast_set_flag(&ast_options, AST_OPT_FLAG_STDEXTEN_MACRO);
3482                         } else {
3483                                 ast_log(LOG_WARNING,
3484                                         "'%s' is not a valid setting for the stdexten option, defaulting to 'gosub'\n",
3485                                         v->value);
3486                                 ast_clear_flag(&ast_options, AST_OPT_FLAG_STDEXTEN_MACRO);
3487                         }
3488                 }
3489         }
3490         for (v = ast_variable_browse(cfg, "compat"); v; v = v->next) {
3491                 float version;
3492                 if (sscanf(v->value, "%30f", &version) != 1) {
3493                         fprintf(stderr, "Compatibility version for option '%s' is not a number: '%s'\n", v->name, v->value);
3494                         continue;
3495                 }
3496                 if (!strcasecmp(v->name, "app_set")) {
3497                         ast_set2_flag(&ast_compat, version < 1.5 ? 1 : 0, AST_COMPAT_APP_SET);
3498                 } else if (!strcasecmp(v->name, "res_agi")) {
3499                         ast_set2_flag(&ast_compat, version < 1.5 ? 1 : 0, AST_COMPAT_DELIM_RES_AGI);
3500                 } else if (!strcasecmp(v->name, "pbx_realtime")) {
3501                         ast_set2_flag(&ast_compat, version < 1.5 ? 1 : 0, AST_COMPAT_DELIM_PBX_REALTIME);
3502                 }
3503         }
3504         ast_config_destroy(cfg);
3505 }
3506
3507 static void *monitor_sig_flags(void *unused)
3508 {
3509         for (;;) {
3510                 struct pollfd p = { sig_alert_pipe[0], POLLIN, 0 };
3511                 int a;
3512                 ast_poll(&p, 1, -1);
3513                 if (sig_flags.need_reload) {
3514                         sig_flags.need_reload = 0;
3515                         ast_module_reload(NULL);
3516                 }
3517                 if (sig_flags.need_quit) {
3518                         sig_flags.need_quit = 0;
3519                         if ((consolethread != AST_PTHREADT_NULL) && (consolethread != pthread_self())) {
3520                                 sig_flags.need_quit_handler = 1;
3521                                 pthread_kill(consolethread, SIGURG);
3522                         } else {
3523                                 quit_handler(0, SHUTDOWN_NORMAL, 0);
3524                         }
3525                 }
3526                 if (read(sig_alert_pipe[0], &a, sizeof(a)) != sizeof(a)) {
3527                 }
3528         }
3529
3530         return NULL;
3531 }
3532
3533 static void *canary_thread(void *unused)
3534 {
3535         struct stat canary_stat;
3536         struct timeval now;
3537
3538         /* Give the canary time to sing */
3539         sleep(120);
3540
3541         for (;;) {
3542                 now = ast_tvnow();
3543                 if (stat(canary_filename, &canary_stat) || now.tv_sec > canary_stat.st_mtime + 60) {
3544                         ast_log(LOG_WARNING,
3545                                 "The canary is no more.  He has ceased to be!  "
3546                                 "He's expired and gone to meet his maker!  "
3547                                 "He's a stiff!  Bereft of life, he rests in peace.  "
3548                                 "His metabolic processes are now history!  He's off the twig!  "
3549                                 "He's kicked the bucket.  He's shuffled off his mortal coil, "
3550                                 "run down the curtain, and joined the bleeding choir invisible!!  "
3551                                 "THIS is an EX-CANARY.  (Reducing priority)\n");
3552                         ast_set_priority(0);
3553                         pthread_exit(NULL);
3554                 }
3555
3556                 /* Check the canary once a minute */
3557                 sleep(60);
3558         }
3559 }
3560
3561 /* Used by libc's atexit(3) function */
3562 static void canary_exit(void)
3563 {
3564         if (canary_pid > 0)
3565                 kill(canary_pid, SIGKILL);
3566 }
3567
3568 static void run_startup_commands(void)
3569 {
3570         int fd;
3571         struct ast_config *cfg;
3572         struct ast_flags cfg_flags = { 0 };
3573         struct ast_variable *v;
3574
3575         if (!(cfg = ast_config_load2("cli.conf", "" /* core, can't reload */, cfg_flags)))
3576                 return;
3577         if (cfg == CONFIG_STATUS_FILEMISSING || cfg == CONFIG_STATUS_FILEUNCHANGED || cfg == CONFIG_STATUS_FILEINVALID) {
3578                 return;
3579         }
3580