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