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