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