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