Fix a variety of ref counting issues
[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         ast_verb(0, "Executing last minute cleanups\n");
1873         ast_run_atexits();
1874         /* Called on exit */
1875         ast_verb(0, "Asterisk %s ending (%d).\n", ast_active_channels() ? "uncleanly" : "cleanly", num);
1876         ast_debug(1, "Asterisk ending (%d).\n", num);
1877         /*** DOCUMENTATION
1878                 <managerEventInstance>
1879                         <synopsis>Raised when Asterisk is shutdown or restarted.</synopsis>
1880                         <syntax>
1881                                 <parameter name="Shutdown">
1882                                         <enumlist>
1883                                                 <enum name="Uncleanly"/>
1884                                                 <enum name="Cleanly"/>
1885                                         </enumlist>
1886                                 </parameter>
1887                                 <parameter name="Restart">
1888                                         <enumlist>
1889                                                 <enum name="True"/>
1890                                                 <enum name="False"/>
1891                                         </enumlist>
1892                                 </parameter>
1893                         </syntax>
1894                 </managerEventInstance>
1895         ***/
1896         manager_event(EVENT_FLAG_SYSTEM, "Shutdown", "Shutdown: %s\r\nRestart: %s\r\n", ast_active_channels() ? "Uncleanly" : "Cleanly", restart ? "True" : "False");
1897         if (ast_socket > -1) {
1898                 pthread_cancel(lthread);
1899                 close(ast_socket);
1900                 ast_socket = -1;
1901                 unlink(ast_config_AST_SOCKET);
1902         }
1903         if (ast_consock > -1)
1904                 close(ast_consock);
1905         if (!ast_opt_remote)
1906                 unlink(ast_config_AST_PID);
1907         printf("%s", term_quit());
1908         if (restart) {
1909                 int i;
1910                 ast_verb(0, "Preparing for Asterisk restart...\n");
1911                 /* Mark all FD's for closing on exec */
1912                 for (i = 3; i < 32768; i++) {
1913                         fcntl(i, F_SETFD, FD_CLOEXEC);
1914                 }
1915                 ast_verb(0, "Asterisk is now restarting...\n");
1916                 restartnow = 1;
1917
1918                 /* close logger */
1919                 close_logger();
1920
1921                 /* If there is a consolethread running send it a SIGHUP
1922                    so it can execvp, otherwise we can do it ourselves */
1923                 if ((consolethread != AST_PTHREADT_NULL) && (consolethread != pthread_self())) {
1924                         pthread_kill(consolethread, SIGHUP);
1925                         /* Give the signal handler some time to complete */
1926                         sleep(2);
1927                 } else
1928                         execvp(_argv[0], _argv);
1929
1930         } else {
1931                 /* close logger */
1932                 close_logger();
1933         }
1934
1935         exit(0);
1936 }
1937
1938 static void __quit_handler(int num)
1939 {
1940         int a = 0;
1941         sig_flags.need_quit = 1;
1942         if (sig_alert_pipe[1] != -1) {
1943                 if (write(sig_alert_pipe[1], &a, sizeof(a)) < 0) {
1944                         fprintf(stderr, "quit_handler: write() failed: %s\n", strerror(errno));
1945                 }
1946         }
1947         /* There is no need to restore the signal handler here, since the app
1948          * is going to exit */
1949 }
1950
1951 static void __remote_quit_handler(int num)
1952 {
1953         sig_flags.need_quit = 1;
1954 }
1955
1956 static const char *fix_header(char *outbuf, int maxout, const char *s, char *cmp)
1957 {
1958         const char *c;
1959
1960         if (!strncmp(s, cmp, strlen(cmp))) {
1961                 c = s + strlen(cmp);
1962                 term_color(outbuf, cmp, COLOR_GRAY, 0, maxout);
1963                 return c;
1964         }
1965         return NULL;
1966 }
1967
1968 /* These gymnastics are due to platforms which designate char as unsigned by
1969  * default. Level is the negative character -- offset by 1, because \0 is the
1970  * EOS delimiter. */
1971 #define VERBOSE_MAGIC2LEVEL(x) (((char) -*(signed char *) (x)) - 1)
1972 #define VERBOSE_HASMAGIC(x)     (*(signed char *) (x) < 0)
1973
1974 static void console_verboser(const char *s)
1975 {
1976         char tmp[80];
1977         const char *c = NULL;
1978         char level = 0;
1979
1980         if (VERBOSE_HASMAGIC(s)) {
1981                 level = VERBOSE_MAGIC2LEVEL(s);
1982                 s++;
1983                 if (level > option_verbose) {
1984                         return;
1985                 }
1986         }
1987
1988         if ((c = fix_header(tmp, sizeof(tmp), s, VERBOSE_PREFIX_4)) ||
1989             (c = fix_header(tmp, sizeof(tmp), s, VERBOSE_PREFIX_3)) ||
1990             (c = fix_header(tmp, sizeof(tmp), s, VERBOSE_PREFIX_2)) ||
1991             (c = fix_header(tmp, sizeof(tmp), s, VERBOSE_PREFIX_1))) {
1992                 fputs(tmp, stdout);
1993                 fputs(c, stdout);
1994         } else {
1995                 fputs(s, stdout);
1996         }
1997
1998         fflush(stdout);
1999
2000         /* Wake up a poll()ing console */
2001         if (ast_opt_console && consolethread != AST_PTHREADT_NULL) {
2002                 pthread_kill(consolethread, SIGURG);
2003         }
2004 }
2005
2006 static int ast_all_zeros(char *s)
2007 {
2008         while (*s) {
2009                 if (*s > 32)
2010                         return 0;
2011                 s++;
2012         }
2013         return 1;
2014 }
2015
2016 static void consolehandler(char *s)
2017 {
2018         printf("%s", term_end());
2019         fflush(stdout);
2020
2021         /* Called when readline data is available */
2022         if (!ast_all_zeros(s))
2023                 ast_el_add_history(s);
2024         /* The real handler for bang */
2025         if (s[0] == '!') {
2026                 if (s[1])
2027                         ast_safe_system(s+1);
2028                 else
2029                         ast_safe_system(getenv("SHELL") ? getenv("SHELL") : "/bin/sh");
2030         } else
2031                 ast_cli_command(STDOUT_FILENO, s);
2032 }
2033
2034 static int remoteconsolehandler(char *s)
2035 {
2036         int ret = 0;
2037
2038         /* Called when readline data is available */
2039         if (!ast_all_zeros(s))
2040                 ast_el_add_history(s);
2041         /* The real handler for bang */
2042         if (s[0] == '!') {
2043                 if (s[1])
2044                         ast_safe_system(s+1);
2045                 else
2046                         ast_safe_system(getenv("SHELL") ? getenv("SHELL") : "/bin/sh");
2047                 ret = 1;
2048         } else if (strncasecmp(s, "core set verbose ", 17) == 0) {
2049                 int old_verbose = option_verbose;
2050                 if (strncasecmp(s + 17, "atleast ", 8) == 0) {
2051                         int tmp;
2052                         if (sscanf(s + 25, "%d", &tmp) != 1) {
2053                                 fprintf(stderr, "Usage: core set verbose [atleast] <level>\n");
2054                         } else {
2055                                 if (tmp > option_verbose) {
2056                                         option_verbose = tmp;
2057                                 }
2058                                 if (old_verbose != option_verbose) {
2059                                         fprintf(stdout, "Set remote console verbosity from %d to %d\n", old_verbose, option_verbose);
2060                                 } else {
2061                                         fprintf(stdout, "Verbosity level unchanged.\n");
2062                                 }
2063                         }
2064                 } else {
2065                         if (sscanf(s + 17, "%d", &option_verbose) != 1) {
2066                                 fprintf(stderr, "Usage: core set verbose [atleast] <level>\n");
2067                         } else {
2068                                 if (old_verbose != option_verbose) {
2069                                         fprintf(stdout, "Set remote console verbosity to %d\n", option_verbose);
2070                                 } else {
2071                                         fprintf(stdout, "Verbosity level unchanged.\n");
2072                                 }
2073                         }
2074                 }
2075                 ret = 1;
2076         } else if ((strncasecmp(s, "quit", 4) == 0 || strncasecmp(s, "exit", 4) == 0) &&
2077             (s[4] == '\0' || isspace(s[4]))) {
2078                 quit_handler(0, SHUTDOWN_FAST, 0);
2079                 ret = 1;
2080         }
2081
2082         return ret;
2083 }
2084
2085 static char *handle_version(struct ast_cli_entry *e, int cmd, struct ast_cli_args *a)
2086 {
2087         switch (cmd) {
2088         case CLI_INIT:
2089                 e->command = "core show version";
2090                 e->usage =
2091                         "Usage: core show version\n"
2092                         "       Shows Asterisk version information.\n";
2093                 return NULL;
2094         case CLI_GENERATE:
2095                 return NULL;
2096         }
2097
2098         if (a->argc != 3)
2099                 return CLI_SHOWUSAGE;
2100         ast_cli(a->fd, "Asterisk %s built by %s @ %s on a %s running %s on %s\n",
2101                 ast_get_version(), ast_build_user, ast_build_hostname,
2102                 ast_build_machine, ast_build_os, ast_build_date);
2103         return CLI_SUCCESS;
2104 }
2105
2106 #if 0
2107 static int handle_quit(int fd, int argc, char *argv[])
2108 {
2109         if (argc != 1)
2110                 return RESULT_SHOWUSAGE;
2111         quit_handler(0, SHUTDOWN_NORMAL, 0);
2112         return RESULT_SUCCESS;
2113 }
2114 #endif
2115
2116 static char *handle_stop_now(struct ast_cli_entry *e, int cmd, struct ast_cli_args *a)
2117 {
2118         switch (cmd) {
2119         case CLI_INIT:
2120                 e->command = "core stop now";
2121                 e->usage =
2122                         "Usage: core stop now\n"
2123                         "       Shuts down a running Asterisk immediately, hanging up all active calls .\n";
2124                 return NULL;
2125         case CLI_GENERATE:
2126                 return NULL;
2127         }
2128
2129         if (a->argc != e->args)
2130                 return CLI_SHOWUSAGE;
2131         quit_handler(0, SHUTDOWN_NORMAL, 0 /* not restart */);
2132         return CLI_SUCCESS;
2133 }
2134
2135 static char *handle_stop_gracefully(struct ast_cli_entry *e, int cmd, struct ast_cli_args *a)
2136 {
2137         switch (cmd) {
2138         case CLI_INIT:
2139                 e->command = "core stop gracefully";
2140                 e->usage =
2141                         "Usage: core stop gracefully\n"
2142                         "       Causes Asterisk to not accept new calls, and exit when all\n"
2143                         "       active calls have terminated normally.\n";
2144                 return NULL;
2145         case CLI_GENERATE:
2146                 return NULL;
2147         }
2148
2149         if (a->argc != e->args)
2150                 return CLI_SHOWUSAGE;
2151         quit_handler(0, SHUTDOWN_NICE, 0 /* no restart */);
2152         return CLI_SUCCESS;
2153 }
2154
2155 static char *handle_stop_when_convenient(struct ast_cli_entry *e, int cmd, struct ast_cli_args *a)
2156 {
2157         switch (cmd) {
2158         case CLI_INIT:
2159                 e->command = "core stop when convenient";
2160                 e->usage =
2161                         "Usage: core stop when convenient\n"
2162                         "       Causes Asterisk to perform a shutdown when all active calls have ended.\n";
2163                 return NULL;
2164         case CLI_GENERATE:
2165                 return NULL;
2166         }
2167
2168         if (a->argc != e->args)
2169                 return CLI_SHOWUSAGE;
2170         ast_cli(a->fd, "Waiting for inactivity to perform halt\n");
2171         quit_handler(0, SHUTDOWN_REALLY_NICE, 0 /* don't restart */);
2172         return CLI_SUCCESS;
2173 }
2174
2175 static char *handle_restart_now(struct ast_cli_entry *e, int cmd, struct ast_cli_args *a)
2176 {
2177         switch (cmd) {
2178         case CLI_INIT:
2179                 e->command = "core restart now";
2180                 e->usage =
2181                         "Usage: core restart now\n"
2182                         "       Causes Asterisk to hangup all calls and exec() itself performing a cold\n"
2183                         "       restart.\n";
2184                 return NULL;
2185         case CLI_GENERATE:
2186                 return NULL;
2187         }
2188
2189         if (a->argc != e->args)
2190                 return CLI_SHOWUSAGE;
2191         quit_handler(0, SHUTDOWN_NORMAL, 1 /* restart */);
2192         return CLI_SUCCESS;
2193 }
2194
2195 static char *handle_restart_gracefully(struct ast_cli_entry *e, int cmd, struct ast_cli_args *a)
2196 {
2197         switch (cmd) {
2198         case CLI_INIT:
2199                 e->command = "core restart gracefully";
2200                 e->usage =
2201                         "Usage: core restart gracefully\n"
2202                         "       Causes Asterisk to stop accepting new calls and exec() itself performing a cold\n"
2203                         "       restart when all active calls have ended.\n";
2204                 return NULL;
2205         case CLI_GENERATE:
2206                 return NULL;
2207         }
2208
2209         if (a->argc != e->args)
2210                 return CLI_SHOWUSAGE;
2211         quit_handler(0, SHUTDOWN_NICE, 1 /* restart */);
2212         return CLI_SUCCESS;
2213 }
2214
2215 static char *handle_restart_when_convenient(struct ast_cli_entry *e, int cmd, struct ast_cli_args *a)
2216 {
2217         switch (cmd) {
2218         case CLI_INIT:
2219                 e->command = "core restart when convenient";
2220                 e->usage =
2221                         "Usage: core restart when convenient\n"
2222                         "       Causes Asterisk to perform a cold restart when all active calls have ended.\n";
2223                 return NULL;
2224         case CLI_GENERATE:
2225                 return NULL;
2226         }
2227
2228         if (a->argc != e->args)
2229                 return CLI_SHOWUSAGE;
2230         ast_cli(a->fd, "Waiting for inactivity to perform restart\n");
2231         quit_handler(0, SHUTDOWN_REALLY_NICE, 1 /* restart */);
2232         return CLI_SUCCESS;
2233 }
2234
2235 static char *handle_abort_shutdown(struct ast_cli_entry *e, int cmd, struct ast_cli_args *a)
2236 {
2237         int aborting_shutdown = 0;
2238
2239         switch (cmd) {
2240         case CLI_INIT:
2241                 e->command = "core abort shutdown";
2242                 e->usage =
2243                         "Usage: core abort shutdown\n"
2244                         "       Causes Asterisk to abort an executing shutdown or restart, and resume normal\n"
2245                         "       call operations.\n";
2246                 return NULL;
2247         case CLI_GENERATE:
2248                 return NULL;
2249         }
2250
2251         if (a->argc != e->args)
2252                 return CLI_SHOWUSAGE;
2253
2254         ast_mutex_lock(&safe_system_lock);
2255         if (shuttingdown >= SHUTDOWN_FAST) {
2256                 aborting_shutdown = 1;
2257                 shuttingdown = NOT_SHUTTING_DOWN;
2258         }
2259         ast_mutex_unlock(&safe_system_lock);
2260
2261         if (aborting_shutdown) {
2262                 ast_cancel_shutdown();
2263         }
2264         return CLI_SUCCESS;
2265 }
2266
2267 static char *handle_bang(struct ast_cli_entry *e, int cmd, struct ast_cli_args *a)
2268 {
2269         switch (cmd) {
2270         case CLI_INIT:
2271                 e->command = "!";
2272                 e->usage =
2273                         "Usage: !<command>\n"
2274                         "       Executes a given shell command\n";
2275                 return NULL;
2276         case CLI_GENERATE:
2277                 return NULL;
2278         }
2279
2280         return CLI_SUCCESS;
2281 }
2282 static const char warranty_lines[] = {
2283         "\n"
2284         "                           NO WARRANTY\n"
2285         "\n"
2286         "BECAUSE THE PROGRAM IS LICENSED FREE OF CHARGE, THERE IS NO WARRANTY\n"
2287         "FOR THE PROGRAM, TO THE EXTENT PERMITTED BY APPLICABLE LAW.  EXCEPT WHEN\n"
2288         "OTHERWISE STATED IN WRITING THE COPYRIGHT HOLDERS AND/OR OTHER PARTIES\n"
2289         "PROVIDE THE PROGRAM \"AS IS\" WITHOUT WARRANTY OF ANY KIND, EITHER EXPRESSED\n"
2290         "OR IMPLIED, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF\n"
2291         "MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE.  THE ENTIRE RISK AS\n"
2292         "TO THE QUALITY AND PERFORMANCE OF THE PROGRAM IS WITH YOU.  SHOULD THE\n"
2293         "PROGRAM PROVE DEFECTIVE, YOU ASSUME THE COST OF ALL NECESSARY SERVICING,\n"
2294         "REPAIR OR CORRECTION.\n"
2295         "\n"
2296         "IN NO EVENT UNLESS REQUIRED BY APPLICABLE LAW OR AGREED TO IN WRITING\n"
2297         "WILL ANY COPYRIGHT HOLDER, OR ANY OTHER PARTY WHO MAY MODIFY AND/OR\n"
2298         "REDISTRIBUTE THE PROGRAM AS PERMITTED ABOVE, BE LIABLE TO YOU FOR DAMAGES,\n"
2299         "INCLUDING ANY GENERAL, SPECIAL, INCIDENTAL OR CONSEQUENTIAL DAMAGES ARISING\n"
2300         "OUT OF THE USE OR INABILITY TO USE THE PROGRAM (INCLUDING BUT NOT LIMITED\n"
2301         "TO LOSS OF DATA OR DATA BEING RENDERED INACCURATE OR LOSSES SUSTAINED BY\n"
2302         "YOU OR THIRD PARTIES OR A FAILURE OF THE PROGRAM TO OPERATE WITH ANY OTHER\n"
2303         "PROGRAMS), EVEN IF SUCH HOLDER OR OTHER PARTY HAS BEEN ADVISED OF THE\n"
2304         "POSSIBILITY OF SUCH DAMAGES.\n"
2305 };
2306
2307 static char *show_warranty(struct ast_cli_entry *e, int cmd, struct ast_cli_args *a)
2308 {
2309         switch (cmd) {
2310         case CLI_INIT:
2311                 e->command = "core show warranty";
2312                 e->usage =
2313                         "Usage: core show warranty\n"
2314                         "       Shows the warranty (if any) for this copy of Asterisk.\n";
2315                 return NULL;
2316         case CLI_GENERATE:
2317                 return NULL;
2318         }
2319
2320         ast_cli(a->fd, "%s", warranty_lines);
2321
2322         return CLI_SUCCESS;
2323 }
2324
2325 static const char license_lines[] = {
2326         "\n"
2327         "This program is free software; you can redistribute it and/or modify\n"
2328         "it under the terms of the GNU General Public License version 2 as\n"
2329         "published by the Free Software Foundation.\n"
2330         "\n"
2331         "This program also contains components licensed under other licenses.\n"
2332         "They include:\n"
2333         "\n"
2334         "This program is distributed in the hope that it will be useful,\n"
2335         "but WITHOUT ANY WARRANTY; without even the implied warranty of\n"
2336         "MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the\n"
2337         "GNU General Public License for more details.\n"
2338         "\n"
2339         "You should have received a copy of the GNU General Public License\n"
2340         "along with this program; if not, write to the Free Software\n"
2341         "Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA\n"
2342 };
2343
2344 static char *show_license(struct ast_cli_entry *e, int cmd, struct ast_cli_args *a)
2345 {
2346         switch (cmd) {
2347         case CLI_INIT:
2348                 e->command = "core show license";
2349                 e->usage =
2350                         "Usage: core show license\n"
2351                         "       Shows the license(s) for this copy of Asterisk.\n";
2352                 return NULL;
2353         case CLI_GENERATE:
2354                 return NULL;
2355         }
2356
2357         ast_cli(a->fd, "%s", license_lines);
2358
2359         return CLI_SUCCESS;
2360 }
2361
2362 #define ASTERISK_PROMPT "*CLI> "
2363
2364 #define ASTERISK_PROMPT2 "%s*CLI> "
2365
2366 static struct ast_cli_entry cli_asterisk[] = {
2367         AST_CLI_DEFINE(handle_abort_shutdown, "Cancel a running shutdown"),
2368         AST_CLI_DEFINE(handle_stop_now, "Shut down Asterisk immediately"),
2369         AST_CLI_DEFINE(handle_stop_gracefully, "Gracefully shut down Asterisk"),
2370         AST_CLI_DEFINE(handle_stop_when_convenient, "Shut down Asterisk at empty call volume"),
2371         AST_CLI_DEFINE(handle_restart_now, "Restart Asterisk immediately"),
2372         AST_CLI_DEFINE(handle_restart_gracefully, "Restart Asterisk gracefully"),
2373         AST_CLI_DEFINE(handle_restart_when_convenient, "Restart Asterisk at empty call volume"),
2374         AST_CLI_DEFINE(show_warranty, "Show the warranty (if any) for this copy of Asterisk"),
2375         AST_CLI_DEFINE(show_license, "Show the license(s) for this copy of Asterisk"),
2376         AST_CLI_DEFINE(handle_version, "Display version info"),
2377         AST_CLI_DEFINE(handle_bang, "Execute a shell command"),
2378 #if !defined(LOW_MEMORY)
2379         AST_CLI_DEFINE(handle_show_version_files, "List versions of files used to build Asterisk"),
2380         AST_CLI_DEFINE(handle_show_threads, "Show running threads"),
2381 #if defined(HAVE_SYSINFO) || defined(HAVE_SYSCTL)
2382         AST_CLI_DEFINE(handle_show_sysinfo, "Show System Information"),
2383 #endif
2384         AST_CLI_DEFINE(handle_show_profile, "Display profiling info"),
2385         AST_CLI_DEFINE(handle_show_settings, "Show some core settings"),
2386         AST_CLI_DEFINE(handle_clear_profile, "Clear profiling info"),
2387 #endif /* ! LOW_MEMORY */
2388 };
2389
2390 struct el_read_char_state_struct {
2391         unsigned int line_full:1;
2392         unsigned int prev_line_full:1;
2393         char prev_line_verbosity;
2394 };
2395
2396 static int el_read_char_state_init(void *ptr)
2397 {
2398         struct el_read_char_state_struct *state = ptr;
2399         state->line_full = 1;
2400         state->prev_line_full = 1;
2401         state->prev_line_verbosity = 0;
2402         return 0;
2403 }
2404
2405 AST_THREADSTORAGE_CUSTOM(el_read_char_state, el_read_char_state_init, ast_free_ptr);
2406
2407 static int ast_el_read_char(EditLine *editline, char *cp)
2408 {
2409         int num_read = 0;
2410         int lastpos = 0;
2411         struct pollfd fds[2];
2412         int res;
2413         int max;
2414 #define EL_BUF_SIZE 512
2415         char buf[EL_BUF_SIZE];
2416         struct el_read_char_state_struct *state = ast_threadstorage_get(&el_read_char_state, sizeof(*state));
2417
2418         for (;;) {
2419                 max = 1;
2420                 fds[0].fd = ast_consock;
2421                 fds[0].events = POLLIN;
2422                 if (!ast_opt_exec) {
2423                         fds[1].fd = STDIN_FILENO;
2424                         fds[1].events = POLLIN;
2425                         max++;
2426                 }
2427                 res = ast_poll(fds, max, -1);
2428                 if (res < 0) {
2429                         if (sig_flags.need_quit || sig_flags.need_quit_handler)
2430                                 break;
2431                         if (errno == EINTR)
2432                                 continue;
2433                         ast_log(LOG_ERROR, "poll failed: %s\n", strerror(errno));
2434                         break;
2435                 }
2436
2437                 if (!ast_opt_exec && fds[1].revents) {
2438                         num_read = read(STDIN_FILENO, cp, 1);
2439                         if (num_read < 1) {
2440                                 break;
2441                         } else {
2442                                 return (num_read);
2443                         }
2444                 }
2445                 if (fds[0].revents) {
2446                         char level = 0;
2447                         char *curline = buf, *nextline;
2448                         res = read(ast_consock, buf, sizeof(buf) - 1);
2449                         /* if the remote side disappears exit */
2450                         if (res < 1) {
2451                                 fprintf(stderr, "\nDisconnected from Asterisk server\n");
2452                                 if (!ast_opt_reconnect) {
2453                                         quit_handler(0, SHUTDOWN_FAST, 0);
2454                                 } else {
2455                                         int tries;
2456                                         int reconnects_per_second = 20;
2457                                         fprintf(stderr, "Attempting to reconnect for 30 seconds\n");
2458                                         for (tries = 0; tries < 30 * reconnects_per_second; tries++) {
2459                                                 if (ast_tryconnect()) {
2460                                                         fprintf(stderr, "Reconnect succeeded after %.3f seconds\n", 1.0 / reconnects_per_second * tries);
2461                                                         printf("%s", term_quit());
2462                                                         WELCOME_MESSAGE;
2463                                                         if (!ast_opt_mute)
2464                                                                 fdsend(ast_consock, "logger mute silent");
2465                                                         else
2466                                                                 printf("log and verbose output currently muted ('logger mute' to unmute)\n");
2467                                                         break;
2468                                                 } else
2469                                                         usleep(1000000 / reconnects_per_second);
2470                                         }
2471                                         if (tries >= 30 * reconnects_per_second) {
2472                                                 fprintf(stderr, "Failed to reconnect for 30 seconds.  Quitting.\n");
2473                                                 quit_handler(0, SHUTDOWN_FAST, 0);
2474                                         }
2475                                 }
2476                                 continue;
2477                         }
2478
2479                         buf[res] = '\0';
2480
2481                         /* Write over the CLI prompt */
2482                         if (!ast_opt_exec && !lastpos) {
2483                                 if (write(STDOUT_FILENO, "\r\e[0K", 5) < 0) {
2484                                 }
2485                         }
2486
2487                         do {
2488                                 state->prev_line_full = state->line_full;
2489                                 if ((nextline = strchr(curline, '\n'))) {
2490                                         state->line_full = 1;
2491                                         nextline++;
2492                                 } else {
2493                                         state->line_full = 0;
2494                                         nextline = strchr(curline, '\0');
2495                                 }
2496
2497                                 if (state->prev_line_full && VERBOSE_HASMAGIC(curline)) {
2498                                         level = VERBOSE_MAGIC2LEVEL(curline);
2499                                         curline++;
2500                                 } else if (state->prev_line_full && !VERBOSE_HASMAGIC(curline)) {
2501                                         /* Non-verbose output */
2502                                         level = 0;
2503                                 } else {
2504                                         level = state->prev_line_verbosity;
2505                                 }
2506                                 if ((!state->prev_line_full && state->prev_line_verbosity <= option_verbose) || (state->prev_line_full && level <= option_verbose)) {
2507                                         if (write(STDOUT_FILENO, curline, nextline - curline) < 0) {
2508                                         }
2509                                 }
2510
2511                                 state->prev_line_verbosity = level;
2512                                 curline = nextline;
2513                         } while (!ast_strlen_zero(curline));
2514
2515                         if ((res < EL_BUF_SIZE - 1) && ((buf[res-1] == '\n') || (buf[res-2] == '\n'))) {
2516                                 *cp = CC_REFRESH;
2517                                 return(1);
2518                         } else
2519                                 lastpos = 1;
2520                 }
2521         }
2522
2523         *cp = '\0';
2524         return (0);
2525 }
2526
2527 static struct ast_str *prompt = NULL;
2528
2529 static char *cli_prompt(EditLine *editline)
2530 {
2531         char tmp[100];
2532         char *pfmt;
2533         int color_used = 0;
2534         static int cli_prompt_changes = 0;
2535         char term_code[20];
2536         struct passwd *pw;
2537         struct group *gr;
2538
2539         if (prompt == NULL) {
2540                 prompt = ast_str_create(100);
2541         } else if (!cli_prompt_changes) {
2542                 return ast_str_buffer(prompt);
2543         } else {
2544                 ast_str_reset(prompt);
2545         }
2546
2547         if ((pfmt = getenv("ASTERISK_PROMPT"))) {
2548                 char *t = pfmt;
2549                 struct timeval ts = ast_tvnow();
2550                 while (*t != '\0') {
2551                         if (*t == '%') {
2552                                 char hostname[MAXHOSTNAMELEN] = "";
2553                                 int i, which;
2554                                 struct ast_tm tm = { 0, };
2555                                 int fgcolor = COLOR_WHITE, bgcolor = COLOR_BLACK;
2556
2557                                 t++;
2558                                 switch (*t) {
2559                                 case 'C': /* color */
2560                                         t++;
2561                                         if (sscanf(t, "%30d;%30d%n", &fgcolor, &bgcolor, &i) == 2) {
2562                                                 ast_str_append(&prompt, 0, "%s", term_color_code(term_code, fgcolor, bgcolor, sizeof(term_code)));
2563                                                 t += i - 1;
2564                                         } else if (sscanf(t, "%30d%n", &fgcolor, &i) == 1) {
2565                                                 ast_str_append(&prompt, 0, "%s", term_color_code(term_code, fgcolor, 0, sizeof(term_code)));
2566                                                 t += i - 1;
2567                                         }
2568
2569                                         /* If the color has been reset correctly, then there's no need to reset it later */
2570                                         color_used = ((fgcolor == COLOR_WHITE) && (bgcolor == COLOR_BLACK)) ? 0 : 1;
2571                                         break;
2572                                 case 'd': /* date */
2573                                         if (ast_localtime(&ts, &tm, NULL)) {
2574                                                 ast_strftime(tmp, sizeof(tmp), "%Y-%m-%d", &tm);
2575                                                 ast_str_append(&prompt, 0, "%s", tmp);
2576                                                 cli_prompt_changes++;
2577                                         }
2578                                         break;
2579                                 case 'g': /* group */
2580                                         if ((gr = getgrgid(getgid()))) {
2581                                                 ast_str_append(&prompt, 0, "%s", gr->gr_name);
2582                                         }
2583                                         break;
2584                                 case 'h': /* hostname */
2585                                         if (!gethostname(hostname, sizeof(hostname) - 1)) {
2586                                                 ast_str_append(&prompt, 0, "%s", hostname);
2587                                         } else {
2588                                                 ast_str_append(&prompt, 0, "%s", "localhost");
2589                                         }
2590                                         break;
2591                                 case 'H': /* short hostname */
2592                                         if (!gethostname(hostname, sizeof(hostname) - 1)) {
2593                                                 char *dotptr;
2594                                                 if ((dotptr = strchr(hostname, '.'))) {
2595                                                         *dotptr = '\0';
2596                                                 }
2597                                                 ast_str_append(&prompt, 0, "%s", hostname);
2598                                         } else {
2599                                                 ast_str_append(&prompt, 0, "%s", "localhost");
2600                                         }
2601                                         break;
2602 #ifdef HAVE_GETLOADAVG
2603                                 case 'l': /* load avg */
2604                                         t++;
2605                                         if (sscanf(t, "%30d", &which) == 1 && which > 0 && which <= 3) {
2606                                                 double list[3];
2607                                                 getloadavg(list, 3);
2608                                                 ast_str_append(&prompt, 0, "%.2f", list[which - 1]);
2609                                                 cli_prompt_changes++;
2610                                         }
2611                                         break;
2612 #endif
2613                                 case 's': /* Asterisk system name (from asterisk.conf) */
2614                                         ast_str_append(&prompt, 0, "%s", ast_config_AST_SYSTEM_NAME);
2615                                         break;
2616                                 case 't': /* time */
2617                                         if (ast_localtime(&ts, &tm, NULL)) {
2618                                                 ast_strftime(tmp, sizeof(tmp), "%H:%M:%S", &tm);
2619                                                 ast_str_append(&prompt, 0, "%s", tmp);
2620                                                 cli_prompt_changes++;
2621                                         }
2622                                         break;
2623                                 case 'u': /* username */
2624                                         if ((pw = getpwuid(getuid()))) {
2625                                                 ast_str_append(&prompt, 0, "%s", pw->pw_name);
2626                                         }
2627                                         break;
2628                                 case '#': /* process console or remote? */
2629                                         ast_str_append(&prompt, 0, "%c", ast_opt_remote ? '>' : '#');
2630                                         break;
2631                                 case '%': /* literal % */
2632                                         ast_str_append(&prompt, 0, "%c", '%');
2633                                         break;
2634                                 case '\0': /* % is last character - prevent bug */
2635                                         t--;
2636                                         break;
2637                                 }
2638                         } else {
2639                                 ast_str_append(&prompt, 0, "%c", *t);
2640                         }
2641                         t++;
2642                 }
2643                 if (color_used) {
2644                         /* Force colors back to normal at end */
2645                         ast_str_append(&prompt, 0, "%s", term_color_code(term_code, 0, 0, sizeof(term_code)));
2646                 }
2647         } else if (remotehostname) {
2648                 ast_str_set(&prompt, 0, ASTERISK_PROMPT2, remotehostname);
2649         } else {
2650                 ast_str_set(&prompt, 0, "%s", ASTERISK_PROMPT);
2651         }
2652
2653         return ast_str_buffer(prompt);
2654 }
2655
2656 static char **ast_el_strtoarr(char *buf)
2657 {
2658         char **match_list = NULL, **match_list_tmp, *retstr;
2659         size_t match_list_len;
2660         int matches = 0;
2661
2662         match_list_len = 1;
2663         while ( (retstr = strsep(&buf, " ")) != NULL) {
2664
2665                 if (!strcmp(retstr, AST_CLI_COMPLETE_EOF))
2666                         break;
2667                 if (matches + 1 >= match_list_len) {
2668                         match_list_len <<= 1;
2669                         if ((match_list_tmp = ast_realloc(match_list, match_list_len * sizeof(char *)))) {
2670                                 match_list = match_list_tmp;
2671                         } else {
2672                                 if (match_list)
2673                                         ast_free(match_list);
2674                                 return (char **) NULL;
2675                         }
2676                 }
2677
2678                 match_list[matches++] = ast_strdup(retstr);
2679         }
2680
2681         if (!match_list)
2682                 return (char **) NULL;
2683
2684         if (matches >= match_list_len) {
2685                 if ((match_list_tmp = ast_realloc(match_list, (match_list_len + 1) * sizeof(char *)))) {
2686                         match_list = match_list_tmp;
2687                 } else {
2688                         if (match_list)
2689                                 ast_free(match_list);
2690                         return (char **) NULL;
2691                 }
2692         }
2693
2694         match_list[matches] = (char *) NULL;
2695
2696         return match_list;
2697 }
2698
2699 static int ast_el_sort_compare(const void *i1, const void *i2)
2700 {
2701         char *s1, *s2;
2702
2703         s1 = ((char **)i1)[0];
2704         s2 = ((char **)i2)[0];
2705
2706         return strcasecmp(s1, s2);
2707 }
2708
2709 static int ast_cli_display_match_list(char **matches, int len, int max)
2710 {
2711         int i, idx, limit, count;
2712         int screenwidth = 0;
2713         int numoutput = 0, numoutputline = 0;
2714
2715         screenwidth = ast_get_termcols(STDOUT_FILENO);
2716
2717         /* find out how many entries can be put on one line, with two spaces between strings */
2718         limit = screenwidth / (max + 2);
2719         if (limit == 0)
2720                 limit = 1;
2721
2722         /* how many lines of output */
2723         count = len / limit;
2724         if (count * limit < len)
2725                 count++;
2726
2727         idx = 1;
2728
2729         qsort(&matches[0], (size_t)(len), sizeof(char *), ast_el_sort_compare);
2730
2731         for (; count > 0; count--) {
2732                 numoutputline = 0;
2733                 for (i = 0; i < limit && matches[idx]; i++, idx++) {
2734
2735                         /* Don't print dupes */
2736                         if ( (matches[idx+1] != NULL && strcmp(matches[idx], matches[idx+1]) == 0 ) ) {
2737                                 i--;
2738                                 ast_free(matches[idx]);
2739                                 matches[idx] = NULL;
2740                                 continue;
2741                         }
2742
2743                         numoutput++;
2744                         numoutputline++;
2745                         fprintf(stdout, "%-*s  ", max, matches[idx]);
2746                         ast_free(matches[idx]);
2747                         matches[idx] = NULL;
2748                 }
2749                 if (numoutputline > 0)
2750                         fprintf(stdout, "\n");
2751         }
2752
2753         return numoutput;
2754 }
2755
2756
2757 static char *cli_complete(EditLine *editline, int ch)
2758 {
2759         int len = 0;
2760         char *ptr;
2761         int nummatches = 0;
2762         char **matches;
2763         int retval = CC_ERROR;
2764         char buf[2048], savechr;
2765         int res;
2766
2767         LineInfo *lf = (LineInfo *)el_line(editline);
2768
2769         savechr = *(char *)lf->cursor;
2770         *(char *)lf->cursor = '\0';
2771         ptr = (char *)lf->cursor;
2772         if (ptr) {
2773                 while (ptr > lf->buffer) {
2774                         if (isspace(*ptr)) {
2775                                 ptr++;
2776                                 break;
2777                         }
2778                         ptr--;
2779                 }
2780         }
2781
2782         len = lf->cursor - ptr;
2783
2784         if (ast_opt_remote) {
2785                 snprintf(buf, sizeof(buf), "_COMMAND NUMMATCHES \"%s\" \"%s\"", lf->buffer, ptr);
2786                 fdsend(ast_consock, buf);
2787                 if ((res = read(ast_consock, buf, sizeof(buf) - 1)) < 0) {
2788                         return (char*)(CC_ERROR);
2789                 }
2790                 buf[res] = '\0';
2791                 nummatches = atoi(buf);
2792
2793                 if (nummatches > 0) {
2794                         char *mbuf;
2795                         int mlen = 0, maxmbuf = 2048;
2796                         /* Start with a 2048 byte buffer */
2797                         if (!(mbuf = ast_malloc(maxmbuf))) {
2798                                 *((char *) lf->cursor) = savechr;
2799                                 return (char *)(CC_ERROR);
2800                         }
2801                         snprintf(buf, sizeof(buf), "_COMMAND MATCHESARRAY \"%s\" \"%s\"", lf->buffer, ptr);
2802                         fdsend(ast_consock, buf);
2803                         res = 0;
2804                         mbuf[0] = '\0';
2805                         while (!strstr(mbuf, AST_CLI_COMPLETE_EOF) && res != -1) {
2806                                 if (mlen + 1024 > maxmbuf) {
2807                                         /* Every step increment buffer 1024 bytes */
2808                                         maxmbuf += 1024;
2809                                         if (!(mbuf = ast_realloc(mbuf, maxmbuf))) {
2810                                                 *((char *) lf->cursor) = savechr;
2811                                                 return (char *)(CC_ERROR);
2812                                         }
2813                                 }
2814                                 /* Only read 1024 bytes at a time */
2815                                 res = read(ast_consock, mbuf + mlen, 1024);
2816                                 if (res > 0)
2817                                         mlen += res;
2818                         }
2819                         mbuf[mlen] = '\0';
2820
2821                         matches = ast_el_strtoarr(mbuf);
2822                         ast_free(mbuf);
2823                 } else
2824                         matches = (char **) NULL;
2825         } else {
2826                 char **p, *oldbuf=NULL;
2827                 nummatches = 0;
2828                 matches = ast_cli_completion_matches((char *)lf->buffer,ptr);
2829                 for (p = matches; p && *p; p++) {
2830                         if (!oldbuf || strcmp(*p,oldbuf))
2831                                 nummatches++;
2832                         oldbuf = *p;
2833                 }
2834         }
2835
2836         if (matches) {
2837                 int i;
2838                 int matches_num, maxlen, match_len;
2839
2840                 if (matches[0][0] != '\0') {
2841                         el_deletestr(editline, (int) len);
2842                         el_insertstr(editline, matches[0]);
2843                         retval = CC_REFRESH;
2844                 }
2845
2846                 if (nummatches == 1) {
2847                         /* Found an exact match */
2848                         el_insertstr(editline, " ");
2849                         retval = CC_REFRESH;
2850                 } else {
2851                         /* Must be more than one match */
2852                         for (i = 1, maxlen = 0; matches[i]; i++) {
2853                                 match_len = strlen(matches[i]);
2854                                 if (match_len > maxlen)
2855                                         maxlen = match_len;
2856                         }
2857                         matches_num = i - 1;
2858                         if (matches_num >1) {
2859                                 fprintf(stdout, "\n");
2860                                 ast_cli_display_match_list(matches, nummatches, maxlen);
2861                                 retval = CC_REDISPLAY;
2862                         } else {
2863                                 el_insertstr(editline," ");
2864                                 retval = CC_REFRESH;
2865                         }
2866                 }
2867                 for (i = 0; matches[i]; i++)
2868                         ast_free(matches[i]);
2869                 ast_free(matches);
2870         }
2871
2872         *((char *) lf->cursor) = savechr;
2873
2874         return (char *)(long)retval;
2875 }
2876
2877 static int ast_el_initialize(void)
2878 {
2879         HistEvent ev;
2880         char *editor, *editrc = getenv("EDITRC");
2881
2882         if (!(editor = getenv("AST_EDITMODE"))) {
2883                 if (!(editor = getenv("AST_EDITOR"))) {
2884                         editor = "emacs";
2885                 }
2886         }
2887
2888         if (el != NULL)
2889                 el_end(el);
2890         if (el_hist != NULL)
2891                 history_end(el_hist);
2892
2893         el = el_init("asterisk", stdin, stdout, stderr);
2894         el_set(el, EL_PROMPT, cli_prompt);
2895
2896         el_set(el, EL_EDITMODE, 1);
2897         el_set(el, EL_EDITOR, editor);
2898         el_hist = history_init();
2899         if (!el || !el_hist)
2900                 return -1;
2901
2902         /* setup history with 100 entries */
2903         history(el_hist, &ev, H_SETSIZE, 100);
2904
2905         el_set(el, EL_HIST, history, el_hist);
2906
2907         el_set(el, EL_ADDFN, "ed-complete", "Complete argument", cli_complete);
2908         /* Bind <tab> to command completion */
2909         el_set(el, EL_BIND, "^I", "ed-complete", NULL);
2910         /* Bind ? to command completion */
2911         el_set(el, EL_BIND, "?", "ed-complete", NULL);
2912         /* Bind ^D to redisplay */
2913         el_set(el, EL_BIND, "^D", "ed-redisplay", NULL);
2914         /* Bind Delete to delete char left */
2915         el_set(el, EL_BIND, "\\e[3~", "ed-delete-next-char", NULL);
2916         /* Bind Home and End to move to line start and end */
2917         el_set(el, EL_BIND, "\\e[1~", "ed-move-to-beg", NULL);
2918         el_set(el, EL_BIND, "\\e[4~", "ed-move-to-end", NULL);
2919         /* Bind C-left and C-right to move by word (not all terminals) */
2920         el_set(el, EL_BIND, "\\eOC", "vi-next-word", NULL);
2921         el_set(el, EL_BIND, "\\eOD", "vi-prev-word", NULL);
2922
2923         if (editrc) {
2924                 el_source(el, editrc);
2925         }
2926
2927         return 0;
2928 }
2929
2930 #define MAX_HISTORY_COMMAND_LENGTH 256
2931
2932 static int ast_el_add_history(char *buf)
2933 {
2934         HistEvent ev;
2935
2936         if (el_hist == NULL || el == NULL)
2937                 ast_el_initialize();
2938         if (strlen(buf) > (MAX_HISTORY_COMMAND_LENGTH - 1))
2939                 return 0;
2940         return (history(el_hist, &ev, H_ENTER, ast_strip(ast_strdupa(buf))));
2941 }
2942
2943 static int ast_el_write_history(char *filename)
2944 {
2945         HistEvent ev;
2946
2947         if (el_hist == NULL || el == NULL)
2948                 ast_el_initialize();
2949
2950         return (history(el_hist, &ev, H_SAVE, filename));
2951 }
2952
2953 static int ast_el_read_history(char *filename)
2954 {
2955         HistEvent ev;
2956
2957         if (el_hist == NULL || el == NULL) {
2958                 ast_el_initialize();
2959         }
2960
2961         return history(el_hist, &ev, H_LOAD, filename);
2962 }
2963
2964 static void ast_remotecontrol(char *data)
2965 {
2966         char buf[80];
2967         int res;
2968         char filename[80] = "";
2969         char *hostname;
2970         char *cpid;
2971         char *version;
2972         int pid;
2973         char *stringp = NULL;
2974
2975         char *ebuf;
2976         int num = 0;
2977
2978         memset(&sig_flags, 0, sizeof(sig_flags));
2979         signal(SIGINT, __remote_quit_handler);
2980         signal(SIGTERM, __remote_quit_handler);
2981         signal(SIGHUP, __remote_quit_handler);
2982
2983         if (read(ast_consock, buf, sizeof(buf)) < 0) {
2984                 ast_log(LOG_ERROR, "read() failed: %s\n", strerror(errno));
2985                 return;
2986         }
2987         if (data) {
2988                 char prefix[] = "cli quit after ";
2989                 char *tmp = ast_alloca(strlen(data) + strlen(prefix) + 1);
2990                 sprintf(tmp, "%s%s", prefix, data);
2991                 if (write(ast_consock, tmp, strlen(tmp) + 1) < 0) {
2992                         ast_log(LOG_ERROR, "write() failed: %s\n", strerror(errno));
2993                         if (sig_flags.need_quit || sig_flags.need_quit_handler) {
2994                                 return;
2995                         }
2996                 }
2997         }
2998         stringp = buf;
2999         hostname = strsep(&stringp, "/");
3000         cpid = strsep(&stringp, "/");
3001         version = strsep(&stringp, "\n");
3002         if (!version)
3003                 version = "<Version Unknown>";
3004         stringp = hostname;
3005         strsep(&stringp, ".");
3006         if (cpid)
3007                 pid = atoi(cpid);
3008         else
3009                 pid = -1;
3010         if (!data) {
3011                 if (!ast_opt_mute) {
3012                         fdsend(ast_consock, "logger mute silent");
3013                 } else {
3014                         printf("log and verbose output currently muted ('logger mute' to unmute)\n");
3015                 }
3016         }
3017
3018         if (ast_opt_exec && data) {  /* hack to print output then exit if asterisk -rx is used */
3019                 int linefull = 1, prev_linefull = 1, prev_line_verbose = 0;
3020                 struct pollfd fds;
3021                 fds.fd = ast_consock;
3022                 fds.events = POLLIN;
3023                 fds.revents = 0;
3024
3025                 while (ast_poll(&fds, 1, 60000) > 0) {
3026                         char buffer[512] = "", *curline = buffer, *nextline;
3027                         int not_written = 1;
3028
3029                         if (sig_flags.need_quit || sig_flags.need_quit_handler) {
3030                                 break;
3031                         }
3032
3033                         if (read(ast_consock, buffer, sizeof(buffer) - 1) <= 0) {
3034                                 break;
3035                         }
3036
3037                         do {
3038                                 prev_linefull = linefull;
3039                                 if ((nextline = strchr(curline, '\n'))) {
3040                                         linefull = 1;
3041                                         nextline++;
3042                                 } else {
3043                                         linefull = 0;
3044                                         nextline = strchr(curline, '\0');
3045                                 }
3046
3047                                 /* Skip verbose lines */
3048                                 /* Prev line full? | Line is verbose | Last line verbose? | Print
3049                                  * TRUE            | TRUE*           | TRUE               | FALSE
3050                                  * TRUE            | TRUE*           | FALSE              | FALSE
3051                                  * TRUE            | FALSE*          | TRUE               | TRUE
3052                                  * TRUE            | FALSE*          | FALSE              | TRUE
3053                                  * FALSE           | TRUE            | TRUE*              | FALSE
3054                                  * FALSE           | TRUE            | FALSE*             | TRUE
3055                                  * FALSE           | FALSE           | TRUE*              | FALSE
3056                                  * FALSE           | FALSE           | FALSE*             | TRUE
3057                                  */
3058                                 if ((!prev_linefull && !prev_line_verbose) || (prev_linefull && *curline > 0)) {
3059                                         prev_line_verbose = 0;
3060                                         not_written = 0;
3061                                         if (write(STDOUT_FILENO, curline, nextline - curline) < 0) {
3062                                                 ast_log(LOG_WARNING, "write() failed: %s\n", strerror(errno));
3063                                         }
3064                                 } else {
3065                                         prev_line_verbose = 1;
3066                                 }
3067                                 curline = nextline;
3068                         } while (!ast_strlen_zero(curline));
3069
3070                         /* No non-verbose output in 60 seconds. */
3071                         if (not_written) {
3072                                 break;
3073                         }
3074                 }
3075                 return;
3076         }
3077
3078         ast_verbose("Connected to Asterisk %s currently running on %s (pid = %d)\n", version, hostname, pid);
3079         remotehostname = hostname;
3080         if (getenv("HOME"))
3081                 snprintf(filename, sizeof(filename), "%s/.asterisk_history", getenv("HOME"));
3082         if (el_hist == NULL || el == NULL)
3083                 ast_el_initialize();
3084
3085         el_set(el, EL_GETCFN, ast_el_read_char);
3086
3087         if (!ast_strlen_zero(filename))
3088                 ast_el_read_history(filename);
3089
3090         for (;;) {
3091                 ebuf = (char *)el_gets(el, &num);
3092
3093                 if (sig_flags.need_quit || sig_flags.need_quit_handler) {
3094                         break;
3095                 }
3096
3097                 if (!ebuf && write(1, "", 1) < 0)
3098                         break;
3099
3100                 if (!ast_strlen_zero(ebuf)) {
3101                         if (ebuf[strlen(ebuf)-1] == '\n')
3102                                 ebuf[strlen(ebuf)-1] = '\0';
3103                         if (!remoteconsolehandler(ebuf)) {
3104                                 res = write(ast_consock, ebuf, strlen(ebuf) + 1);
3105                                 if (res < 1) {
3106                                         ast_log(LOG_WARNING, "Unable to write: %s\n", strerror(errno));
3107                                         break;
3108                                 }
3109                         }
3110                 }
3111         }
3112         printf("\nDisconnected from Asterisk server\n");
3113 }
3114
3115 static int show_version(void)
3116 {
3117         printf("Asterisk %s\n", ast_get_version());
3118         return 0;
3119 }
3120
3121 static int show_cli_help(void)
3122 {
3123         printf("Asterisk %s, Copyright (C) 1999 - 2012, Digium, Inc. and others.\n", ast_get_version());
3124         printf("Usage: asterisk [OPTIONS]\n");
3125         printf("Valid Options:\n");
3126         printf("   -V              Display version number and exit\n");
3127         printf("   -C <configfile> Use an alternate configuration file\n");
3128         printf("   -G <group>      Run as a group other than the caller\n");
3129         printf("   -U <user>       Run as a user other than the caller\n");
3130         printf("   -c              Provide console CLI\n");
3131         printf("   -d              Enable extra debugging\n");
3132 #if HAVE_WORKING_FORK
3133         printf("   -f              Do not fork\n");
3134         printf("   -F              Always fork\n");
3135 #endif
3136         printf("   -g              Dump core in case of a crash\n");
3137         printf("   -h              This help screen\n");
3138         printf("   -i              Initialize crypto keys at startup\n");
3139         printf("   -I              Enable internal timing if DAHDI timer is available\n");
3140         printf("   -L <load>       Limit the maximum load average before rejecting new calls\n");
3141         printf("   -M <value>      Limit the maximum number of calls to the specified value\n");
3142         printf("   -m              Mute debugging and console output on the console\n");
3143         printf("   -n              Disable console colorization\n");
3144         printf("   -p              Run as pseudo-realtime thread\n");
3145         printf("   -q              Quiet mode (suppress output)\n");
3146         printf("   -r              Connect to Asterisk on this machine\n");
3147         printf("   -R              Same as -r, except attempt to reconnect if disconnected\n");
3148         printf("   -s <socket>     Connect to Asterisk via socket <socket> (only valid with -r)\n");
3149         printf("   -t              Record soundfiles in /var/tmp and move them where they\n");
3150         printf("                   belong after they are done\n");
3151         printf("   -T              Display the time in [Mmm dd hh:mm:ss] format for each line\n");
3152         printf("                   of output to the CLI\n");
3153         printf("   -v              Increase verbosity (multiple v's = more verbose)\n");
3154         printf("   -x <cmd>        Execute command <cmd> (implies -r)\n");
3155         printf("   -X              Execute includes by default (allows #exec in asterisk.conf)\n");
3156         printf("   -W              Adjust terminal colors to compensate for a light background\n");
3157         printf("\n");
3158         return 0;
3159 }
3160
3161 static void ast_readconfig(void)
3162 {
3163         struct ast_config *cfg;
3164         struct ast_variable *v;
3165         char *config = DEFAULT_CONFIG_FILE;
3166         char hostname[MAXHOSTNAMELEN] = "";
3167         struct ast_flags config_flags = { CONFIG_FLAG_NOREALTIME };
3168         struct {
3169                 unsigned int dbdir:1;
3170                 unsigned int keydir:1;
3171         } found = { 0, 0 };
3172
3173         /* Set default value */
3174         option_dtmfminduration = AST_MIN_DTMF_DURATION;
3175
3176         if (ast_opt_override_config) {
3177                 cfg = ast_config_load2(ast_config_AST_CONFIG_FILE, "" /* core, can't reload */, config_flags);
3178                 if (cfg == CONFIG_STATUS_FILEMISSING || cfg == CONFIG_STATUS_FILEUNCHANGED || cfg == CONFIG_STATUS_FILEINVALID)
3179                         ast_log(LOG_WARNING, "Unable to open specified master config file '%s', using built-in defaults\n", ast_config_AST_CONFIG_FILE);
3180         } else
3181                 cfg = ast_config_load2(config, "" /* core, can't reload */, config_flags);
3182
3183         /* init with buildtime config */
3184         ast_copy_string(cfg_paths.config_dir, DEFAULT_CONFIG_DIR, sizeof(cfg_paths.config_dir));
3185         ast_copy_string(cfg_paths.spool_dir, DEFAULT_SPOOL_DIR, sizeof(cfg_paths.spool_dir));
3186         ast_copy_string(cfg_paths.module_dir, DEFAULT_MODULE_DIR, sizeof(cfg_paths.module_dir));
3187         snprintf(cfg_paths.monitor_dir, sizeof(cfg_paths.monitor_dir), "%s/monitor", cfg_paths.spool_dir);
3188         ast_copy_string(cfg_paths.var_dir, DEFAULT_VAR_DIR, sizeof(cfg_paths.var_dir));
3189         ast_copy_string(cfg_paths.data_dir, DEFAULT_DATA_DIR, sizeof(cfg_paths.data_dir));
3190         ast_copy_string(cfg_paths.log_dir, DEFAULT_LOG_DIR, sizeof(cfg_paths.log_dir));
3191         ast_copy_string(cfg_paths.agi_dir, DEFAULT_AGI_DIR, sizeof(cfg_paths.agi_dir));
3192         ast_copy_string(cfg_paths.db_path, DEFAULT_DB, sizeof(cfg_paths.db_path));
3193         ast_copy_string(cfg_paths.sbin_dir, DEFAULT_SBIN_DIR, sizeof(cfg_paths.sbin_dir));
3194         ast_copy_string(cfg_paths.key_dir, DEFAULT_KEY_DIR, sizeof(cfg_paths.key_dir));
3195         ast_copy_string(cfg_paths.pid_path, DEFAULT_PID, sizeof(cfg_paths.pid_path));
3196         ast_copy_string(cfg_paths.socket_path, DEFAULT_SOCKET, sizeof(cfg_paths.socket_path));
3197         ast_copy_string(cfg_paths.run_dir, DEFAULT_RUN_DIR, sizeof(cfg_paths.run_dir));
3198
3199         ast_set_default_eid(&ast_eid_default);
3200
3201         /* no asterisk.conf? no problem, use buildtime config! */
3202         if (cfg == CONFIG_STATUS_FILEMISSING || cfg == CONFIG_STATUS_FILEUNCHANGED || cfg == CONFIG_STATUS_FILEINVALID) {
3203                 return;
3204         }
3205
3206         for (v = ast_variable_browse(cfg, "files"); v; v = v->next) {
3207                 if (!strcasecmp(v->name, "astctlpermissions"))
3208                         ast_copy_string(ast_config_AST_CTL_PERMISSIONS, v->value, sizeof(ast_config_AST_CTL_PERMISSIONS));
3209                 else if (!strcasecmp(v->name, "astctlowner"))
3210                         ast_copy_string(ast_config_AST_CTL_OWNER, v->value, sizeof(ast_config_AST_CTL_OWNER));
3211                 else if (!strcasecmp(v->name, "astctlgroup"))
3212                         ast_copy_string(ast_config_AST_CTL_GROUP, v->value, sizeof(ast_config_AST_CTL_GROUP));
3213                 else if (!strcasecmp(v->name, "astctl"))
3214                         ast_copy_string(ast_config_AST_CTL, v->value, sizeof(ast_config_AST_CTL));
3215         }
3216
3217         for (v = ast_variable_browse(cfg, "directories"); v; v = v->next) {
3218                 if (!strcasecmp(v->name, "astetcdir")) {
3219                         ast_copy_string(cfg_paths.config_dir, v->value, sizeof(cfg_paths.config_dir));
3220                 } else if (!strcasecmp(v->name, "astspooldir")) {
3221                         ast_copy_string(cfg_paths.spool_dir, v->value, sizeof(cfg_paths.spool_dir));
3222                         snprintf(cfg_paths.monitor_dir, sizeof(cfg_paths.monitor_dir), "%s/monitor", v->value);
3223                 } else if (!strcasecmp(v->name, "astvarlibdir")) {
3224                         ast_copy_string(cfg_paths.var_dir, v->value, sizeof(cfg_paths.var_dir));
3225                         if (!found.dbdir)
3226                                 snprintf(cfg_paths.db_path, sizeof(cfg_paths.db_path), "%s/astdb", v->value);
3227                 } else if (!strcasecmp(v->name, "astdbdir")) {
3228                         snprintf(cfg_paths.db_path, sizeof(cfg_paths.db_path), "%s/astdb", v->value);
3229                         found.dbdir = 1;
3230                 } else if (!strcasecmp(v->name, "astdatadir")) {
3231                         ast_copy_string(cfg_paths.data_dir, v->value, sizeof(cfg_paths.data_dir));
3232                         if (!found.keydir)
3233                                 snprintf(cfg_paths.key_dir, sizeof(cfg_paths.key_dir), "%s/keys", v->value);
3234                 } else if (!strcasecmp(v->name, "astkeydir")) {
3235                         snprintf(cfg_paths.key_dir, sizeof(cfg_paths.key_dir), "%s/keys", v->value);
3236                         found.keydir = 1;
3237                 } else if (!strcasecmp(v->name, "astlogdir")) {
3238                         ast_copy_string(cfg_paths.log_dir, v->value, sizeof(cfg_paths.log_dir));
3239                 } else if (!strcasecmp(v->name, "astagidir")) {
3240                         ast_copy_string(cfg_paths.agi_dir, v->value, sizeof(cfg_paths.agi_dir));
3241                 } else if (!strcasecmp(v->name, "astrundir")) {
3242                         snprintf(cfg_paths.pid_path, sizeof(cfg_paths.pid_path), "%s/%s", v->value, "asterisk.pid");
3243                         snprintf(cfg_paths.socket_path, sizeof(cfg_paths.socket_path), "%s/%s", v->value, ast_config_AST_CTL);
3244                         ast_copy_string(cfg_paths.run_dir, v->value, sizeof(cfg_paths.run_dir));
3245                 } else if (!strcasecmp(v->name, "astmoddir")) {
3246                         ast_copy_string(cfg_paths.module_dir, v->value, sizeof(cfg_paths.module_dir));
3247                 } else if (!strcasecmp(v->name, "astsbindir")) {
3248                         ast_copy_string(cfg_paths.sbin_dir, v->value, sizeof(cfg_paths.sbin_dir));
3249                 }
3250         }
3251
3252         for (v = ast_variable_browse(cfg, "options"); v; v = v->next) {
3253                 /* verbose level (-v at startup) */
3254                 if (!strcasecmp(v->name, "verbose")) {
3255                         option_verbose = atoi(v->value);
3256                 /* whether or not to force timestamping in CLI verbose output. (-T at startup) */
3257                 } else if (!strcasecmp(v->name, "timestamp")) {
3258                         ast_set2_flag(&ast_options, ast_true(v->value), AST_OPT_FLAG_TIMESTAMP);
3259                 /* whether or not to support #exec in config files */
3260                 } else if (!strcasecmp(v->name, "execincludes")) {
3261                         ast_set2_flag(&ast_options, ast_true(v->value), AST_OPT_FLAG_EXEC_INCLUDES);
3262                 /* debug level (-d at startup) */
3263                 } else if (!strcasecmp(v->name, "debug")) {
3264                         option_debug = 0;
3265                         if (sscanf(v->value, "%30d", &option_debug) != 1) {
3266                                 option_debug = ast_true(v->value);
3267                         }
3268 #if HAVE_WORKING_FORK
3269                 /* Disable forking (-f at startup) */
3270                 } else if (!strcasecmp(v->name, "nofork")) {
3271                         ast_set2_flag(&ast_options, ast_true(v->value), AST_OPT_FLAG_NO_FORK);
3272                 /* Always fork, even if verbose or debug are enabled (-F at startup) */
3273                 } else if (!strcasecmp(v->name, "alwaysfork")) {
3274                         ast_set2_flag(&ast_options, ast_true(v->value), AST_OPT_FLAG_ALWAYS_FORK);
3275 #endif
3276                 /* Run quietly (-q at startup ) */
3277                 } else if (!strcasecmp(v->name, "quiet")) {
3278                         ast_set2_flag(&ast_options, ast_true(v->value), AST_OPT_FLAG_QUIET);
3279                 /* Run as console (-c at startup, implies nofork) */
3280                 } else if (!strcasecmp(v->name, "console")) {
3281                         ast_set2_flag(&ast_options, ast_true(v->value), AST_OPT_FLAG_NO_FORK | AST_OPT_FLAG_CONSOLE);
3282                 /* Run with high priority if the O/S permits (-p at startup) */
3283                 } else if (!strcasecmp(v->name, "highpriority")) {
3284                         ast_set2_flag(&ast_options, ast_true(v->value), AST_OPT_FLAG_HIGH_PRIORITY);
3285                 /* Initialize RSA auth keys (IAX2) (-i at startup) */
3286                 } else if (!strcasecmp(v->name, "initcrypto")) {
3287                         ast_set2_flag(&ast_options, ast_true(v->value), AST_OPT_FLAG_INIT_KEYS);
3288                 /* Disable ANSI colors for console (-c at startup) */
3289                 } else if (!strcasecmp(v->name, "nocolor")) {
3290                         ast_set2_flag(&ast_options, ast_true(v->value), AST_OPT_FLAG_NO_COLOR);
3291                 /* Disable some usage warnings for picky people :p */
3292                 } else if (!strcasecmp(v->name, "dontwarn")) {
3293                         ast_set2_flag(&ast_options, ast_true(v->value), AST_OPT_FLAG_DONT_WARN);
3294                 /* Dump core in case of crash (-g) */
3295                 } else if (!strcasecmp(v->name, "dumpcore")) {
3296                         ast_set2_flag(&ast_options, ast_true(v->value), AST_OPT_FLAG_DUMP_CORE);
3297                 /* Cache recorded sound files to another directory during recording */
3298                 } else if (!strcasecmp(v->name, "cache_record_files")) {
3299                         ast_set2_flag(&ast_options, ast_true(v->value), AST_OPT_FLAG_CACHE_RECORD_FILES);
3300                 /* Specify cache directory */
3301                 }  else if (!strcasecmp(v->name, "record_cache_dir")) {
3302                         ast_copy_string(record_cache_dir, v->value, AST_CACHE_DIR_LEN);
3303                 /* Build transcode paths via SLINEAR, instead of directly */
3304                 } else if (!strcasecmp(v->name, "transcode_via_sln")) {
3305                         ast_set2_flag(&ast_options, ast_true(v->value), AST_OPT_FLAG_TRANSCODE_VIA_SLIN);
3306                 /* Transmit SLINEAR silence while a channel is being recorded or DTMF is being generated on a channel */
3307                 } else if (!strcasecmp(v->name, "transmit_silence_during_record") || !strcasecmp(v->name, "transmit_silence")) {
3308                         ast_set2_flag(&ast_options, ast_true(v->value), AST_OPT_FLAG_TRANSMIT_SILENCE);
3309                 /* Enable internal timing */
3310                 } else if (!strcasecmp(v->name, "internal_timing")) {
3311                         ast_set2_flag(&ast_options, ast_true(v->value), AST_OPT_FLAG_INTERNAL_TIMING);
3312                 } else if (!strcasecmp(v->name, "mindtmfduration")) {
3313                         if (sscanf(v->value, "%30u", &option_dtmfminduration) != 1) {
3314                                 option_dtmfminduration = AST_MIN_DTMF_DURATION;
3315                         }
3316                 } else if (!strcasecmp(v->name, "maxcalls")) {
3317                         if ((sscanf(v->value, "%30d", &option_maxcalls) != 1) || (option_maxcalls < 0)) {
3318                                 option_maxcalls = 0;
3319                         }
3320                 } else if (!strcasecmp(v->name, "maxload")) {
3321                         double test[1];
3322
3323                         if (getloadavg(test, 1) == -1) {
3324                                 ast_log(LOG_ERROR, "Cannot obtain load average on this system. 'maxload' option disabled.\n");
3325                                 option_maxload = 0.0;
3326                         } else if ((sscanf(v->value, "%30lf", &option_maxload) != 1) || (option_maxload < 0.0)) {
3327                                 option_maxload = 0.0;
3328                         }
3329                 /* Set the maximum amount of open files */
3330                 } else if (!strcasecmp(v->name, "maxfiles")) {
3331                         option_maxfiles = atoi(v->value);
3332                         set_ulimit(option_maxfiles);
3333                 /* What user to run as */
3334                 } else if (!strcasecmp(v->name, "runuser")) {
3335                         ast_copy_string(cfg_paths.run_user, v->value, sizeof(cfg_paths.run_user));
3336                 /* What group to run as */
3337                 } else if (!strcasecmp(v->name, "rungroup")) {
3338                         ast_copy_string(cfg_paths.run_group, v->value, sizeof(cfg_paths.run_group));
3339                 } else if (!strcasecmp(v->name, "systemname")) {
3340                         ast_copy_string(cfg_paths.system_name, v->value, sizeof(cfg_paths.system_name));
3341                 } else if (!strcasecmp(v->name, "autosystemname")) {
3342                         if (ast_true(v->value)) {
3343                                 if (!gethostname(hostname, sizeof(hostname) - 1))
3344                                         ast_copy_string(cfg_paths.system_name, hostname, sizeof(cfg_paths.system_name));
3345                                 else {
3346                                         if (ast_strlen_zero(ast_config_AST_SYSTEM_NAME)){
3347                                                 ast_copy_string(cfg_paths.system_name, "localhost", sizeof(cfg_paths.system_name));
3348                                         }
3349                                         ast_log(LOG_ERROR, "Cannot obtain hostname for this system.  Using '%s' instead.\n", ast_config_AST_SYSTEM_NAME);
3350                                 }
3351                         }
3352                 } else if (!strcasecmp(v->name, "languageprefix")) {
3353                         ast_language_is_prefix = ast_true(v->value);
3354                 } else if (!strcasecmp(v->name, "defaultlanguage")) {
3355                         ast_copy_string(defaultlanguage, v->value, MAX_LANGUAGE);
3356                 } else if (!strcasecmp(v->name, "lockmode")) {
3357                         if (!strcasecmp(v->value, "lockfile")) {
3358                                 ast_set_lock_type(AST_LOCK_TYPE_LOCKFILE);
3359                         } else if (!strcasecmp(v->value, "flock")) {
3360                                 ast_set_lock_type(AST_LOCK_TYPE_FLOCK);
3361                         } else {
3362                                 ast_log(LOG_WARNING, "'%s' is not a valid setting for the lockmode option, "
3363                                         "defaulting to 'lockfile'\n", v->value);
3364                                 ast_set_lock_type(AST_LOCK_TYPE_LOCKFILE);
3365                         }
3366 #if defined(HAVE_SYSINFO)
3367                 } else if (!strcasecmp(v->name, "minmemfree")) {
3368                         /* specify the minimum amount of free memory to retain.  Asterisk should stop accepting new calls
3369                          * if the amount of free memory falls below this watermark */
3370                         if ((sscanf(v->value, "%30ld", &option_minmemfree) != 1) || (option_minmemfree < 0)) {
3371                                 option_minmemfree = 0;
3372                         }
3373 #endif
3374                 } else if (!strcasecmp(v->name, "entityid")) {
3375                         struct ast_eid tmp_eid;
3376                         if (!ast_str_to_eid(&tmp_eid, v->value)) {
3377                                 ast_verbose("Successfully set global EID to '%s'\n", v->value);
3378                                 ast_eid_default = tmp_eid;
3379                         } else
3380                                 ast_verbose("Invalid Entity ID '%s' provided\n", v->value);
3381                 } else if (!strcasecmp(v->name, "lightbackground")) {
3382                         ast_set2_flag(&ast_options, ast_true(v->value), AST_OPT_FLAG_LIGHT_BACKGROUND);
3383                 } else if (!strcasecmp(v->name, "forceblackbackground")) {
3384                         ast_set2_flag(&ast_options, ast_true(v->value), AST_OPT_FLAG_FORCE_BLACK_BACKGROUND);
3385                 } else if (!strcasecmp(v->name, "hideconnect")) {
3386                         ast_set2_flag(&ast_options, ast_true(v->value), AST_OPT_FLAG_HIDE_CONSOLE_CONNECT);
3387                 } else if (!strcasecmp(v->name, "lockconfdir")) {
3388                         ast_set2_flag(&ast_options, ast_true(v->value), AST_OPT_FLAG_LOCK_CONFIG_DIR);
3389                 } else if (!strcasecmp(v->name, "stdexten")) {
3390                         /* Choose how to invoke the extensions.conf stdexten */
3391                         if (!strcasecmp(v->value, "gosub")) {
3392                                 ast_clear_flag(&ast_options, AST_OPT_FLAG_STDEXTEN_MACRO);
3393                         } else if (!strcasecmp(v->value, "macro")) {
3394                                 ast_set_flag(&ast_options, AST_OPT_FLAG_STDEXTEN_MACRO);
3395                         } else {
3396                                 ast_log(LOG_WARNING,
3397                                         "'%s' is not a valid setting for the stdexten option, defaulting to 'gosub'\n",
3398                                         v->value);
3399                                 ast_clear_flag(&ast_options, AST_OPT_FLAG_STDEXTEN_MACRO);
3400                         }
3401                 }
3402         }
3403         for (v = ast_variable_browse(cfg, "compat"); v; v = v->next) {
3404                 float version;
3405                 if (sscanf(v->value, "%30f", &version) != 1) {
3406                         ast_log(LOG_WARNING, "Compatibility version for option '%s' is not a number: '%s'\n", v->name, v->value);
3407                         continue;
3408                 }
3409                 if (!strcasecmp(v->name, "app_set")) {
3410                         ast_set2_flag(&ast_compat, version < 1.5 ? 1 : 0, AST_COMPAT_APP_SET);
3411                 } else if (!strcasecmp(v->name, "res_agi")) {
3412                         ast_set2_flag(&ast_compat, version < 1.5 ? 1 : 0, AST_COMPAT_DELIM_RES_AGI);
3413                 } else if (!strcasecmp(v->name, "pbx_realtime")) {
3414                         ast_set2_flag(&ast_compat, version < 1.5 ? 1 : 0, AST_COMPAT_DELIM_PBX_REALTIME);
3415                 }
3416         }
3417         ast_config_destroy(cfg);
3418 }
3419
3420 static void *monitor_sig_flags(void *unused)
3421 {
3422         for (;;) {
3423                 struct pollfd p = { sig_alert_pipe[0], POLLIN, 0 };
3424                 int a;
3425                 ast_poll(&p, 1, -1);
3426                 if (sig_flags.need_reload) {
3427                         sig_flags.need_reload = 0;
3428                         ast_module_reload(NULL);
3429                 }
3430                 if (sig_flags.need_quit) {
3431                         sig_flags.need_quit = 0;
3432                         if ((consolethread != AST_PTHREADT_NULL) && (consolethread != pthread_self())) {
3433                                 sig_flags.need_quit_handler = 1;
3434                                 pthread_kill(consolethread, SIGURG);
3435                         } else {
3436                                 quit_handler(0, SHUTDOWN_NORMAL, 0);
3437                         }
3438                 }
3439                 if (read(sig_alert_pipe[0], &a, sizeof(a)) != sizeof(a)) {
3440                 }
3441         }
3442
3443         return NULL;
3444 }
3445
3446 static void *canary_thread(void *unused)
3447 {
3448         struct stat canary_stat;
3449         struct timeval now;
3450
3451         /* Give the canary time to sing */
3452         sleep(120);
3453
3454         for (;;) {
3455                 now = ast_tvnow();
3456                 if (stat(canary_filename, &canary_stat) || now.tv_sec > canary_stat.st_mtime + 60) {
3457                         ast_log(LOG_WARNING,
3458                                 "The canary is no more.  He has ceased to be!  "
3459                                 "He's expired and gone to meet his maker!  "
3460                                 "He's a stiff!  Bereft of life, he rests in peace.  "
3461                                 "His metabolic processes are now history!  He's off the twig!  "
3462                                 "He's kicked the bucket.  He's shuffled off his mortal coil, "
3463                                 "run down the curtain, and joined the bleeding choir invisible!!  "
3464                                 "THIS is an EX-CANARY.  (Reducing priority)\n");
3465                         ast_set_priority(0);
3466                         pthread_exit(NULL);
3467                 }
3468
3469                 /* Check the canary once a minute */
3470                 sleep(60);
3471         }
3472 }
3473
3474 /* Used by libc's atexit(3) function */
3475 static void canary_exit(void)
3476 {
3477         if (canary_pid > 0)
3478                 kill(canary_pid, SIGKILL);
3479 }
3480
3481 static void run_startup_commands(void)
3482 {
3483         int fd;
3484         struct ast_config *cfg;
3485         struct ast_flags cfg_flags = { 0 };
3486         struct ast_variable *v;
3487
3488         if (!(cfg = ast_config_load2("cli.conf", "" /* core, can't reload */, cfg_flags)))
3489                 return;
3490         if (cfg == CONFIG_STATUS_FILEMISSING || cfg == CONFIG_STATUS_FILEUNCHANGED || cfg == CONFIG_STATUS_FILEINVALID) {
3491                 return;
3492         }
3493
3494         fd = open("/dev/null", O_RDWR);
3495         if (fd < 0) {
3496                 ast_config_destroy(cfg);
3497                 return;
3498         }
3499
3500         for (v = ast_variable_browse(cfg, "startup_commands"); v; v = v->next) {
3501                 if (ast_true(v->value))
3502                         ast_cli_command(fd, v->name);
3503         }
3504
3505         close(fd);
3506         ast_config_destroy(cfg);
3507 }
3508
3509 static void env_init(void)
3510 {
3511         setenv("AST_SYSTEMNAME", ast_config_AST_SYSTEM_NAME, 1);
3512         setenv("AST_BUILD_HOST", ast_build_hostname, 1);
3513         setenv("AST_BUILD_DATE", ast_build_date, 1);
3514         setenv("AST_BUILD_KERNEL", ast_build_kernel, 1);
3515         setenv("AST_BUILD_MACHINE", ast_build_machine, 1);
3516         setenv("AST_BUILD_OS", ast_build_os, 1);
3517         setenv("AST_BUILD_USER", ast_build_user, 1);
3518         setenv("AST_VERSION", ast_get_version(), 1);
3519 }
3520
3521 int main(int argc, char *argv[])
3522 {
3523         int c;
3524         char filename[80] = "";
3525         char hostname[MAXHOSTNAMELEN] = "";
3526         char tmp[80];
3527         char * xarg = NULL;
3528         int x;
3529         FILE *f;
3530         sigset_t sigs;
3531         int num;
3532         int isroot = 1, rundir_exists = 0;
3533         char *buf;
3534         const char *runuser = NULL, *rungroup = NULL;
3535         char *remotesock = NULL;
3536         int moduleresult;         /*!< Result from the module load subsystem */
3537         struct rlimit l;
3538
3539         /* Remember original args for restart */
3540         if (argc > ARRAY_LEN(_argv) - 1) {
3541                 fprintf(stderr, "Truncating argument size to %d\n", (int)ARRAY_LEN(_argv) - 1);
3542                 argc = ARRAY_LEN(_argv) - 1;
3543         }
3544         for (x = 0; x < argc; x++)
3545                 _argv[x] = argv[x];
3546         _argv[x] = NULL;
3547
3548         if (geteuid() != 0)
3549                 isroot = 0;
3550
3551         /* if the progname is rasterisk consider it a remote console */
3552         if (argv[0] && (strstr(argv[0], "rasterisk")) != NULL) {
3553                 ast_set_flag(&ast_options, AST_OPT_FLAG_NO_FORK | AST_OPT_FLAG_REMOTE);
3554         }
3555         if (gethostname(hostname, sizeof(hostname)-1))
3556                 ast_copy_string(hostname, "<Unknown>", sizeof(hostname));
3557         ast_mainpid = getpid();
3558         ast_ulaw_init();
3559         ast_alaw_init();
3560         callerid_init();
3561         ast_builtins_init();
3562         ast_utils_init();
3563         tdd_init();
3564         ast_tps_init();
3565         ast_fd_init();
3566         ast_pbx_init();
3567
3568         if (getenv("HOME"))
3569                 snprintf(filename, sizeof(filename), "%s/.asterisk_history", getenv("HOME"));
3570         /*! \brief Check for options
3571          *
3572          * \todo Document these options
3573          */
3574         while ((c = getopt(argc, argv, "BC:cde:FfG:ghIiL:M:mnpqRrs:TtU:VvWXx:")) != -1) {
3575                 /*!\note Please keep the ordering here to alphabetical, capital letters
3576                  * first.  This will make it easier in the future to select unused
3577                  * option flags for new features. */
3578                 switch (c) {
3579                 case 'B': /* Force black background */
3580                         ast_set_flag(&ast_options, AST_OPT_FLAG_FORCE_BLACK_BACKGROUND);
3581                         ast_clear_flag(&ast_options, AST_OPT_FLAG_LIGHT_BACKGROUND);