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