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