Initial support for endpoints.
[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 static struct stasis_message_type *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 struct stasis_message_type *ast_network_change_type(void)
1067 {
1068         return network_change_type;
1069 }
1070
1071 /*! \brief Cleanup the \ref stasis system level items */
1072 static void stasis_system_topic_cleanup(void)
1073 {
1074         ao2_ref(system_topic, -1);
1075         system_topic = NULL;
1076         ao2_ref(network_change_type, -1);
1077         network_change_type = NULL;
1078 }
1079
1080 /*! \brief Initialize the system level items for \ref stasis */
1081 static int stasis_system_topic_init(void)
1082 {
1083         ast_register_atexit(stasis_system_topic_cleanup);
1084
1085         system_topic = stasis_topic_create("ast_system");
1086         if (!system_topic) {
1087                 return 1;
1088         }
1089
1090         network_change_type = stasis_message_type_create("network_change");
1091         if (!network_change_type) {
1092                 return -1;
1093         }
1094         return 0;
1095 }
1096
1097 static void ast_run_atexits(void)
1098 {
1099         struct ast_atexit *ae;
1100
1101         AST_LIST_LOCK(&atexits);
1102         while ((ae = AST_LIST_REMOVE_HEAD(&atexits, list))) {
1103                 if (ae->func) {
1104                         ae->func();
1105                 }
1106                 ast_free(ae);
1107         }
1108         AST_LIST_UNLOCK(&atexits);
1109 }
1110
1111 static void __ast_unregister_atexit(void (*func)(void))
1112 {
1113         struct ast_atexit *ae;
1114
1115         AST_LIST_TRAVERSE_SAFE_BEGIN(&atexits, ae, list) {
1116                 if (ae->func == func) {
1117                         AST_LIST_REMOVE_CURRENT(list);
1118                         ast_free(ae);
1119                         break;
1120                 }
1121         }
1122         AST_LIST_TRAVERSE_SAFE_END;
1123 }
1124
1125 int ast_register_atexit(void (*func)(void))
1126 {
1127         struct ast_atexit *ae;
1128
1129         ae = ast_calloc(1, sizeof(*ae));
1130         if (!ae) {
1131                 return -1;
1132         }
1133         ae->func = func;
1134
1135         AST_LIST_LOCK(&atexits);
1136         __ast_unregister_atexit(func);
1137         AST_LIST_INSERT_HEAD(&atexits, ae, list);
1138         AST_LIST_UNLOCK(&atexits);
1139
1140         return 0;
1141 }
1142
1143 void ast_unregister_atexit(void (*func)(void))
1144 {
1145         AST_LIST_LOCK(&atexits);
1146         __ast_unregister_atexit(func);
1147         AST_LIST_UNLOCK(&atexits);
1148 }
1149
1150 /* Sending commands from consoles back to the daemon requires a terminating NULL */
1151 static int fdsend(int fd, const char *s)
1152 {
1153         return write(fd, s, strlen(s) + 1);
1154 }
1155
1156 /* Sending messages from the daemon back to the display requires _excluding_ the terminating NULL */
1157 static int fdprint(int fd, const char *s)
1158 {
1159         return write(fd, s, strlen(s));
1160 }
1161
1162 /*! \brief NULL handler so we can collect the child exit status */
1163 static void _null_sig_handler(int sig)
1164 {
1165 }
1166
1167 static struct sigaction null_sig_handler = {
1168         .sa_handler = _null_sig_handler,
1169         .sa_flags = SA_RESTART,
1170 };
1171
1172 static struct sigaction ignore_sig_handler = {
1173         .sa_handler = SIG_IGN,
1174 };
1175
1176 AST_MUTEX_DEFINE_STATIC(safe_system_lock);
1177 /*! \brief Keep track of how many threads are currently trying to wait*() on
1178  *  a child process
1179  */
1180 static unsigned int safe_system_level = 0;
1181 static struct sigaction safe_system_prev_handler;
1182
1183 void ast_replace_sigchld(void)
1184 {
1185         unsigned int level;
1186
1187         ast_mutex_lock(&safe_system_lock);
1188         level = safe_system_level++;
1189
1190         /* only replace the handler if it has not already been done */
1191         if (level == 0) {
1192                 sigaction(SIGCHLD, &null_sig_handler, &safe_system_prev_handler);
1193         }
1194
1195         ast_mutex_unlock(&safe_system_lock);
1196 }
1197
1198 void ast_unreplace_sigchld(void)
1199 {
1200         unsigned int level;
1201
1202         ast_mutex_lock(&safe_system_lock);
1203         level = --safe_system_level;
1204
1205         /* only restore the handler if we are the last one */
1206         if (level == 0) {
1207                 sigaction(SIGCHLD, &safe_system_prev_handler, NULL);
1208         }
1209
1210         ast_mutex_unlock(&safe_system_lock);
1211 }
1212
1213 int ast_safe_system(const char *s)
1214 {
1215         pid_t pid;
1216         int res;
1217         struct rusage rusage;
1218         int status;
1219
1220 #if defined(HAVE_WORKING_FORK) || defined(HAVE_WORKING_VFORK)
1221         ast_replace_sigchld();
1222
1223 #ifdef HAVE_WORKING_FORK
1224         pid = fork();
1225 #else
1226         pid = vfork();
1227 #endif
1228
1229         if (pid == 0) {
1230 #ifdef HAVE_CAP
1231                 cap_t cap = cap_from_text("cap_net_admin-eip");
1232
1233                 if (cap_set_proc(cap)) {
1234                         /* Careful with order! Logging cannot happen after we close FDs */
1235                         ast_log(LOG_WARNING, "Unable to remove capabilities.\n");
1236                 }
1237                 cap_free(cap);
1238 #endif
1239 #ifdef HAVE_WORKING_FORK
1240                 if (ast_opt_high_priority)
1241                         ast_set_priority(0);
1242                 /* Close file descriptors and launch system command */
1243                 ast_close_fds_above_n(STDERR_FILENO);
1244 #endif
1245                 execl("/bin/sh", "/bin/sh", "-c", s, (char *) NULL);
1246                 _exit(1);
1247         } else if (pid > 0) {
1248                 for (;;) {
1249                         res = wait4(pid, &status, 0, &rusage);
1250                         if (res > -1) {
1251                                 res = WIFEXITED(status) ? WEXITSTATUS(status) : -1;
1252                                 break;
1253                         } else if (errno != EINTR)
1254                                 break;
1255                 }
1256         } else {
1257                 ast_log(LOG_WARNING, "Fork failed: %s\n", strerror(errno));
1258                 res = -1;
1259         }
1260
1261         ast_unreplace_sigchld();
1262 #else /* !defined(HAVE_WORKING_FORK) && !defined(HAVE_WORKING_VFORK) */
1263         res = -1;
1264 #endif
1265
1266         return res;
1267 }
1268
1269 /*!
1270  * \brief enable or disable a logging level to a specified console
1271  */
1272 void ast_console_toggle_loglevel(int fd, int level, int state)
1273 {
1274         int x;
1275
1276         if (level >= NUMLOGLEVELS) {
1277                 level = NUMLOGLEVELS - 1;
1278         }
1279
1280         for (x = 0;x < AST_MAX_CONNECTS; x++) {
1281                 if (fd == consoles[x].fd) {
1282                         /*
1283                          * Since the logging occurs when levels are false, set to
1284                          * flipped iinput because this function accepts 0 as off and 1 as on
1285                          */
1286                         consoles[x].levels[level] = state ? 0 : 1;
1287                         return;
1288                 }
1289         }
1290 }
1291
1292 /*!
1293  * \brief mute or unmute a console from logging
1294  */
1295 void ast_console_toggle_mute(int fd, int silent)
1296 {
1297         int x;
1298         for (x = 0;x < AST_MAX_CONNECTS; x++) {
1299                 if (fd == consoles[x].fd) {
1300                         if (consoles[x].mute) {
1301                                 consoles[x].mute = 0;
1302                                 if (!silent)
1303                                         ast_cli(fd, "Console is not muted anymore.\n");
1304                         } else {
1305                                 consoles[x].mute = 1;
1306                                 if (!silent)
1307                                         ast_cli(fd, "Console is muted.\n");
1308                         }
1309                         return;
1310                 }
1311         }
1312         ast_cli(fd, "Couldn't find remote console.\n");
1313 }
1314
1315 /*!
1316  * \brief log the string to all attached console clients
1317  */
1318 static void ast_network_puts_mutable(const char *string, int level)
1319 {
1320         int x;
1321         for (x = 0;x < AST_MAX_CONNECTS; x++) {
1322                 if (consoles[x].mute)
1323                         continue;
1324                 if (consoles[x].fd > -1) {
1325                         if (!consoles[x].levels[level])
1326                                 fdprint(consoles[x].p[1], string);
1327                 }
1328         }
1329 }
1330
1331 /*!
1332  * \brief log the string to the console, and all attached
1333  * console clients
1334  */
1335 void ast_console_puts_mutable(const char *string, int level)
1336 {
1337         fputs(string, stdout);
1338         fflush(stdout);
1339         ast_network_puts_mutable(string, level);
1340 }
1341
1342 /*!
1343  * \brief write the string to all attached console clients
1344  */
1345 static void ast_network_puts(const char *string)
1346 {
1347         int x;
1348         for (x = 0; x < AST_MAX_CONNECTS; x++) {
1349                 if (consoles[x].fd > -1)
1350                         fdprint(consoles[x].p[1], string);
1351         }
1352 }
1353
1354 /*!
1355  * \brief write the string to the console, and all attached
1356  * console clients
1357  */
1358 void ast_console_puts(const char *string)
1359 {
1360         fputs(string, stdout);
1361         fflush(stdout);
1362         ast_network_puts(string);
1363 }
1364
1365 static void network_verboser(const char *s)
1366 {
1367         ast_network_puts_mutable(s, __LOG_VERBOSE);
1368 }
1369
1370 static pthread_t lthread;
1371
1372 /*!
1373  * \brief read() function supporting the reception of user credentials.
1374  *
1375  * \param fd Socket file descriptor.
1376  * \param buffer Receive buffer.
1377  * \param size 'buffer' size.
1378  * \param con Console structure to set received credentials
1379  * \retval -1 on error
1380  * \retval the number of bytes received on success.
1381  */
1382 static int read_credentials(int fd, char *buffer, size_t size, struct console *con)
1383 {
1384 #if defined(SO_PEERCRED)
1385 #ifdef HAVE_STRUCT_SOCKPEERCRED_UID
1386 #define HAVE_STRUCT_UCRED_UID
1387         struct sockpeercred cred;
1388 #else
1389         struct ucred cred;
1390 #endif
1391         socklen_t len = sizeof(cred);
1392 #endif
1393 #if defined(HAVE_GETPEEREID)
1394         uid_t uid;
1395         gid_t gid;
1396 #else
1397         int uid, gid;
1398 #endif
1399         int result;
1400
1401         result = read(fd, buffer, size);
1402         if (result < 0) {
1403                 return result;
1404         }
1405
1406 #if defined(SO_PEERCRED) && (defined(HAVE_STRUCT_UCRED_UID) || defined(HAVE_STRUCT_UCRED_CR_UID))
1407         if (getsockopt(fd, SOL_SOCKET, SO_PEERCRED, &cred, &len)) {
1408                 return result;
1409         }
1410 #if defined(HAVE_STRUCT_UCRED_UID)
1411         uid = cred.uid;
1412         gid = cred.gid;
1413 #else /* defined(HAVE_STRUCT_UCRED_CR_UID) */
1414         uid = cred.cr_uid;
1415         gid = cred.cr_gid;
1416 #endif /* defined(HAVE_STRUCT_UCRED_UID) */
1417
1418 #elif defined(HAVE_GETPEEREID)
1419         if (getpeereid(fd, &uid, &gid)) {
1420                 return result;
1421         }
1422 #else
1423         return result;
1424 #endif
1425         con->uid = uid;
1426         con->gid = gid;
1427
1428         return result;
1429 }
1430
1431 static void *netconsole(void *vconsole)
1432 {
1433         struct console *con = vconsole;
1434         char hostname[MAXHOSTNAMELEN] = "";
1435         char inbuf[512];
1436         char outbuf[512];
1437         const char * const end_buf = inbuf + sizeof(inbuf);
1438         char *start_read = inbuf;
1439         int res;
1440         struct pollfd fds[2];
1441
1442         if (gethostname(hostname, sizeof(hostname)-1))
1443                 ast_copy_string(hostname, "<Unknown>", sizeof(hostname));
1444         snprintf(outbuf, sizeof(outbuf), "%s/%ld/%s\n", hostname, (long)ast_mainpid, ast_get_version());
1445         fdprint(con->fd, outbuf);
1446         for (;;) {
1447                 fds[0].fd = con->fd;
1448                 fds[0].events = POLLIN;
1449                 fds[0].revents = 0;
1450                 fds[1].fd = con->p[0];
1451                 fds[1].events = POLLIN;
1452                 fds[1].revents = 0;
1453
1454                 res = ast_poll(fds, 2, -1);
1455                 if (res < 0) {
1456                         if (errno != EINTR)
1457                                 ast_log(LOG_WARNING, "poll returned < 0: %s\n", strerror(errno));
1458                         continue;
1459                 }
1460                 if (fds[0].revents) {
1461                         int cmds_read, bytes_read;
1462                         if ((bytes_read = read_credentials(con->fd, start_read, end_buf - start_read, con)) < 1) {
1463                                 break;
1464                         }
1465                         /* XXX This will only work if it is the first command, and I'm not sure fixing it is worth the effort. */
1466                         if (strncmp(inbuf, "cli quit after ", 15) == 0) {
1467                                 ast_cli_command_multiple_full(con->uid, con->gid, con->fd, bytes_read - 15, inbuf + 15);
1468                                 break;
1469                         }
1470                         /* ast_cli_command_multiple_full will only process individual commands terminated by a
1471                          * NULL and not trailing partial commands. */
1472                         if (!(cmds_read = ast_cli_command_multiple_full(con->uid, con->gid, con->fd, bytes_read + start_read - inbuf, inbuf))) {
1473                                 /* No commands were read. We either have a short read on the first command
1474                                  * with space left, or a command that is too long */
1475                                 if (start_read + bytes_read < end_buf) {
1476                                         start_read += bytes_read;
1477                                 } else {
1478                                         ast_log(LOG_ERROR, "Command too long! Skipping\n");
1479                                         start_read = inbuf;
1480                                 }
1481                                 continue;
1482                         }
1483                         if (start_read[bytes_read - 1] == '\0') {
1484                                 /* The read ended on a command boundary, start reading again at the head of inbuf */
1485                                 start_read = inbuf;
1486                                 continue;
1487                         }
1488                         /* If we get this far, we have left over characters that have not been processed.
1489                          * Advance to the character after the last command read by ast_cli_command_multiple_full.
1490                          * We are guaranteed to have at least cmds_read NULLs */
1491                         while (cmds_read-- && (start_read = strchr(start_read, '\0'))) {
1492                                 start_read++;
1493                         }
1494                         memmove(inbuf, start_read, end_buf - start_read);
1495                         start_read = end_buf - start_read + inbuf;
1496                 }
1497                 if (fds[1].revents) {
1498                         res = read_credentials(con->p[0], outbuf, sizeof(outbuf), con);
1499                         if (res < 1) {
1500                                 ast_log(LOG_ERROR, "read returned %d\n", res);
1501                                 break;
1502                         }
1503                         res = write(con->fd, outbuf, res);
1504                         if (res < 1)
1505                                 break;
1506                 }
1507         }
1508         if (!ast_opt_hide_connect) {
1509                 ast_verb(3, "Remote UNIX connection disconnected\n");
1510         }
1511         close(con->fd);
1512         close(con->p[0]);
1513         close(con->p[1]);
1514         con->fd = -1;
1515
1516         return NULL;
1517 }
1518
1519 static void *listener(void *unused)
1520 {
1521         struct sockaddr_un sunaddr;
1522         int s;
1523         socklen_t len;
1524         int x;
1525         int flags;
1526         struct pollfd fds[1];
1527         for (;;) {
1528                 if (ast_socket < 0)
1529                         return NULL;
1530                 fds[0].fd = ast_socket;
1531                 fds[0].events = POLLIN;
1532                 s = ast_poll(fds, 1, -1);
1533                 pthread_testcancel();
1534                 if (s < 0) {
1535                         if (errno != EINTR)
1536                                 ast_log(LOG_WARNING, "poll returned error: %s\n", strerror(errno));
1537                         continue;
1538                 }
1539                 len = sizeof(sunaddr);
1540                 s = accept(ast_socket, (struct sockaddr *)&sunaddr, &len);
1541                 if (s < 0) {
1542                         if (errno != EINTR)
1543                                 ast_log(LOG_WARNING, "Accept returned %d: %s\n", s, strerror(errno));
1544                 } else {
1545 #if !defined(SO_PASSCRED)
1546                         {
1547 #else
1548                         int sckopt = 1;
1549                         /* turn on socket credentials passing. */
1550                         if (setsockopt(s, SOL_SOCKET, SO_PASSCRED, &sckopt, sizeof(sckopt)) < 0) {
1551                                 ast_log(LOG_WARNING, "Unable to turn on socket credentials passing\n");
1552                         } else {
1553 #endif
1554                                 for (x = 0; x < AST_MAX_CONNECTS; x++) {
1555                                         if (consoles[x].fd >= 0) {
1556                                                 continue;
1557                                         }
1558                                         if (socketpair(AF_LOCAL, SOCK_STREAM, 0, consoles[x].p)) {
1559                                                 ast_log(LOG_ERROR, "Unable to create pipe: %s\n", strerror(errno));
1560                                                 consoles[x].fd = -1;
1561                                                 fdprint(s, "Server failed to create pipe\n");
1562                                                 close(s);
1563                                                 break;
1564                                         }
1565                                         flags = fcntl(consoles[x].p[1], F_GETFL);
1566                                         fcntl(consoles[x].p[1], F_SETFL, flags | O_NONBLOCK);
1567                                         consoles[x].fd = s;
1568                                         consoles[x].mute = 1; /* Default is muted, we will un-mute if necessary */
1569                                         /* Default uid and gid to -2, so then in cli.c/cli_has_permissions() we will be able
1570                                            to know if the user didn't send the credentials. */
1571                                         consoles[x].uid = -2;
1572                                         consoles[x].gid = -2;
1573                                         if (ast_pthread_create_detached_background(&consoles[x].t, NULL, netconsole, &consoles[x])) {
1574                                                 ast_log(LOG_ERROR, "Unable to spawn thread to handle connection: %s\n", strerror(errno));
1575                                                 close(consoles[x].p[0]);
1576                                                 close(consoles[x].p[1]);
1577                                                 consoles[x].fd = -1;
1578                                                 fdprint(s, "Server failed to spawn thread\n");
1579                                                 close(s);
1580                                         }
1581                                         break;
1582                                 }
1583                                 if (x >= AST_MAX_CONNECTS) {
1584                                         fdprint(s, "No more connections allowed\n");
1585                                         ast_log(LOG_WARNING, "No more connections allowed\n");
1586                                         close(s);
1587                                 } else if ((consoles[x].fd > -1) && (!ast_opt_hide_connect)) {
1588                                         ast_verb(3, "Remote UNIX connection\n");
1589                                 }
1590                         }
1591                 }
1592         }
1593         return NULL;
1594 }
1595
1596 static int ast_makesocket(void)
1597 {
1598         struct sockaddr_un sunaddr;
1599         int res;
1600         int x;
1601         uid_t uid = -1;
1602         gid_t gid = -1;
1603
1604         for (x = 0; x < AST_MAX_CONNECTS; x++)
1605                 consoles[x].fd = -1;
1606         unlink(ast_config_AST_SOCKET);
1607         ast_socket = socket(PF_LOCAL, SOCK_STREAM, 0);
1608         if (ast_socket < 0) {
1609                 ast_log(LOG_WARNING, "Unable to create control socket: %s\n", strerror(errno));
1610                 return -1;
1611         }
1612         memset(&sunaddr, 0, sizeof(sunaddr));
1613         sunaddr.sun_family = AF_LOCAL;
1614         ast_copy_string(sunaddr.sun_path, ast_config_AST_SOCKET, sizeof(sunaddr.sun_path));
1615         res = bind(ast_socket, (struct sockaddr *)&sunaddr, sizeof(sunaddr));
1616         if (res) {
1617                 ast_log(LOG_WARNING, "Unable to bind socket to %s: %s\n", ast_config_AST_SOCKET, strerror(errno));
1618                 close(ast_socket);
1619                 ast_socket = -1;
1620                 return -1;
1621         }
1622         res = listen(ast_socket, 2);
1623         if (res < 0) {
1624                 ast_log(LOG_WARNING, "Unable to listen on socket %s: %s\n", ast_config_AST_SOCKET, strerror(errno));
1625                 close(ast_socket);
1626                 ast_socket = -1;
1627                 return -1;
1628         }
1629         if (ast_register_verbose(network_verboser)) {
1630                 ast_log(LOG_WARNING, "Unable to register network verboser?\n");
1631         }
1632
1633         if (ast_pthread_create_background(&lthread, NULL, listener, NULL)) {
1634                 ast_log(LOG_WARNING, "Unable to create listener thread.\n");
1635                 close(ast_socket);
1636                 return -1;
1637         }
1638
1639         if (!ast_strlen_zero(ast_config_AST_CTL_OWNER)) {
1640                 struct passwd *pw;
1641                 if ((pw = getpwnam(ast_config_AST_CTL_OWNER)) == NULL)
1642                         ast_log(LOG_WARNING, "Unable to find uid of user %s\n", ast_config_AST_CTL_OWNER);
1643                 else
1644                         uid = pw->pw_uid;
1645         }
1646
1647         if (!ast_strlen_zero(ast_config_AST_CTL_GROUP)) {
1648                 struct group *grp;
1649                 if ((grp = getgrnam(ast_config_AST_CTL_GROUP)) == NULL)
1650                         ast_log(LOG_WARNING, "Unable to find gid of group %s\n", ast_config_AST_CTL_GROUP);
1651                 else
1652                         gid = grp->gr_gid;
1653         }
1654
1655         if (chown(ast_config_AST_SOCKET, uid, gid) < 0)
1656                 ast_log(LOG_WARNING, "Unable to change ownership of %s: %s\n", ast_config_AST_SOCKET, strerror(errno));
1657
1658         if (!ast_strlen_zero(ast_config_AST_CTL_PERMISSIONS)) {
1659                 int p1;
1660                 mode_t p;
1661                 sscanf(ast_config_AST_CTL_PERMISSIONS, "%30o", &p1);
1662                 p = p1;
1663                 if ((chmod(ast_config_AST_SOCKET, p)) < 0)
1664                         ast_log(LOG_WARNING, "Unable to change file permissions of %s: %s\n", ast_config_AST_SOCKET, strerror(errno));
1665         }
1666
1667         return 0;
1668 }
1669
1670 static int ast_tryconnect(void)
1671 {
1672         struct sockaddr_un sunaddr;
1673         int res;
1674         ast_consock = socket(PF_LOCAL, SOCK_STREAM, 0);
1675         if (ast_consock < 0) {
1676                 fprintf(stderr, "Unable to create socket: %s\n", strerror(errno));
1677                 return 0;
1678         }
1679         memset(&sunaddr, 0, sizeof(sunaddr));
1680         sunaddr.sun_family = AF_LOCAL;
1681         ast_copy_string(sunaddr.sun_path, ast_config_AST_SOCKET, sizeof(sunaddr.sun_path));
1682         res = connect(ast_consock, (struct sockaddr *)&sunaddr, sizeof(sunaddr));
1683         if (res) {
1684                 close(ast_consock);
1685                 ast_consock = -1;
1686                 return 0;
1687         } else
1688                 return 1;
1689 }
1690
1691 /*! \brief Urgent handler
1692  *
1693  * Called by soft_hangup to interrupt the poll, read, or other
1694  * system call.  We don't actually need to do anything though.
1695  * Remember: Cannot EVER ast_log from within a signal handler
1696  */
1697 static void _urg_handler(int num)
1698 {
1699         return;
1700 }
1701
1702 static struct sigaction urg_handler = {
1703         .sa_handler = _urg_handler,
1704         .sa_flags = SA_RESTART,
1705 };
1706
1707 static void _hup_handler(int num)
1708 {
1709         int a = 0, save_errno = errno;
1710         printf("Received HUP signal -- Reloading configs\n");
1711         if (restartnow)
1712                 execvp(_argv[0], _argv);
1713         sig_flags.need_reload = 1;
1714         if (sig_alert_pipe[1] != -1) {
1715                 if (write(sig_alert_pipe[1], &a, sizeof(a)) < 0) {
1716                         fprintf(stderr, "hup_handler: write() failed: %s\n", strerror(errno));
1717                 }
1718         }
1719         errno = save_errno;
1720 }
1721
1722 static struct sigaction hup_handler = {
1723         .sa_handler = _hup_handler,
1724         .sa_flags = SA_RESTART,
1725 };
1726
1727 static void _child_handler(int sig)
1728 {
1729         /* Must not ever ast_log or ast_verbose within signal handler */
1730         int n, status, save_errno = errno;
1731
1732         /*
1733          * Reap all dead children -- not just one
1734          */
1735         for (n = 0; wait4(-1, &status, WNOHANG, NULL) > 0; n++)
1736                 ;
1737         if (n == 0 && option_debug)
1738                 printf("Huh?  Child handler, but nobody there?\n");
1739         errno = save_errno;
1740 }
1741
1742 static struct sigaction child_handler = {
1743         .sa_handler = _child_handler,
1744         .sa_flags = SA_RESTART,
1745 };
1746
1747 /*! \brief Set maximum open files */
1748 static void set_ulimit(int value)
1749 {
1750         struct rlimit l = {0, 0};
1751
1752         if (value <= 0) {
1753                 ast_log(LOG_WARNING, "Unable to change max files open to invalid value %i\n",value);
1754                 return;
1755         }
1756
1757         l.rlim_cur = value;
1758         l.rlim_max = value;
1759
1760         if (setrlimit(RLIMIT_NOFILE, &l)) {
1761                 ast_log(LOG_WARNING, "Unable to disable core size resource limit: %s\n",strerror(errno));
1762                 return;
1763         }
1764
1765         ast_log(LOG_NOTICE, "Setting max files open to %d\n",value);
1766
1767         return;
1768 }
1769
1770 /*! \brief Set an X-term or screen title */
1771 static void set_title(char *text)
1772 {
1773         if (getenv("TERM") && strstr(getenv("TERM"), "xterm"))
1774                 fprintf(stdout, "\033]2;%s\007", text);
1775 }
1776
1777 static void set_icon(char *text)
1778 {
1779         if (getenv("TERM") && strstr(getenv("TERM"), "xterm"))
1780                 fprintf(stdout, "\033]1;%s\007", text);
1781 }
1782
1783 /*! \brief We set ourselves to a high priority, that we might pre-empt
1784  * everything else.  If your PBX has heavy activity on it, this is a
1785  * good thing.
1786  */
1787 int ast_set_priority(int pri)
1788 {
1789         struct sched_param sched;
1790         memset(&sched, 0, sizeof(sched));
1791 #ifdef __linux__
1792         if (pri) {
1793                 sched.sched_priority = 10;
1794                 if (sched_setscheduler(0, SCHED_RR, &sched)) {
1795                         ast_log(LOG_WARNING, "Unable to set high priority\n");
1796                         return -1;
1797                 } else
1798                         ast_verb(1, "Set to realtime thread\n");
1799         } else {
1800                 sched.sched_priority = 0;
1801                 /* According to the manpage, these parameters can never fail. */
1802                 sched_setscheduler(0, SCHED_OTHER, &sched);
1803         }
1804 #else
1805         if (pri) {
1806                 if (setpriority(PRIO_PROCESS, 0, -10) == -1) {
1807                         ast_log(LOG_WARNING, "Unable to set high priority\n");
1808                         return -1;
1809                 } else
1810                         ast_verb(1, "Set to high priority\n");
1811         } else {
1812                 /* According to the manpage, these parameters can never fail. */
1813                 setpriority(PRIO_PROCESS, 0, 0);
1814         }
1815 #endif
1816         return 0;
1817 }
1818
1819 static int can_safely_quit(shutdown_nice_t niceness, int restart);
1820 static void really_quit(int num, shutdown_nice_t niceness, int restart);
1821
1822 static void quit_handler(int num, shutdown_nice_t niceness, int restart)
1823 {
1824         if (can_safely_quit(niceness, restart)) {
1825                 really_quit(num, niceness, restart);
1826                 /* No one gets here. */
1827         }
1828         /* It wasn't our time. */
1829 }
1830
1831 static int can_safely_quit(shutdown_nice_t niceness, int restart)
1832 {
1833         /* Check if someone else isn't already doing this. */
1834         ast_mutex_lock(&safe_system_lock);
1835         if (shuttingdown != NOT_SHUTTING_DOWN && niceness >= shuttingdown) {
1836                 /* Already in progress and other request was less nice. */
1837                 ast_mutex_unlock(&safe_system_lock);
1838                 ast_verbose("Ignoring asterisk %s request, already in progress.\n", restart ? "restart" : "shutdown");
1839                 return 0;
1840         }
1841         shuttingdown = niceness;
1842         ast_mutex_unlock(&safe_system_lock);
1843
1844         /* Try to get as many CDRs as possible submitted to the backend engines
1845          * (if in batch mode). really_quit happens to call it again when running
1846          * the atexit handlers, otherwise this would be a bit early. */
1847         ast_cdr_engine_term();
1848
1849         /* Shutdown the message queue for the technology agnostic message channel.
1850          * This has to occur before we pause shutdown pending ast_undestroyed_channels. */
1851         ast_msg_shutdown();
1852
1853         if (niceness == SHUTDOWN_NORMAL) {
1854                 time_t s, e;
1855                 /* Begin shutdown routine, hanging up active channels */
1856                 ast_begin_shutdown(1);
1857                 if (option_verbose && ast_opt_console) {
1858                         ast_verbose("Beginning asterisk %s....\n", restart ? "restart" : "shutdown");
1859                 }
1860                 time(&s);
1861                 for (;;) {
1862                         time(&e);
1863                         /* Wait up to 15 seconds for all channels to go away */
1864                         if ((e - s) > 15 || !ast_undestroyed_channels() || shuttingdown != niceness) {
1865                                 break;
1866                         }
1867                         /* Sleep 1/10 of a second */
1868                         usleep(100000);
1869                 }
1870         } else if (niceness >= SHUTDOWN_NICE) {
1871                 if (niceness != SHUTDOWN_REALLY_NICE) {
1872                         ast_begin_shutdown(0);
1873                 }
1874                 if (option_verbose && ast_opt_console) {
1875                         ast_verb(0, "Waiting for inactivity to perform %s...\n", restart ? "restart" : "halt");
1876                 }
1877                 for (;;) {
1878                         if (!ast_undestroyed_channels() || shuttingdown != niceness) {
1879                                 break;
1880                         }
1881                         sleep(1);
1882                 }
1883         }
1884
1885         /* Re-acquire lock and check if someone changed the niceness, in which
1886          * case someone else has taken over the shutdown.
1887          */
1888         ast_mutex_lock(&safe_system_lock);
1889         if (shuttingdown != niceness) {
1890                 if (shuttingdown == NOT_SHUTTING_DOWN && option_verbose && ast_opt_console) {
1891                         ast_verb(0, "Asterisk %s cancelled.\n", restart ? "restart" : "shutdown");
1892                 }
1893                 ast_mutex_unlock(&safe_system_lock);
1894                 return 0;
1895         }
1896         shuttingdown = SHUTTING_DOWN;
1897         ast_mutex_unlock(&safe_system_lock);
1898
1899         return 1;
1900 }
1901
1902 /*! Called when exiting is certain. */
1903 static void really_quit(int num, shutdown_nice_t niceness, int restart)
1904 {
1905         int active_channels;
1906
1907         if (niceness >= SHUTDOWN_NICE) {
1908                 ast_module_shutdown();
1909         }
1910
1911         if (ast_opt_console || (ast_opt_remote && !ast_opt_exec)) {
1912                 char filename[80] = "";
1913                 if (getenv("HOME")) {
1914                         snprintf(filename, sizeof(filename), "%s/.asterisk_history", getenv("HOME"));
1915                 }
1916                 if (!ast_strlen_zero(filename)) {
1917                         ast_el_write_history(filename);
1918                 }
1919                 if (consolethread == AST_PTHREADT_NULL || consolethread == pthread_self()) {
1920                         /* Only end if we are the consolethread, otherwise there's a race with that thread. */
1921                         if (el != NULL) {
1922                                 el_end(el);
1923                         }
1924                         if (el_hist != NULL) {
1925                                 history_end(el_hist);
1926                         }
1927                 } else if (mon_sig_flags == pthread_self()) {
1928                         if (consolethread != AST_PTHREADT_NULL) {
1929                                 pthread_kill(consolethread, SIGURG);
1930                         }
1931                 }
1932         }
1933         active_channels = ast_active_channels();
1934         /* The manager event for shutdown must happen prior to ast_run_atexits, as
1935          * the manager interface will dispose of its sessions as part of its
1936          * shutdown.
1937          */
1938         /*** DOCUMENTATION
1939                 <managerEventInstance>
1940                         <synopsis>Raised when Asterisk is shutdown or restarted.</synopsis>
1941                         <syntax>
1942                                 <parameter name="Shutdown">
1943                                         <enumlist>
1944                                                 <enum name="Uncleanly"/>
1945                                                 <enum name="Cleanly"/>
1946                                         </enumlist>
1947                                 </parameter>
1948                                 <parameter name="Restart">
1949                                         <enumlist>
1950                                                 <enum name="True"/>
1951                                                 <enum name="False"/>
1952                                         </enumlist>
1953                                 </parameter>
1954                         </syntax>
1955                 </managerEventInstance>
1956         ***/
1957         manager_event(EVENT_FLAG_SYSTEM, "Shutdown", "Shutdown: %s\r\n"
1958                 "Restart: %s\r\n",
1959                 active_channels ? "Uncleanly" : "Cleanly",
1960                 restart ? "True" : "False");
1961         ast_verb(0, "Asterisk %s ending (%d).\n",
1962                 active_channels ? "uncleanly" : "cleanly", num);
1963
1964         ast_verb(0, "Executing last minute cleanups\n");
1965         ast_run_atexits();
1966
1967         ast_debug(1, "Asterisk ending (%d).\n", num);
1968         if (ast_socket > -1) {
1969                 pthread_cancel(lthread);
1970                 close(ast_socket);
1971                 ast_socket = -1;
1972                 unlink(ast_config_AST_SOCKET);
1973         }
1974         if (ast_consock > -1)
1975                 close(ast_consock);
1976         if (!ast_opt_remote)
1977                 unlink(ast_config_AST_PID);
1978         printf("%s", term_quit());
1979         if (restart) {
1980                 int i;
1981                 ast_verb(0, "Preparing for Asterisk restart...\n");
1982                 /* Mark all FD's for closing on exec */
1983                 for (i = 3; i < 32768; i++) {
1984                         fcntl(i, F_SETFD, FD_CLOEXEC);
1985                 }
1986                 ast_verb(0, "Asterisk is now restarting...\n");
1987                 restartnow = 1;
1988
1989                 /* close logger */
1990                 close_logger();
1991                 clean_time_zones();
1992
1993                 /* If there is a consolethread running send it a SIGHUP
1994                    so it can execvp, otherwise we can do it ourselves */
1995                 if ((consolethread != AST_PTHREADT_NULL) && (consolethread != pthread_self())) {
1996                         pthread_kill(consolethread, SIGHUP);
1997                         /* Give the signal handler some time to complete */
1998                         sleep(2);
1999                 } else
2000                         execvp(_argv[0], _argv);
2001
2002         } else {
2003                 /* close logger */
2004                 close_logger();
2005                 clean_time_zones();
2006         }
2007
2008         exit(0);
2009 }
2010
2011 static void __quit_handler(int num)
2012 {
2013         int a = 0;
2014         sig_flags.need_quit = 1;
2015         if (sig_alert_pipe[1] != -1) {
2016                 if (write(sig_alert_pipe[1], &a, sizeof(a)) < 0) {
2017                         fprintf(stderr, "quit_handler: write() failed: %s\n", strerror(errno));
2018                 }
2019         }
2020         /* There is no need to restore the signal handler here, since the app
2021          * is going to exit */
2022 }
2023
2024 static void __remote_quit_handler(int num)
2025 {
2026         sig_flags.need_quit = 1;
2027 }
2028
2029 static const char *fix_header(char *outbuf, int maxout, const char *s, char *cmp)
2030 {
2031         const char *c;
2032
2033         if (!strncmp(s, cmp, strlen(cmp))) {
2034                 c = s + strlen(cmp);
2035                 term_color(outbuf, cmp, COLOR_GRAY, 0, maxout);
2036                 return c;
2037         }
2038         return NULL;
2039 }
2040
2041 /* These gymnastics are due to platforms which designate char as unsigned by
2042  * default. Level is the negative character -- offset by 1, because \0 is the
2043  * EOS delimiter. */
2044 #define VERBOSE_MAGIC2LEVEL(x) (((char) -*(signed char *) (x)) - 1)
2045 #define VERBOSE_HASMAGIC(x)     (*(signed char *) (x) < 0)
2046
2047 static void console_verboser(const char *s)
2048 {
2049         char tmp[80];
2050         const char *c = NULL;
2051         char level = 0;
2052
2053         if (VERBOSE_HASMAGIC(s)) {
2054                 level = VERBOSE_MAGIC2LEVEL(s);
2055                 s++;
2056                 if (level > option_verbose) {
2057                         return;
2058                 }
2059         }
2060
2061         if ((c = fix_header(tmp, sizeof(tmp), s, VERBOSE_PREFIX_4)) ||
2062             (c = fix_header(tmp, sizeof(tmp), s, VERBOSE_PREFIX_3)) ||
2063             (c = fix_header(tmp, sizeof(tmp), s, VERBOSE_PREFIX_2)) ||
2064             (c = fix_header(tmp, sizeof(tmp), s, VERBOSE_PREFIX_1))) {
2065                 fputs(tmp, stdout);
2066                 fputs(c, stdout);
2067         } else {
2068                 fputs(s, stdout);
2069         }
2070
2071         fflush(stdout);
2072
2073         /* Wake up a poll()ing console */
2074         if (ast_opt_console && consolethread != AST_PTHREADT_NULL) {
2075                 pthread_kill(consolethread, SIGURG);
2076         }
2077 }
2078
2079 static int ast_all_zeros(char *s)
2080 {
2081         while (*s) {
2082                 if (*s > 32)
2083                         return 0;
2084                 s++;
2085         }
2086         return 1;
2087 }
2088
2089 static void consolehandler(char *s)
2090 {
2091         printf("%s", term_end());
2092         fflush(stdout);
2093
2094         /* Called when readline data is available */
2095         if (!ast_all_zeros(s))
2096                 ast_el_add_history(s);
2097         /* The real handler for bang */
2098         if (s[0] == '!') {
2099                 if (s[1])
2100                         ast_safe_system(s+1);
2101                 else
2102                         ast_safe_system(getenv("SHELL") ? getenv("SHELL") : "/bin/sh");
2103         } else
2104                 ast_cli_command(STDOUT_FILENO, s);
2105 }
2106
2107 static int remoteconsolehandler(char *s)
2108 {
2109         int ret = 0;
2110
2111         /* Called when readline data is available */
2112         if (!ast_all_zeros(s))
2113                 ast_el_add_history(s);
2114         /* The real handler for bang */
2115         if (s[0] == '!') {
2116                 if (s[1])
2117                         ast_safe_system(s+1);
2118                 else
2119                         ast_safe_system(getenv("SHELL") ? getenv("SHELL") : "/bin/sh");
2120                 ret = 1;
2121         } else if (strncasecmp(s, "core set verbose ", 17) == 0) {
2122                 int old_verbose = option_verbose;
2123                 if (strncasecmp(s + 17, "atleast ", 8) == 0) {
2124                         int tmp;
2125                         if (sscanf(s + 25, "%d", &tmp) != 1) {
2126                                 fprintf(stderr, "Usage: core set verbose [atleast] <level>\n");
2127                         } else {
2128                                 if (tmp > option_verbose) {
2129                                         option_verbose = tmp;
2130                                 }
2131                                 if (old_verbose != option_verbose) {
2132                                         fprintf(stdout, "Set remote console verbosity from %d to %d\n", old_verbose, option_verbose);
2133                                 } else {
2134                                         fprintf(stdout, "Verbosity level unchanged.\n");
2135                                 }
2136                         }
2137                 } else {
2138                         if (sscanf(s + 17, "%d", &option_verbose) != 1) {
2139                                 fprintf(stderr, "Usage: core set verbose [atleast] <level>\n");
2140                         } else {
2141                                 if (old_verbose != option_verbose) {
2142                                         fprintf(stdout, "Set remote console verbosity to %d\n", option_verbose);
2143                                 } else {
2144                                         fprintf(stdout, "Verbosity level unchanged.\n");
2145                                 }
2146                         }
2147                 }
2148                 ret = 1;
2149         } else if ((strncasecmp(s, "quit", 4) == 0 || strncasecmp(s, "exit", 4) == 0) &&
2150             (s[4] == '\0' || isspace(s[4]))) {
2151                 quit_handler(0, SHUTDOWN_FAST, 0);
2152                 ret = 1;
2153         }
2154
2155         return ret;
2156 }
2157
2158 static char *handle_version(struct ast_cli_entry *e, int cmd, struct ast_cli_args *a)
2159 {
2160         switch (cmd) {
2161         case CLI_INIT:
2162                 e->command = "core show version";
2163                 e->usage =
2164                         "Usage: core show version\n"
2165                         "       Shows Asterisk version information.\n";
2166                 return NULL;
2167         case CLI_GENERATE:
2168                 return NULL;
2169         }
2170
2171         if (a->argc != 3)
2172                 return CLI_SHOWUSAGE;
2173         ast_cli(a->fd, "Asterisk %s built by %s @ %s on a %s running %s on %s\n",
2174                 ast_get_version(), ast_build_user, ast_build_hostname,
2175                 ast_build_machine, ast_build_os, ast_build_date);
2176         return CLI_SUCCESS;
2177 }
2178
2179 #if 0
2180 static int handle_quit(int fd, int argc, char *argv[])
2181 {
2182         if (argc != 1)
2183                 return RESULT_SHOWUSAGE;
2184         quit_handler(0, SHUTDOWN_NORMAL, 0);
2185         return RESULT_SUCCESS;
2186 }
2187 #endif
2188
2189 static char *handle_stop_now(struct ast_cli_entry *e, int cmd, struct ast_cli_args *a)
2190 {
2191         switch (cmd) {
2192         case CLI_INIT:
2193                 e->command = "core stop now";
2194                 e->usage =
2195                         "Usage: core stop now\n"
2196                         "       Shuts down a running Asterisk immediately, hanging up all active calls .\n";
2197                 return NULL;
2198         case CLI_GENERATE:
2199                 return NULL;
2200         }
2201
2202         if (a->argc != e->args)
2203                 return CLI_SHOWUSAGE;
2204         quit_handler(0, SHUTDOWN_NORMAL, 0 /* not restart */);
2205         return CLI_SUCCESS;
2206 }
2207
2208 static char *handle_stop_gracefully(struct ast_cli_entry *e, int cmd, struct ast_cli_args *a)
2209 {
2210         switch (cmd) {
2211         case CLI_INIT:
2212                 e->command = "core stop gracefully";
2213                 e->usage =
2214                         "Usage: core stop gracefully\n"
2215                         "       Causes Asterisk to not accept new calls, and exit when all\n"
2216                         "       active calls have terminated normally.\n";
2217                 return NULL;
2218         case CLI_GENERATE:
2219                 return NULL;
2220         }
2221
2222         if (a->argc != e->args)
2223                 return CLI_SHOWUSAGE;
2224         quit_handler(0, SHUTDOWN_NICE, 0 /* no restart */);
2225         return CLI_SUCCESS;
2226 }
2227
2228 static char *handle_stop_when_convenient(struct ast_cli_entry *e, int cmd, struct ast_cli_args *a)
2229 {
2230         switch (cmd) {
2231         case CLI_INIT:
2232                 e->command = "core stop when convenient";
2233                 e->usage =
2234                         "Usage: core stop when convenient\n"
2235                         "       Causes Asterisk to perform a shutdown when all active calls have ended.\n";
2236                 return NULL;
2237         case CLI_GENERATE:
2238                 return NULL;
2239         }
2240
2241         if (a->argc != e->args)
2242                 return CLI_SHOWUSAGE;
2243         ast_cli(a->fd, "Waiting for inactivity to perform halt\n");
2244         quit_handler(0, SHUTDOWN_REALLY_NICE, 0 /* don't restart */);
2245         return CLI_SUCCESS;
2246 }
2247
2248 static char *handle_restart_now(struct ast_cli_entry *e, int cmd, struct ast_cli_args *a)
2249 {
2250         switch (cmd) {
2251         case CLI_INIT:
2252                 e->command = "core restart now";
2253                 e->usage =
2254                         "Usage: core restart now\n"
2255                         "       Causes Asterisk to hangup all calls and exec() itself performing a cold\n"
2256                         "       restart.\n";
2257                 return NULL;
2258         case CLI_GENERATE:
2259                 return NULL;
2260         }
2261
2262         if (a->argc != e->args)
2263                 return CLI_SHOWUSAGE;
2264         quit_handler(0, SHUTDOWN_NORMAL, 1 /* restart */);
2265         return CLI_SUCCESS;
2266 }
2267
2268 static char *handle_restart_gracefully(struct ast_cli_entry *e, int cmd, struct ast_cli_args *a)
2269 {
2270         switch (cmd) {
2271         case CLI_INIT:
2272                 e->command = "core restart gracefully";
2273                 e->usage =
2274                         "Usage: core restart gracefully\n"
2275                         "       Causes Asterisk to stop accepting new calls and exec() itself performing a cold\n"
2276                         "       restart when all active calls have ended.\n";
2277                 return NULL;
2278         case CLI_GENERATE:
2279                 return NULL;
2280         }
2281
2282         if (a->argc != e->args)
2283                 return CLI_SHOWUSAGE;
2284         quit_handler(0, SHUTDOWN_NICE, 1 /* restart */);
2285         return CLI_SUCCESS;
2286 }
2287
2288 static char *handle_restart_when_convenient(struct ast_cli_entry *e, int cmd, struct ast_cli_args *a)
2289 {
2290         switch (cmd) {
2291         case CLI_INIT:
2292                 e->command = "core restart when convenient";
2293                 e->usage =
2294                         "Usage: core restart when convenient\n"
2295                         "       Causes Asterisk to perform a cold restart when all active calls have ended.\n";
2296                 return NULL;
2297         case CLI_GENERATE:
2298                 return NULL;
2299         }
2300
2301         if (a->argc != e->args)
2302                 return CLI_SHOWUSAGE;
2303         ast_cli(a->fd, "Waiting for inactivity to perform restart\n");
2304         quit_handler(0, SHUTDOWN_REALLY_NICE, 1 /* restart */);
2305         return CLI_SUCCESS;
2306 }
2307
2308 static char *handle_abort_shutdown(struct ast_cli_entry *e, int cmd, struct ast_cli_args *a)
2309 {
2310         int aborting_shutdown = 0;
2311
2312         switch (cmd) {
2313         case CLI_INIT:
2314                 e->command = "core abort shutdown";
2315                 e->usage =
2316                         "Usage: core abort shutdown\n"
2317                         "       Causes Asterisk to abort an executing shutdown or restart, and resume normal\n"
2318                         "       call operations.\n";
2319                 return NULL;
2320         case CLI_GENERATE:
2321                 return NULL;
2322         }
2323
2324         if (a->argc != e->args)
2325                 return CLI_SHOWUSAGE;
2326
2327         ast_mutex_lock(&safe_system_lock);
2328         if (shuttingdown >= SHUTDOWN_FAST) {
2329                 aborting_shutdown = 1;
2330                 shuttingdown = NOT_SHUTTING_DOWN;
2331         }
2332         ast_mutex_unlock(&safe_system_lock);
2333
2334         if (aborting_shutdown) {
2335                 ast_cancel_shutdown();
2336         }
2337         return CLI_SUCCESS;
2338 }
2339
2340 static char *handle_bang(struct ast_cli_entry *e, int cmd, struct ast_cli_args *a)
2341 {
2342         switch (cmd) {
2343         case CLI_INIT:
2344                 e->command = "!";
2345                 e->usage =
2346                         "Usage: !<command>\n"
2347                         "       Executes a given shell command\n";
2348                 return NULL;
2349         case CLI_GENERATE:
2350                 return NULL;
2351         }
2352
2353         return CLI_SUCCESS;
2354 }
2355 static const char warranty_lines[] = {
2356         "\n"
2357         "                           NO WARRANTY\n"
2358         "\n"
2359         "BECAUSE THE PROGRAM IS LICENSED FREE OF CHARGE, THERE IS NO WARRANTY\n"
2360         "FOR THE PROGRAM, TO THE EXTENT PERMITTED BY APPLICABLE LAW.  EXCEPT WHEN\n"
2361         "OTHERWISE STATED IN WRITING THE COPYRIGHT HOLDERS AND/OR OTHER PARTIES\n"
2362         "PROVIDE THE PROGRAM \"AS IS\" WITHOUT WARRANTY OF ANY KIND, EITHER EXPRESSED\n"
2363         "OR IMPLIED, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF\n"
2364         "MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE.  THE ENTIRE RISK AS\n"
2365         "TO THE QUALITY AND PERFORMANCE OF THE PROGRAM IS WITH YOU.  SHOULD THE\n"
2366         "PROGRAM PROVE DEFECTIVE, YOU ASSUME THE COST OF ALL NECESSARY SERVICING,\n"
2367         "REPAIR OR CORRECTION.\n"
2368         "\n"
2369         "IN NO EVENT UNLESS REQUIRED BY APPLICABLE LAW OR AGREED TO IN WRITING\n"
2370         "WILL ANY COPYRIGHT HOLDER, OR ANY OTHER PARTY WHO MAY MODIFY AND/OR\n"
2371         "REDISTRIBUTE THE PROGRAM AS PERMITTED ABOVE, BE LIABLE TO YOU FOR DAMAGES,\n"
2372         "INCLUDING ANY GENERAL, SPECIAL, INCIDENTAL OR CONSEQUENTIAL DAMAGES ARISING\n"
2373         "OUT OF THE USE OR INABILITY TO USE THE PROGRAM (INCLUDING BUT NOT LIMITED\n"
2374         "TO LOSS OF DATA OR DATA BEING RENDERED INACCURATE OR LOSSES SUSTAINED BY\n"
2375         "YOU OR THIRD PARTIES OR A FAILURE OF THE PROGRAM TO OPERATE WITH ANY OTHER\n"
2376         "PROGRAMS), EVEN IF SUCH HOLDER OR OTHER PARTY HAS BEEN ADVISED OF THE\n"
2377         "POSSIBILITY OF SUCH DAMAGES.\n"
2378 };
2379
2380 static char *show_warranty(struct ast_cli_entry *e, int cmd, struct ast_cli_args *a)
2381 {
2382         switch (cmd) {
2383         case CLI_INIT:
2384                 e->command = "core show warranty";
2385                 e->usage =
2386                         "Usage: core show warranty\n"
2387                         "       Shows the warranty (if any) for this copy of Asterisk.\n";
2388                 return NULL;
2389         case CLI_GENERATE:
2390                 return NULL;
2391         }
2392
2393         ast_cli(a->fd, "%s", warranty_lines);
2394
2395         return CLI_SUCCESS;
2396 }
2397
2398 static const char license_lines[] = {
2399         "\n"
2400         "This program is free software; you can redistribute it and/or modify\n"
2401         "it under the terms of the GNU General Public License version 2 as\n"
2402         "published by the Free Software Foundation.\n"
2403         "\n"
2404         "This program also contains components licensed under other licenses.\n"
2405         "They include:\n"
2406         "\n"
2407         "This program is distributed in the hope that it will be useful,\n"
2408         "but WITHOUT ANY WARRANTY; without even the implied warranty of\n"
2409         "MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the\n"
2410         "GNU General Public License for more details.\n"
2411         "\n"
2412         "You should have received a copy of the GNU General Public License\n"
2413         "along with this program; if not, write to the Free Software\n"
2414         "Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA\n"
2415 };
2416
2417 static char *show_license(struct ast_cli_entry *e, int cmd, struct ast_cli_args *a)
2418 {
2419         switch (cmd) {
2420         case CLI_INIT:
2421                 e->command = "core show license";
2422                 e->usage =
2423                         "Usage: core show license\n"
2424                         "       Shows the license(s) for this copy of Asterisk.\n";
2425                 return NULL;
2426         case CLI_GENERATE:
2427                 return NULL;
2428         }
2429
2430         ast_cli(a->fd, "%s", license_lines);
2431
2432         return CLI_SUCCESS;
2433 }
2434
2435 #define ASTERISK_PROMPT "*CLI> "
2436
2437 #define ASTERISK_PROMPT2 "%s*CLI> "
2438
2439 /*!
2440  * \brief Shutdown Asterisk CLI commands.
2441  *
2442  * \note These CLI commands cannot be unregistered at shutdown
2443  * because one of them is likely the reason for the shutdown.
2444  * The CLI generates a warning if a command is in-use when it is
2445  * unregistered.
2446  */
2447 static struct ast_cli_entry cli_asterisk_shutdown[] = {
2448         AST_CLI_DEFINE(handle_stop_now, "Shut down Asterisk immediately"),
2449         AST_CLI_DEFINE(handle_stop_gracefully, "Gracefully shut down Asterisk"),
2450         AST_CLI_DEFINE(handle_stop_when_convenient, "Shut down Asterisk at empty call volume"),
2451         AST_CLI_DEFINE(handle_restart_now, "Restart Asterisk immediately"),
2452         AST_CLI_DEFINE(handle_restart_gracefully, "Restart Asterisk gracefully"),
2453         AST_CLI_DEFINE(handle_restart_when_convenient, "Restart Asterisk at empty call volume"),
2454 };
2455
2456 static struct ast_cli_entry cli_asterisk[] = {
2457         AST_CLI_DEFINE(handle_abort_shutdown, "Cancel a running shutdown"),
2458         AST_CLI_DEFINE(show_warranty, "Show the warranty (if any) for this copy of Asterisk"),
2459         AST_CLI_DEFINE(show_license, "Show the license(s) for this copy of Asterisk"),
2460         AST_CLI_DEFINE(handle_version, "Display version info"),
2461         AST_CLI_DEFINE(handle_bang, "Execute a shell command"),
2462 #if !defined(LOW_MEMORY)
2463         AST_CLI_DEFINE(handle_show_version_files, "List versions of files used to build Asterisk"),
2464         AST_CLI_DEFINE(handle_show_threads, "Show running threads"),
2465 #if defined(HAVE_SYSINFO) || defined(HAVE_SYSCTL)
2466         AST_CLI_DEFINE(handle_show_sysinfo, "Show System Information"),
2467 #endif
2468         AST_CLI_DEFINE(handle_show_profile, "Display profiling info"),
2469         AST_CLI_DEFINE(handle_show_settings, "Show some core settings"),
2470         AST_CLI_DEFINE(handle_clear_profile, "Clear profiling info"),
2471 #endif /* ! LOW_MEMORY */
2472 };
2473
2474 struct el_read_char_state_struct {
2475         unsigned int line_full:1;
2476         unsigned int prev_line_full:1;
2477         char prev_line_verbosity;
2478 };
2479
2480 static int el_read_char_state_init(void *ptr)
2481 {
2482         struct el_read_char_state_struct *state = ptr;
2483         state->line_full = 1;
2484         state->prev_line_full = 1;
2485         state->prev_line_verbosity = 0;
2486         return 0;
2487 }
2488
2489 AST_THREADSTORAGE_CUSTOM(el_read_char_state, el_read_char_state_init, ast_free_ptr);
2490
2491 static int ast_el_read_char(EditLine *editline, char *cp)
2492 {
2493         int num_read = 0;
2494         int lastpos = 0;
2495         struct pollfd fds[2];
2496         int res;
2497         int max;
2498 #define EL_BUF_SIZE 512
2499         char buf[EL_BUF_SIZE];
2500         struct el_read_char_state_struct *state = ast_threadstorage_get(&el_read_char_state, sizeof(*state));
2501
2502         for (;;) {
2503                 max = 1;
2504                 fds[0].fd = ast_consock;
2505                 fds[0].events = POLLIN;
2506                 if (!ast_opt_exec) {
2507                         fds[1].fd = STDIN_FILENO;
2508                         fds[1].events = POLLIN;
2509                         max++;
2510                 }
2511                 res = ast_poll(fds, max, -1);
2512                 if (res < 0) {
2513                         if (sig_flags.need_quit || sig_flags.need_quit_handler)
2514                                 break;
2515                         if (errno == EINTR)
2516                                 continue;
2517                         fprintf(stderr, "poll failed: %s\n", strerror(errno));
2518                         break;
2519                 }
2520
2521                 if (!ast_opt_exec && fds[1].revents) {
2522                         num_read = read(STDIN_FILENO, cp, 1);
2523                         if (num_read < 1) {
2524                                 break;
2525                         } else {
2526                                 return (num_read);
2527                         }
2528                 }
2529                 if (fds[0].revents) {
2530                         char level = 0;
2531                         char *curline = buf, *nextline;
2532                         res = read(ast_consock, buf, sizeof(buf) - 1);
2533                         /* if the remote side disappears exit */
2534                         if (res < 1) {
2535                                 fprintf(stderr, "\nDisconnected from Asterisk server\n");
2536                                 if (!ast_opt_reconnect) {
2537                                         quit_handler(0, SHUTDOWN_FAST, 0);
2538                                 } else {
2539                                         int tries;
2540                                         int reconnects_per_second = 20;
2541                                         fprintf(stderr, "Attempting to reconnect for 30 seconds\n");
2542                                         for (tries = 0; tries < 30 * reconnects_per_second; tries++) {
2543                                                 if (ast_tryconnect()) {
2544                                                         fprintf(stderr, "Reconnect succeeded after %.3f seconds\n", 1.0 / reconnects_per_second * tries);
2545                                                         printf("%s", term_quit());
2546                                                         WELCOME_MESSAGE;
2547                                                         if (!ast_opt_mute)
2548                                                                 fdsend(ast_consock, "logger mute silent");
2549                                                         else
2550                                                                 printf("log and verbose output currently muted ('logger mute' to unmute)\n");
2551                                                         break;
2552                                                 } else
2553                                                         usleep(1000000 / reconnects_per_second);
2554                                         }
2555                                         if (tries >= 30 * reconnects_per_second) {
2556                                                 fprintf(stderr, "Failed to reconnect for 30 seconds.  Quitting.\n");
2557                                                 quit_handler(0, SHUTDOWN_FAST, 0);
2558                                         }
2559                                 }
2560                                 continue;
2561                         }
2562
2563                         buf[res] = '\0';
2564
2565                         /* Write over the CLI prompt */
2566                         if (!ast_opt_exec && !lastpos) {
2567                                 if (write(STDOUT_FILENO, "\r\e[0K", 5) < 0) {
2568                                 }
2569                         }
2570
2571                         do {
2572                                 state->prev_line_full = state->line_full;
2573                                 if ((nextline = strchr(curline, '\n'))) {
2574                                         state->line_full = 1;
2575                                         nextline++;
2576                                 } else {
2577                                         state->line_full = 0;
2578                                         nextline = strchr(curline, '\0');
2579                                 }
2580
2581                                 if (state->prev_line_full && VERBOSE_HASMAGIC(curline)) {
2582                                         level = VERBOSE_MAGIC2LEVEL(curline);
2583                                         curline++;
2584                                 } else if (state->prev_line_full && !VERBOSE_HASMAGIC(curline)) {
2585                                         /* Non-verbose output */
2586                                         level = 0;
2587                                 } else {
2588                                         level = state->prev_line_verbosity;
2589                                 }
2590                                 if ((!state->prev_line_full && state->prev_line_verbosity <= option_verbose) || (state->prev_line_full && level <= option_verbose)) {
2591                                         if (write(STDOUT_FILENO, curline, nextline - curline) < 0) {
2592                                         }
2593                                 }
2594
2595                                 state->prev_line_verbosity = level;
2596                                 curline = nextline;
2597                         } while (!ast_strlen_zero(curline));
2598
2599                         if ((res < EL_BUF_SIZE - 1) && ((buf[res-1] == '\n') || (buf[res-2] == '\n'))) {
2600                                 *cp = CC_REFRESH;
2601                                 return(1);
2602                         } else
2603                                 lastpos = 1;
2604                 }
2605         }
2606
2607         *cp = '\0';
2608         return (0);
2609 }
2610
2611 static struct ast_str *prompt = NULL;
2612
2613 static char *cli_prompt(EditLine *editline)
2614 {
2615         char tmp[100];
2616         char *pfmt;
2617         int color_used = 0;
2618         static int cli_prompt_changes = 0;
2619         struct passwd *pw;
2620         struct group *gr;
2621
2622         if (prompt == NULL) {
2623                 prompt = ast_str_create(100);
2624         } else if (!cli_prompt_changes) {
2625                 return ast_str_buffer(prompt);
2626         } else {
2627                 ast_str_reset(prompt);
2628         }
2629
2630         if ((pfmt = getenv("ASTERISK_PROMPT"))) {
2631                 char *t = pfmt;
2632                 struct timeval ts = ast_tvnow();
2633                 while (*t != '\0') {
2634                         if (*t == '%') {
2635                                 char hostname[MAXHOSTNAMELEN] = "";
2636                                 int i, which;
2637                                 struct ast_tm tm = { 0, };
2638                                 int fgcolor = COLOR_WHITE, bgcolor = COLOR_BLACK;
2639
2640                                 t++;
2641                                 switch (*t) {
2642                                 case 'C': /* color */
2643                                         t++;
2644                                         if (sscanf(t, "%30d;%30d%n", &fgcolor, &bgcolor, &i) == 2) {
2645                                                 ast_term_color_code(&prompt, fgcolor, bgcolor);
2646                                                 t += i - 1;
2647                                         } else if (sscanf(t, "%30d%n", &fgcolor, &i) == 1) {
2648                                                 ast_term_color_code(&prompt, fgcolor, 0);
2649                                                 t += i - 1;
2650                                         }
2651
2652                                         /* If the color has been reset correctly, then there's no need to reset it later */
2653                                         color_used = ((fgcolor == COLOR_WHITE) && (bgcolor == COLOR_BLACK)) ? 0 : 1;
2654                                         break;
2655                                 case 'd': /* date */
2656                                         if (ast_localtime(&ts, &tm, NULL)) {
2657                                                 ast_strftime(tmp, sizeof(tmp), "%Y-%m-%d", &tm);
2658                                                 ast_str_append(&prompt, 0, "%s", tmp);
2659                                                 cli_prompt_changes++;
2660                                         }
2661                                         break;
2662                                 case 'g': /* group */
2663                                         if ((gr = getgrgid(getgid()))) {
2664                                                 ast_str_append(&prompt, 0, "%s", gr->gr_name);
2665                                         }
2666                                         break;
2667                                 case 'h': /* hostname */
2668                                         if (!gethostname(hostname, sizeof(hostname) - 1)) {
2669                                                 ast_str_append(&prompt, 0, "%s", hostname);
2670                                         } else {
2671                                                 ast_str_append(&prompt, 0, "%s", "localhost");
2672                                         }
2673                                         break;
2674                                 case 'H': /* short hostname */
2675                                         if (!gethostname(hostname, sizeof(hostname) - 1)) {
2676                                                 char *dotptr;
2677                                                 if ((dotptr = strchr(hostname, '.'))) {
2678                                                         *dotptr = '\0';
2679                                                 }
2680                                                 ast_str_append(&prompt, 0, "%s", hostname);
2681                                         } else {
2682                                                 ast_str_append(&prompt, 0, "%s", "localhost");
2683                                         }
2684                                         break;
2685 #ifdef HAVE_GETLOADAVG
2686                                 case 'l': /* load avg */
2687                                         t++;
2688                                         if (sscanf(t, "%30d", &which) == 1 && which > 0 && which <= 3) {
2689                                                 double list[3];
2690                                                 getloadavg(list, 3);
2691                                                 ast_str_append(&prompt, 0, "%.2f", list[which - 1]);
2692                                                 cli_prompt_changes++;
2693                                         }
2694                                         break;
2695 #endif
2696                                 case 's': /* Asterisk system name (from asterisk.conf) */
2697                                         ast_str_append(&prompt, 0, "%s", ast_config_AST_SYSTEM_NAME);
2698                                         break;
2699                                 case 't': /* time */
2700                                         if (ast_localtime(&ts, &tm, NULL)) {
2701                                                 ast_strftime(tmp, sizeof(tmp), "%H:%M:%S", &tm);
2702                                                 ast_str_append(&prompt, 0, "%s", tmp);
2703                                                 cli_prompt_changes++;
2704                                         }
2705                                         break;
2706                                 case 'u': /* username */
2707                                         if ((pw = getpwuid(getuid()))) {
2708                                                 ast_str_append(&prompt, 0, "%s", pw->pw_name);
2709                                         }
2710                                         break;
2711                                 case '#': /* process console or remote? */
2712                                         ast_str_append(&prompt, 0, "%c", ast_opt_remote ? '>' : '#');
2713                                         break;
2714                                 case '%': /* literal % */
2715                                         ast_str_append(&prompt, 0, "%c", '%');
2716                                         break;
2717                                 case '\0': /* % is last character - prevent bug */
2718                                         t--;
2719                                         break;
2720                                 }
2721                         } else {
2722                                 ast_str_append(&prompt, 0, "%c", *t);
2723                         }
2724                         t++;
2725                 }
2726                 if (color_used) {
2727                         /* Force colors back to normal at end */
2728                         ast_term_color_code(&prompt, 0, 0);
2729                 }
2730         } else if (remotehostname) {
2731                 ast_str_set(&prompt, 0, ASTERISK_PROMPT2, remotehostname);
2732         } else {
2733                 ast_str_set(&prompt, 0, "%s", ASTERISK_PROMPT);
2734         }
2735
2736         return ast_str_buffer(prompt);
2737 }
2738
2739 static char **ast_el_strtoarr(char *buf)
2740 {
2741         char **match_list = NULL, **match_list_tmp, *retstr;
2742         size_t match_list_len;
2743         int matches = 0;
2744
2745         match_list_len = 1;
2746         while ( (retstr = strsep(&buf, " ")) != NULL) {
2747
2748                 if (!strcmp(retstr, AST_CLI_COMPLETE_EOF))
2749                         break;
2750                 if (matches + 1 >= match_list_len) {
2751                         match_list_len <<= 1;
2752                         if ((match_list_tmp = ast_realloc(match_list, match_list_len * sizeof(char *)))) {
2753                                 match_list = match_list_tmp;
2754                         } else {
2755                                 if (match_list)
2756                                         ast_free(match_list);
2757                                 return (char **) NULL;
2758                         }
2759                 }
2760
2761                 match_list[matches++] = ast_strdup(retstr);
2762         }
2763
2764         if (!match_list)
2765                 return (char **) NULL;
2766
2767         if (matches >= match_list_len) {
2768                 if ((match_list_tmp = ast_realloc(match_list, (match_list_len + 1) * sizeof(char *)))) {
2769                         match_list = match_list_tmp;
2770                 } else {
2771                         if (match_list)
2772                                 ast_free(match_list);
2773                         return (char **) NULL;
2774                 }
2775         }
2776
2777         match_list[matches] = (char *) NULL;
2778
2779         return match_list;
2780 }
2781
2782 static int ast_el_sort_compare(const void *i1, const void *i2)
2783 {
2784         char *s1, *s2;
2785
2786         s1 = ((char **)i1)[0];
2787         s2 = ((char **)i2)[0];
2788
2789         return strcasecmp(s1, s2);
2790 }
2791
2792 static int ast_cli_display_match_list(char **matches, int len, int max)
2793 {
2794         int i, idx, limit, count;
2795         int screenwidth = 0;
2796         int numoutput = 0, numoutputline = 0;
2797
2798         screenwidth = ast_get_termcols(STDOUT_FILENO);
2799
2800         /* find out how many entries can be put on one line, with two spaces between strings */
2801         limit = screenwidth / (max + 2);
2802         if (limit == 0)
2803                 limit = 1;
2804
2805         /* how many lines of output */
2806         count = len / limit;
2807         if (count * limit < len)
2808                 count++;
2809
2810         idx = 1;
2811
2812         qsort(&matches[0], (size_t)(len), sizeof(char *), ast_el_sort_compare);
2813
2814         for (; count > 0; count--) {
2815                 numoutputline = 0;
2816                 for (i = 0; i < limit && matches[idx]; i++, idx++) {
2817
2818                         /* Don't print dupes */
2819                         if ( (matches[idx+1] != NULL && strcmp(matches[idx], matches[idx+1]) == 0 ) ) {
2820                                 i--;
2821                                 ast_free(matches[idx]);
2822                                 matches[idx] = NULL;
2823                                 continue;
2824                         }
2825
2826                         numoutput++;
2827                         numoutputline++;
2828                         fprintf(stdout, "%-*s  ", max, matches[idx]);
2829                         ast_free(matches[idx]);
2830                         matches[idx] = NULL;
2831                 }
2832                 if (numoutputline > 0)
2833                         fprintf(stdout, "\n");
2834         }
2835
2836         return numoutput;
2837 }
2838
2839
2840 static char *cli_complete(EditLine *editline, int ch)
2841 {
2842         int len = 0;
2843         char *ptr;
2844         int nummatches = 0;
2845         char **matches;
2846         int retval = CC_ERROR;
2847         char buf[2048], savechr;
2848         int res;
2849
2850         LineInfo *lf = (LineInfo *)el_line(editline);
2851
2852         savechr = *(char *)lf->cursor;
2853         *(char *)lf->cursor = '\0';
2854         ptr = (char *)lf->cursor;
2855         if (ptr) {
2856                 while (ptr > lf->buffer) {
2857                         if (isspace(*ptr)) {
2858                                 ptr++;
2859                                 break;
2860                         }
2861                         ptr--;
2862                 }
2863         }
2864
2865         len = lf->cursor - ptr;
2866
2867         if (ast_opt_remote) {
2868                 snprintf(buf, sizeof(buf), "_COMMAND NUMMATCHES \"%s\" \"%s\"", lf->buffer, ptr);
2869                 fdsend(ast_consock, buf);
2870                 if ((res = read(ast_consock, buf, sizeof(buf) - 1)) < 0) {
2871                         return (char*)(CC_ERROR);
2872                 }
2873                 buf[res] = '\0';
2874                 nummatches = atoi(buf);
2875
2876                 if (nummatches > 0) {
2877                         char *mbuf;
2878                         int mlen = 0, maxmbuf = 2048;
2879                         /* Start with a 2048 byte buffer */
2880                         if (!(mbuf = ast_malloc(maxmbuf))) {
2881                                 *((char *) lf->cursor) = savechr;
2882                                 return (char *)(CC_ERROR);
2883                         }
2884                         snprintf(buf, sizeof(buf), "_COMMAND MATCHESARRAY \"%s\" \"%s\"", lf->buffer, ptr);
2885                         fdsend(ast_consock, buf);
2886                         res = 0;
2887                         mbuf[0] = '\0';
2888                         while (!strstr(mbuf, AST_CLI_COMPLETE_EOF) && res != -1) {
2889                                 if (mlen + 1024 > maxmbuf) {
2890                                         /* Every step increment buffer 1024 bytes */
2891                                         maxmbuf += 1024;
2892                                         if (!(mbuf = ast_realloc(mbuf, maxmbuf))) {
2893                                                 *((char *) lf->cursor) = savechr;
2894                                                 return (char *)(CC_ERROR);
2895                                         }
2896                                 }
2897                                 /* Only read 1024 bytes at a time */
2898                                 res = read(ast_consock, mbuf + mlen, 1024);
2899                                 if (res > 0)
2900                                         mlen += res;
2901                         }
2902                         mbuf[mlen] = '\0';
2903
2904                         matches = ast_el_strtoarr(mbuf);
2905                         ast_free(mbuf);
2906                 } else
2907                         matches = (char **) NULL;
2908         } else {
2909                 char **p, *oldbuf=NULL;
2910                 nummatches = 0;
2911                 matches = ast_cli_completion_matches((char *)lf->buffer,ptr);
2912                 for (p = matches; p && *p; p++) {
2913                         if (!oldbuf || strcmp(*p,oldbuf))
2914                                 nummatches++;
2915                         oldbuf = *p;
2916                 }
2917         }
2918
2919         if (matches) {
2920                 int i;
2921                 int matches_num, maxlen, match_len;
2922
2923                 if (matches[0][0] != '\0') {
2924                         el_deletestr(editline, (int) len);
2925                         el_insertstr(editline, matches[0]);
2926                         retval = CC_REFRESH;
2927                 }
2928
2929                 if (nummatches == 1) {
2930                         /* Found an exact match */
2931                         el_insertstr(editline, " ");
2932                         retval = CC_REFRESH;
2933                 } else {
2934                         /* Must be more than one match */
2935                         for (i = 1, maxlen = 0; matches[i]; i++) {
2936                                 match_len = strlen(matches[i]);
2937                                 if (match_len > maxlen)
2938                                         maxlen = match_len;
2939                         }
2940                         matches_num = i - 1;
2941                         if (matches_num >1) {
2942                                 fprintf(stdout, "\n");
2943                                 ast_cli_display_match_list(matches, nummatches, maxlen);
2944                                 retval = CC_REDISPLAY;
2945                         } else {
2946                                 el_insertstr(editline," ");
2947                                 retval = CC_REFRESH;
2948                         }
2949                 }
2950                 for (i = 0; matches[i]; i++)
2951                         ast_free(matches[i]);
2952                 ast_free(matches);
2953         }
2954
2955         *((char *) lf->cursor) = savechr;
2956
2957         return (char *)(long)retval;
2958 }
2959
2960 static int ast_el_initialize(void)
2961 {
2962         HistEvent ev;
2963         char *editor, *editrc = getenv("EDITRC");
2964
2965         if (!(editor = getenv("AST_EDITMODE"))) {
2966                 if (!(editor = getenv("AST_EDITOR"))) {
2967                         editor = "emacs";
2968                 }
2969         }
2970
2971         if (el != NULL)
2972                 el_end(el);
2973         if (el_hist != NULL)
2974                 history_end(el_hist);
2975
2976         el = el_init("asterisk", stdin, stdout, stderr);
2977         el_set(el, EL_PROMPT, cli_prompt);
2978
2979         el_set(el, EL_EDITMODE, 1);
2980         el_set(el, EL_EDITOR, editor);
2981         el_hist = history_init();
2982         if (!el || !el_hist)
2983                 return -1;
2984
2985         /* setup history with 100 entries */
2986         history(el_hist, &ev, H_SETSIZE, 100);
2987
2988         el_set(el, EL_HIST, history, el_hist);
2989
2990         el_set(el, EL_ADDFN, "ed-complete", "Complete argument", cli_complete);
2991         /* Bind <tab> to command completion */
2992         el_set(el, EL_BIND, "^I", "ed-complete", NULL);
2993         /* Bind ? to command completion */
2994         el_set(el, EL_BIND, "?", "ed-complete", NULL);
2995         /* Bind ^D to redisplay */
2996         el_set(el, EL_BIND, "^D", "ed-redisplay", NULL);
2997         /* Bind Delete to delete char left */
2998         el_set(el, EL_BIND, "\\e[3~", "ed-delete-next-char", NULL);
2999         /* Bind Home and End to move to line start and end */
3000         el_set(el, EL_BIND, "\\e[1~", "ed-move-to-beg", NULL);
3001         el_set(el, EL_BIND, "\\e[4~", "ed-move-to-end", NULL);
3002         /* Bind C-left and C-right to move by word (not all terminals) */
3003         el_set(el, EL_BIND, "\\eOC", "vi-next-word", NULL);
3004         el_set(el, EL_BIND, "\\eOD", "vi-prev-word", NULL);
3005
3006         if (editrc) {
3007                 el_source(el, editrc);
3008         }
3009
3010         return 0;
3011 }
3012
3013 #define MAX_HISTORY_COMMAND_LENGTH 256
3014
3015 static int ast_el_add_history(char *buf)
3016 {
3017         HistEvent ev;
3018
3019         if (el_hist == NULL || el == NULL)
3020                 ast_el_initialize();
3021         if (strlen(buf) > (MAX_HISTORY_COMMAND_LENGTH - 1))
3022                 return 0;
3023         return (history(el_hist, &ev, H_ENTER, ast_strip(ast_strdupa(buf))));
3024 }
3025
3026 static int ast_el_write_history(char *filename)
3027 {
3028         HistEvent ev;
3029
3030         if (el_hist == NULL || el == NULL)
3031                 ast_el_initialize();
3032
3033         return (history(el_hist, &ev, H_SAVE, filename));
3034 }
3035
3036 static int ast_el_read_history(char *filename)
3037 {
3038         HistEvent ev;
3039
3040         if (el_hist == NULL || el == NULL) {
3041                 ast_el_initialize();
3042         }
3043
3044         return history(el_hist, &ev, H_LOAD, filename);
3045 }
3046
3047 static void ast_remotecontrol(char *data)
3048 {
3049         char buf[80];
3050         int res;
3051         char filename[80] = "";
3052         char *hostname;
3053         char *cpid;
3054         char *version;
3055         int pid;
3056         char *stringp = NULL;
3057
3058         char *ebuf;
3059         int num = 0;
3060
3061         memset(&sig_flags, 0, sizeof(sig_flags));
3062         signal(SIGINT, __remote_quit_handler);
3063         signal(SIGTERM, __remote_quit_handler);
3064         signal(SIGHUP, __remote_quit_handler);
3065
3066         if (read(ast_consock, buf, sizeof(buf)) < 0) {
3067                 ast_log(LOG_ERROR, "read() failed: %s\n", strerror(errno));
3068                 return;
3069         }
3070         if (data) {
3071                 char prefix[] = "cli quit after ";
3072                 char *tmp = ast_alloca(strlen(data) + strlen(prefix) + 1);
3073                 sprintf(tmp, "%s%s", prefix, data);
3074                 if (write(ast_consock, tmp, strlen(tmp) + 1) < 0) {
3075                         ast_log(LOG_ERROR, "write() failed: %s\n", strerror(errno));
3076                         if (sig_flags.need_quit || sig_flags.need_quit_handler) {
3077                                 return;
3078                         }
3079                 }
3080         }
3081         stringp = buf;
3082         hostname = strsep(&stringp, "/");
3083         cpid = strsep(&stringp, "/");
3084         version = strsep(&stringp, "\n");
3085         if (!version)
3086                 version = "<Version Unknown>";
3087         stringp = hostname;
3088         strsep(&stringp, ".");
3089         if (cpid)
3090                 pid = atoi(cpid);
3091         else
3092                 pid = -1;
3093         if (!data) {
3094                 if (!ast_opt_mute) {
3095                         fdsend(ast_consock, "logger mute silent");
3096                 } else {
3097                         printf("log and verbose output currently muted ('logger mute' to unmute)\n");
3098                 }
3099         }
3100
3101         if (ast_opt_exec && data) {  /* hack to print output then exit if asterisk -rx is used */
3102                 int linefull = 1, prev_linefull = 1, prev_line_verbose = 0;
3103                 struct pollfd fds;
3104                 fds.fd = ast_consock;
3105                 fds.events = POLLIN;
3106                 fds.revents = 0;
3107
3108                 while (ast_poll(&fds, 1, 60000) > 0) {
3109                         char buffer[512] = "", *curline = buffer, *nextline;
3110                         int not_written = 1;
3111
3112                         if (sig_flags.need_quit || sig_flags.need_quit_handler) {
3113                                 break;
3114                         }
3115
3116                         if (read(ast_consock, buffer, sizeof(buffer) - 1) <= 0) {
3117                                 break;
3118                         }
3119
3120                         do {
3121                                 prev_linefull = linefull;
3122                                 if ((nextline = strchr(curline, '\n'))) {
3123                                         linefull = 1;
3124                                         nextline++;
3125                                 } else {
3126                                         linefull = 0;
3127                                         nextline = strchr(curline, '\0');
3128                                 }
3129
3130                                 /* Skip verbose lines */
3131                                 /* Prev line full? | Line is verbose | Last line verbose? | Print
3132                                  * TRUE            | TRUE*           | TRUE               | FALSE
3133                                  * TRUE            | TRUE*           | FALSE              | FALSE
3134                                  * TRUE            | FALSE*          | TRUE               | TRUE
3135                                  * TRUE            | FALSE*          | FALSE              | TRUE
3136                                  * FALSE           | TRUE            | TRUE*              | FALSE
3137                                  * FALSE           | TRUE            | FALSE*             | TRUE
3138                                  * FALSE           | FALSE           | TRUE*              | FALSE
3139                                  * FALSE           | FALSE           | FALSE*             | TRUE
3140                                  */
3141                                 if ((!prev_linefull && !prev_line_verbose) || (prev_linefull && *curline > 0)) {
3142                                         prev_line_verbose = 0;
3143                                         not_written = 0;
3144                                         if (write(STDOUT_FILENO, curline, nextline - curline) < 0) {
3145                                                 ast_log(LOG_WARNING, "write() failed: %s\n", strerror(errno));
3146                                         }
3147                                 } else {
3148                                         prev_line_verbose = 1;
3149                                 }
3150                                 curline = nextline;
3151                         } while (!ast_strlen_zero(curline));
3152
3153                         /* No non-verbose output in 60 seconds. */
3154                         if (not_written) {
3155                                 break;
3156                         }
3157                 }
3158                 return;
3159         }
3160
3161         ast_verbose("Connected to Asterisk %s currently running on %s (pid = %d)\n", version, hostname, pid);
3162         remotehostname = hostname;
3163         if (getenv("HOME"))
3164                 snprintf(filename, sizeof(filename), "%s/.asterisk_history", getenv("HOME"));
3165         if (el_hist == NULL || el == NULL)
3166                 ast_el_initialize();
3167
3168         el_set(el, EL_GETCFN, ast_el_read_char);
3169
3170         if (!ast_strlen_zero(filename))
3171                 ast_el_read_history(filename);
3172
3173         for (;;) {
3174                 ebuf = (char *)el_gets(el, &num);
3175
3176                 if (sig_flags.need_quit || sig_flags.need_quit_handler) {
3177                         break;
3178                 }
3179
3180                 if (!ebuf && write(1, "", 1) < 0)
3181                         break;
3182
3183                 if (!ast_strlen_zero(ebuf)) {
3184                         if (ebuf[strlen(ebuf)-1] == '\n')
3185                                 ebuf[strlen(ebuf)-1] = '\0';
3186                         if (!remoteconsolehandler(ebuf)) {
3187                                 res = write(ast_consock, ebuf, strlen(ebuf) + 1);
3188                                 if (res < 1) {
3189                                         ast_log(LOG_WARNING, "Unable to write: %s\n", strerror(errno));
3190                                         break;
3191                                 }
3192                         }
3193                 }
3194         }
3195         printf("\nDisconnected from Asterisk server\n");
3196 }
3197
3198 static int show_version(void)
3199 {
3200         printf("Asterisk %s\n", ast_get_version());
3201         return 0;
3202 }
3203
3204 static int show_cli_help(void)
3205 {
3206         printf("Asterisk %s, Copyright (C) 1999 - 2012, Digium, Inc. and others.\n", ast_get_version());
3207         printf("Usage: asterisk [OPTIONS]\n");
3208         printf("Valid Options:\n");
3209         printf("   -V              Display version number and exit\n");
3210         printf("   -C <configfile> Use an alternate configuration file\n");
3211         printf("   -G <group>      Run as a group other than the caller\n");
3212         printf("   -U <user>       Run as a user other than the caller\n");
3213         printf("   -c              Provide console CLI\n");
3214         printf("   -d              Enable extra debugging\n");
3215 #if HAVE_WORKING_FORK
3216         printf("   -f              Do not fork\n");
3217         printf("   -F              Always fork\n");
3218 #endif
3219         printf("   -g              Dump core in case of a crash\n");
3220         printf("   -h              This help screen\n");
3221         printf("   -i              Initialize crypto keys at startup\n");
3222         printf("   -I              Enable internal timing if DAHDI timer is available\n");
3223         printf("   -L <load>       Limit the maximum load average before rejecting new calls\n");
3224         printf("   -M <value>      Limit the maximum number of calls to the specified value\n");
3225         printf("   -m              Mute debugging and console output on the console\n");
3226         printf("   -n              Disable console colorization\n");
3227         printf("   -p              Run as pseudo-realtime thread\n");
3228         printf("   -q              Quiet mode (suppress output)\n");
3229         printf("   -r              Connect to Asterisk on this machine\n");
3230         printf("   -R              Same as -r, except attempt to reconnect if disconnected\n");
3231         printf("   -s <socket>     Connect to Asterisk via socket <socket> (only valid with -r)\n");
3232         printf("   -t              Record soundfiles in /var/tmp and move them where they\n");
3233         printf("                   belong after they are done\n");
3234         printf("   -T              Display the time in [Mmm dd hh:mm:ss] format for each line\n");
3235         printf("                   of output to the CLI\n");
3236         printf("   -v              Increase verbosity (multiple v's = more verbose)\n");
3237         printf("   -x <cmd>        Execute command <cmd> (implies -r)\n");
3238         printf("   -X              Execute includes by default (allows #exec in asterisk.conf)\n");
3239         printf("   -W              Adjust terminal colors to compensate for a light background\n");
3240         printf("\n");
3241         return 0;
3242 }
3243
3244 static void ast_readconfig(void)
3245 {
3246         struct ast_config *cfg;
3247         struct ast_variable *v;
3248         char *config = DEFAULT_CONFIG_FILE;
3249         char hostname[MAXHOSTNAMELEN] = "";
3250         struct ast_flags config_flags = { CONFIG_FLAG_NOREALTIME };
3251         struct {
3252                 unsigned int dbdir:1;
3253                 unsigned int keydir:1;
3254         } found = { 0, 0 };
3255
3256         /* Set default value */
3257         option_dtmfminduration = AST_MIN_DTMF_DURATION;
3258
3259         if (ast_opt_override_config) {
3260                 cfg = ast_config_load2(ast_config_AST_CONFIG_FILE, "" /* core, can't reload */, config_flags);
3261                 if (cfg == CONFIG_STATUS_FILEMISSING || cfg == CONFIG_STATUS_FILEUNCHANGED || cfg == CONFIG_STATUS_FILEINVALID) {
3262                         fprintf(stderr, "Unable to open specified master config file '%s', using built-in defaults\n", ast_config_AST_CONFIG_FILE);
3263                 }
3264         } else {
3265                 cfg = ast_config_load2(config, "" /* core, can't reload */, config_flags);
3266         }
3267
3268         /* init with buildtime config */
3269         ast_copy_string(cfg_paths.config_dir, DEFAULT_CONFIG_DIR, sizeof(cfg_paths.config_dir));
3270         ast_copy_string(cfg_paths.spool_dir, DEFAULT_SPOOL_DIR, sizeof(cfg_paths.spool_dir));
3271         ast_copy_string(cfg_paths.module_dir, DEFAULT_MODULE_DIR, sizeof(cfg_paths.module_dir));
3272         snprintf(cfg_paths.monitor_dir, sizeof(cfg_paths.monitor_dir), "%s/monitor", cfg_paths.spool_dir);
3273         ast_copy_string(cfg_paths.var_dir, DEFAULT_VAR_DIR, sizeof(cfg_paths.var_dir));
3274         ast_copy_string(cfg_paths.data_dir, DEFAULT_DATA_DIR, sizeof(cfg_paths.data_dir));
3275         ast_copy_string(cfg_paths.log_dir, DEFAULT_LOG_DIR, sizeof(cfg_paths.log_dir));
3276         ast_copy_string(cfg_paths.agi_dir, DEFAULT_AGI_DIR, sizeof(cfg_paths.agi_dir));
3277         ast_copy_string(cfg_paths.db_path, DEFAULT_DB, sizeof(cfg_paths.db_path));
3278         ast_copy_string(cfg_paths.sbin_dir, DEFAULT_SBIN_DIR, sizeof(cfg_paths.sbin_dir));
3279         ast_copy_string(cfg_paths.key_dir, DEFAULT_KEY_DIR, sizeof(cfg_paths.key_dir));
3280         ast_copy_string(cfg_paths.pid_path, DEFAULT_PID, sizeof(cfg_paths.pid_path));
3281         ast_copy_string(cfg_paths.socket_path, DEFAULT_SOCKET, sizeof(cfg_paths.socket_path));
3282         ast_copy_string(cfg_paths.run_dir, DEFAULT_RUN_DIR, sizeof(cfg_paths.run_dir));
3283
3284         ast_set_default_eid(&ast_eid_default);
3285
3286         /* no asterisk.conf? no problem, use buildtime config! */
3287         if (cfg == CONFIG_STATUS_FILEMISSING || cfg == CONFIG_STATUS_FILEUNCHANGED || cfg == CONFIG_STATUS_FILEINVALID) {
3288                 return;
3289         }
3290
3291         for (v = ast_variable_browse(cfg, "files"); v; v = v->next) {
3292                 if (!strcasecmp(v->name, "astctlpermissions"))
3293                         ast_copy_string(ast_config_AST_CTL_PERMISSIONS, v->value, sizeof(ast_config_AST_CTL_PERMISSIONS));
3294                 else if (!strcasecmp(v->name, "astctlowner"))
3295                         ast_copy_string(ast_config_AST_CTL_OWNER, v->value, sizeof(ast_config_AST_CTL_OWNER));
3296                 else if (!strcasecmp(v->name, "astctlgroup"))
3297                         ast_copy_string(ast_config_AST_CTL_GROUP, v->value, sizeof(ast_config_AST_CTL_GROUP));
3298                 else if (!strcasecmp(v->name, "astctl"))
3299                         ast_copy_string(ast_config_AST_CTL, v->value, sizeof(ast_config_AST_CTL));
3300         }
3301
3302         for (v = ast_variable_browse(cfg, "directories"); v; v = v->next) {
3303                 if (!strcasecmp(v->name, "astetcdir")) {
3304                         ast_copy_string(cfg_paths.config_dir, v->value, sizeof(cfg_paths.config_dir));
3305                 } else if (!strcasecmp(v->name, "astspooldir")) {
3306                         ast_copy_string(cfg_paths.spool_dir, v->value, sizeof(cfg_paths.spool_dir));
3307                         snprintf(cfg_paths.monitor_dir, sizeof(cfg_paths.monitor_dir), "%s/monitor", v->value);
3308                 } else if (!strcasecmp(v->name, "astvarlibdir")) {
3309                         ast_copy_string(cfg_paths.var_dir, v->value, sizeof(cfg_paths.var_dir));
3310                         if (!found.dbdir)
3311                                 snprintf(cfg_paths.db_path, sizeof(cfg_paths.db_path), "%s/astdb", v->value);
3312                 } else if (!strcasecmp(v->name, "astdbdir")) {
3313                         snprintf(cfg_paths.db_path, sizeof(cfg_paths.db_path), "%s/astdb", v->value);
3314                         found.dbdir = 1;
3315                 } else if (!strcasecmp(v->name, "astdatadir")) {
3316                         ast_copy_string(cfg_paths.data_dir, v->value, sizeof(cfg_paths.data_dir));
3317                         if (!found.keydir)
3318                                 snprintf(cfg_paths.key_dir, sizeof(cfg_paths.key_dir), "%s/keys", v->value);
3319                 } else if (!strcasecmp(v->name, "astkeydir")) {
3320                         snprintf(cfg_paths.key_dir, sizeof(cfg_paths.key_dir), "%s/keys", v->value);
3321                         found.keydir = 1;
3322                 } else if (!strcasecmp(v->name, "astlogdir")) {
3323                         ast_copy_string(cfg_paths.log_dir, v->value, sizeof(cfg_paths.log_dir));
3324                 } else if (!strcasecmp(v->name, "astagidir")) {
3325                         ast_copy_string(cfg_paths.agi_dir, v->value, sizeof(cfg_paths.agi_dir));
3326                 } else if (!strcasecmp(v->name, "astrundir")) {
3327                         snprintf(cfg_paths.pid_path, sizeof(cfg_paths.pid_path), "%s/%s", v->value, "asterisk.pid");
3328                         snprintf(cfg_paths.socket_path, sizeof(cfg_paths.socket_path), "%s/%s", v->value, ast_config_AST_CTL);
3329                         ast_copy_string(cfg_paths.run_dir, v->value, sizeof(cfg_paths.run_dir));
3330                 } else if (!strcasecmp(v->name, "astmoddir")) {
3331                         ast_copy_string(cfg_paths.module_dir, v->value, sizeof(cfg_paths.module_dir));
3332                 } else if (!strcasecmp(v->name, "astsbindir")) {
3333                         ast_copy_string(cfg_paths.sbin_dir, v->value, sizeof(cfg_paths.sbin_dir));
3334                 }
3335         }
3336
3337         for (v = ast_variable_browse(cfg, "options"); v; v = v->next) {
3338                 /* verbose level (-v at startup) */
3339                 if (!strcasecmp(v->name, "verbose")) {
3340                         option_verbose = atoi(v->value);
3341                 /* whether or not to force timestamping in CLI verbose output. (-T at startup) */
3342                 } else if (!strcasecmp(v->name, "timestamp")) {
3343                         ast_set2_flag(&ast_options, ast_true(v->value), AST_OPT_FLAG_TIMESTAMP);
3344                 /* whether or not to support #exec in config files */
3345                 } else if (!strcasecmp(v->name, "execincludes")) {
3346                         ast_set2_flag(&ast_options, ast_true(v->value), AST_OPT_FLAG_EXEC_INCLUDES);
3347                 /* debug level (-d at startup) */
3348                 } else if (!strcasecmp(v->name, "debug")) {
3349                         option_debug = 0;
3350                         if (sscanf(v->value, "%30d", &option_debug) != 1) {
3351                                 option_debug = ast_true(v->value);
3352                         }
3353 #if HAVE_WORKING_FORK
3354                 /* Disable forking (-f at startup) */
3355                 } else if (!strcasecmp(v->name, "nofork")) {
3356                         ast_set2_flag(&ast_options, ast_true(v->value), AST_OPT_FLAG_NO_FORK);
3357                 /* Always fork, even if verbose or debug are enabled (-F at startup) */
3358                 } else if (!strcasecmp(v->name, "alwaysfork")) {
3359                         ast_set2_flag(&ast_options, ast_true(v->value), AST_OPT_FLAG_ALWAYS_FORK);
3360 #endif
3361                 /* Run quietly (-q at startup ) */
3362                 } else if (!strcasecmp(v->name, "quiet")) {
3363                         ast_set2_flag(&ast_options, ast_true(v->value), AST_OPT_FLAG_QUIET);
3364                 /* Run as console (-c at startup, implies nofork) */
3365                 } else if (!strcasecmp(v->name, "console")) {
3366                         ast_set2_flag(&ast_options, ast_true(v->value), AST_OPT_FLAG_NO_FORK | AST_OPT_FLAG_CONSOLE);
3367                 /* Run with high priority if the O/S permits (-p at startup) */
3368                 } else if (!strcasecmp(v->name, "highpriority")) {
3369                         ast_set2_flag(&ast_options, ast_true(v->value), AST_OPT_FLAG_HIGH_PRIORITY);
3370                 /* Initialize RSA auth keys (IAX2) (-i at startup) */
3371                 } else if (!strcasecmp(v->name, "initcrypto")) {
3372                         ast_set2_flag(&ast_options, ast_true(v->value), AST_OPT_FLAG_INIT_KEYS);
3373                 /* Disable ANSI colors for console (-c at startup) */
3374                 } else if (!strcasecmp(v->name, "nocolor")) {
3375                         ast_set2_flag(&ast_options, ast_true(v->value), AST_OPT_FLAG_NO_COLOR);
3376                 /* Disable some usage warnings for picky people :p */
3377                 } else if (!strcasecmp(v->name, "dontwarn")) {
3378                         ast_set2_flag(&ast_options, ast_true(v->value), AST_OPT_FLAG_DONT_WARN);
3379                 /* Dump core in case of crash (-g) */
3380                 } else if (!strcasecmp(v->name, "dumpcore")) {
3381                         ast_set2_flag(&ast_options, ast_true(v->value), AST_OPT_FLAG_DUMP_CORE);
3382                 /* Cache recorded sound files to another directory during recording */
3383                 } else if (!strcasecmp(v->name, "cache_record_files")) {
3384                         ast_set2_flag(&ast_options, ast_true(v->value), AST_OPT_FLAG_CACHE_RECORD_FILES);
3385                 /* Specify cache directory */
3386                 }  else if (!strcasecmp(v->name, "record_cache_dir")) {
3387                         ast_copy_string(record_cache_dir, v->value, AST_CACHE_DIR_LEN);
3388                 /* Build transcode paths via SLINEAR, instead of directly */
3389                 } else if (!strcasecmp(v->name, "transcode_via_sln")) {
3390                         ast_set2_flag(&ast_options, ast_true(v->value), AST_OPT_FLAG_TRANSCODE_VIA_SLIN);
3391                 /* Transmit SLINEAR silence while a channel is being recorded or DTMF is being generated on a channel */
3392                 } else if (!strcasecmp(v->name, "transmit_silence_during_record") || !strcasecmp(v->name, "transmit_silence")) {
3393                         ast_set2_flag(&ast_options, ast_true(v->value), AST_OPT_FLAG_TRANSMIT_SILENCE);
3394                 /* Enable internal timing */
3395                 } else if (!strcasecmp(v->name, "internal_timing")) {
3396                         ast_set2_flag(&ast_options, ast_true(v->value), AST_OPT_FLAG_INTERNAL_TIMING);
3397                 } else if (!strcasecmp(v->name, "mindtmfduration")) {
3398                         if (sscanf(v->value, "%30u", &option_dtmfminduration) != 1) {
3399                                 option_dtmfminduration = AST_MIN_DTMF_DURATION;
3400                         }
3401                 } else if (!strcasecmp(v->name, "maxcalls")) {
3402                         if ((sscanf(v->value, "%30d", &option_maxcalls) != 1) || (option_maxcalls < 0)) {
3403                                 option_maxcalls = 0;
3404                         }
3405                 } else if (!strcasecmp(v->name, "maxload")) {
3406                         double test[1];
3407
3408                         if (getloadavg(test, 1) == -1) {
3409                                 ast_log(LOG_ERROR, "Cannot obtain load average on this system. 'maxload' option disabled.\n");
3410                                 option_maxload = 0.0;
3411                         } else if ((sscanf(v->value, "%30lf", &option_maxload) != 1) || (option_maxload < 0.0)) {
3412                                 option_maxload = 0.0;
3413                         }
3414                 /* Set the maximum amount of open files */
3415                 } else if (!strcasecmp(v->name, "maxfiles")) {
3416                         option_maxfiles = atoi(v->value);
3417                         set_ulimit(option_maxfiles);
3418                 /* What user to run as */
3419                 } else if (!strcasecmp(v->name, "runuser")) {
3420                         ast_copy_string(cfg_paths.run_user, v->value, sizeof(cfg_paths.run_user));
3421                 /* What group to run as */
3422                 } else if (!strcasecmp(v->name, "rungroup")) {
3423                         ast_copy_string(cfg_paths.run_group, v->value, sizeof(cfg_paths.run_group));
3424                 } else if (!strcasecmp(v->name, "systemname")) {
3425                         ast_copy_string(cfg_paths.system_name, v->value, sizeof(cfg_paths.system_name));
3426                 } else if (!strcasecmp(v->name, "autosystemname")) {
3427                         if (ast_true(v->value)) {
3428                                 if (!gethostname(hostname, sizeof(hostname) - 1))
3429                                         ast_copy_string(cfg_paths.system_name, hostname, sizeof(cfg_paths.system_name));
3430                                 else {
3431                                         if (ast_strlen_zero(ast_config_AST_SYSTEM_NAME)){
3432                                                 ast_copy_string(cfg_paths.system_name, "localhost", sizeof(cfg_paths.system_name));
3433                                         }
3434                                         ast_log(LOG_ERROR, "Cannot obtain hostname for this system.  Using '%s' instead.\n", ast_config_AST_SYSTEM_NAME);
3435                                 }
3436                         }
3437                 } else if (!strcasecmp(v->name, "languageprefix")) {
3438                         ast_language_is_prefix = ast_true(v->value);
3439                 } else if (!strcasecmp(v->name, "defaultlanguage")) {
3440                         ast_copy_string(defaultlanguage, v->value, MAX_LANGUAGE);
3441                 } else if (!strcasecmp(v->name, "lockmode")) {
3442                         if (!strcasecmp(v->value, "lockfile")) {
3443                                 ast_set_lock_type(AST_LOCK_TYPE_LOCKFILE);
3444                         } else if (!strcasecmp(v->value, "flock")) {
3445                                 ast_set_lock_type(AST_LOCK_TYPE_FLOCK);
3446                         } else {
3447                                 ast_log(LOG_WARNING, "'%s' is not a valid setting for the lockmode option, "
3448                                         "defaulting to 'lockfile'\n", v->value);
3449                                 ast_set_lock_type(AST_LOCK_TYPE_LOCKFILE);
3450                         }
3451 #if defined(HAVE_SYSINFO)
3452                 } else if (!strcasecmp(v->name, "minmemfree")) {
3453                         /* specify the minimum amount of free memory to retain.  Asterisk should stop accepting new calls
3454                          * if the amount of free memory falls below this watermark */
3455                         if ((sscanf(v->value, "%30ld", &option_minmemfree) != 1) || (option_minmemfree < 0)) {
3456                                 option_minmemfree = 0;
3457                         }
3458 #endif
3459                 } else if (!strcasecmp(v->name, "entityid")) {
3460                         struct ast_eid tmp_eid;
3461                         if (!ast_str_to_eid(&tmp_eid, v->value)) {
3462                                 ast_verbose("Successfully set global EID to '%s'\n", v->value);
3463                                 ast_eid_default = tmp_eid;
3464                         } else
3465                                 ast_verbose("Invalid Entity ID '%s' provided\n", v->value);
3466                 } else if (!strcasecmp(v->name, "lightbackground")) {
3467                         ast_set2_flag(&ast_options, ast_true(v->value), AST_OPT_FLAG_LIGHT_BACKGROUND);
3468                 } else if (!strcasecmp(v->name, "forceblackbackground")) {
3469                         ast_set2_flag(&ast_options, ast_true(v->value), AST_OPT_FLAG_FORCE_BLACK_BACKGROUND);
3470                 } else if (!strcasecmp(v->name, "hideconnect")) {
3471                         ast_set2_flag(&ast_options, ast_true(v->value), AST_OPT_FLAG_HIDE_CONSOLE_CONNECT);
3472                 } else if (!strcasecmp(v->name, "lockconfdir")) {
3473                         ast_set2_flag(&ast_options, ast_true(v->value), AST_OPT_FLAG_LOCK_CONFIG_DIR);
3474                 } else if (!strcasecmp(v->name, "stdexten")) {
3475                         /* Choose how to invoke the extensions.conf stdexten */
3476                         if (!strcasecmp(v->value, "gosub")) {
3477                                 ast_clear_flag(&ast_options, AST_OPT_FLAG_STDEXTEN_MACRO);
3478                         } else if (!strcasecmp(v->value, "macro")) {
3479                                 ast_set_flag(&ast_options, AST_OPT_FLAG_STDEXTEN_MACRO);
3480                         } else {
3481                                 ast_log(LOG_WARNING,
3482                                         "'%s' is not a valid setting for the stdexten option, defaulting to 'gosub'\n",
3483                                         v->value);
3484                                 ast_clear_flag(&ast_options, AST_OPT_FLAG_STDEXTEN_MACRO);
3485                         }
3486                 }
3487         }
3488         for (v = ast_variable_browse(cfg, "compat"); v; v = v->next) {
3489                 float version;
3490                 if (sscanf(v->value, "%30f", &version) != 1) {
3491                         fprintf(stderr, "Compatibility version for option '%s' is not a number: '%s'\n", v->name, v->value);
3492                         continue;
3493                 }
3494                 if (!strcasecmp(v->name, "app_set")) {
3495                         ast_set2_flag(&ast_compat, version < 1.5 ? 1 : 0, AST_COMPAT_APP_SET);
3496                 } else if (!strcasecmp(v->name, "res_agi")) {
3497                         ast_set2_flag(&ast_compat, version < 1.5 ? 1 : 0, AST_COMPAT_DELIM_RES_AGI);
3498                 } else if (!strcasecmp(v->name, "pbx_realtime")) {
3499                         ast_set2_flag(&ast_compat, version < 1.5 ? 1 : 0, AST_COMPAT_DELIM_PBX_REALTIME);
3500                 }
3501         }
3502         ast_config_destroy(cfg);
3503 }
3504
3505 static void *monitor_sig_flags(void *unused)
3506 {
3507         for (;;) {
3508                 struct pollfd p = { sig_alert_pipe[0], POLLIN, 0 };
3509                 int a;
3510                 ast_poll(&p, 1, -1);
3511                 if (sig_flags.need_reload) {
3512                         sig_flags.need_reload = 0;
3513                         ast_module_reload(NULL);
3514                 }
3515                 if (sig_flags.need_quit) {
3516                         sig_flags.need_quit = 0;
3517                         if ((consolethread != AST_PTHREADT_NULL) && (consolethread != pthread_self())) {
3518                                 sig_flags.need_quit_handler = 1;
3519                                 pthread_kill(consolethread, SIGURG);
3520                         } else {
3521                                 quit_handler(0, SHUTDOWN_NORMAL, 0);
3522                         }
3523                 }
3524                 if (read(sig_alert_pipe[0], &a, sizeof(a)) != sizeof(a)) {
3525                 }
3526         }
3527
3528         return NULL;
3529 }
3530
3531 static void *canary_thread(void *unused)
3532 {
3533         struct stat canary_stat;
3534         struct timeval now;
3535
3536         /* Give the canary time to sing */
3537         sleep(120);
3538
3539         for (;;) {
3540                 now = ast_tvnow();
3541                 if (stat(canary_filename, &canary_stat) || now.tv_sec > canary_stat.st_mtime + 60) {
3542                         ast_log(LOG_WARNING,
3543                                 "The canary is no more.  He has ceased to be!  "
3544                                 "He's expired and gone to meet his maker!  "
3545                                 "He's a stiff!  Bereft of life, he rests in peace.  "
3546                                 "His metabolic processes are now history!  He's off the twig!  "
3547                                 "He's kicked the bucket.  He's shuffled off his mortal coil, "
3548                                 "run down the curtain, and joined the bleeding choir invisible!!  "
3549                                 "THIS is an EX-CANARY.  (Reducing priority)\n");
3550                         ast_set_priority(0);
3551                         pthread_exit(NULL);
3552                 }
3553
3554                 /* Check the canary once a minute */
3555                 sleep(60);
3556         }
3557 }
3558
3559 /* Used by libc's atexit(3) function */
3560 static void canary_exit(void)
3561 {
3562         if (canary_pid > 0)
3563                 kill(canary_pid, SIGKILL);
3564 }
3565
3566 static void run_startup_commands(void)
3567 {
3568         int fd;
3569         struct ast_config *cfg;
3570         struct ast_flags cfg_flags = { 0 };
3571         struct ast_variable *v;
3572
3573         if (!(cfg = ast_config_load2("cli.conf", "" /* core, can't reload */, cfg_flags)))
3574                 return;
3575         if (cfg == CONFIG_STATUS_FILEMISSING || cfg == CONFIG_STATUS_FILEUNCHANGED || cfg == CONFIG_STATUS_FILEINVALID) {
3576                 return;
3577         }
3578
3579         fd = open("/dev/null", O_RDWR);
3580         if (fd < 0) {
3581                 ast_config_destroy(cfg);
3582                 return;
3583         }
3584
3585         for (v = ast_variable_browse(cfg, "startup_commands"); v; v = v->next) {
3586                 if (ast_true(v->value))
3587                         ast_cli_command(fd, v->name);
3588         }
3589
3590         close(fd);
3591         ast_config_destroy(cfg);
3592 }
3593
3594 static void env_init(void)