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