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