Add UUID support to Asterisk.
[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
243 #include "../defaults.h"
244
245 /*** DOCUMENTATION
246  ***/
247
248 #ifndef AF_LOCAL
249 #define AF_LOCAL AF_UNIX
250 #define PF_LOCAL PF_UNIX
251 #endif
252
253 #define AST_MAX_CONNECTS 128
254 #define NUM_MSGS 64
255
256 /*! Default minimum DTMF digit length - 80ms */
257 #define AST_MIN_DTMF_DURATION 80
258
259
260 /*! \brief Welcome message when starting a CLI interface */
261 #define WELCOME_MESSAGE \
262     ast_verbose("Asterisk %s, Copyright (C) 1999 - 2012 Digium, Inc. and others.\n" \
263                 "Created by Mark Spencer <markster@digium.com>\n" \
264                 "Asterisk comes with ABSOLUTELY NO WARRANTY; type 'core show warranty' for details.\n" \
265                 "This is free software, with components licensed under the GNU General Public\n" \
266                 "License version 2 and other licenses; you are welcome to redistribute it under\n" \
267                 "certain conditions. Type 'core show license' for details.\n" \
268                 "=========================================================================\n", ast_get_version()) \
269
270 /*! \defgroup main_options Main Configuration Options
271  * \brief Main configuration options from asterisk.conf or OS command line on starting Asterisk.
272  * \arg \ref Config_ast "asterisk.conf"
273  * \note Some of them can be changed in the CLI
274  */
275 /*! @{ */
276
277 struct ast_flags ast_options = { AST_DEFAULT_OPTIONS };
278 struct ast_flags ast_compat = { 0 };
279
280 int option_verbose;                             /*!< Verbosity level */
281 int option_debug;                               /*!< Debug level */
282 double option_maxload;                          /*!< Max load avg on system */
283 int option_maxcalls;                            /*!< Max number of active calls */
284 int option_maxfiles;                            /*!< Max number of open file handles (files, sockets) */
285 unsigned int option_dtmfminduration;            /*!< Minimum duration of DTMF. */
286 #if defined(HAVE_SYSINFO)
287 long option_minmemfree;                         /*!< Minimum amount of free system memory - stop accepting calls if free memory falls below this watermark */
288 #endif
289
290 /*! @} */
291
292 struct ast_eid ast_eid_default;
293
294 /* XXX tmpdir is a subdir of the spool directory, and no way to remap it */
295 char record_cache_dir[AST_CACHE_DIR_LEN] = DEFAULT_TMP_DIR;
296
297 static int ast_socket = -1;             /*!< UNIX Socket for allowing remote control */
298 static int ast_consock = -1;            /*!< UNIX Socket for controlling another asterisk */
299 pid_t ast_mainpid;
300 struct console {
301         int fd;                         /*!< File descriptor */
302         int p[2];                       /*!< Pipe */
303         pthread_t t;                    /*!< Thread of handler */
304         int mute;                       /*!< Is the console muted for logs */
305         int uid;                        /*!< Remote user ID. */
306         int gid;                        /*!< Remote group ID. */
307         int levels[NUMLOGLEVELS];       /*!< Which log levels are enabled for the console */
308 };
309
310 struct ast_atexit {
311         void (*func)(void);
312         AST_LIST_ENTRY(ast_atexit) list;
313 };
314
315 static AST_LIST_HEAD_STATIC(atexits, ast_atexit);
316
317 struct timeval ast_startuptime;
318 struct timeval ast_lastreloadtime;
319
320 static History *el_hist;
321 static EditLine *el;
322 static char *remotehostname;
323
324 struct console consoles[AST_MAX_CONNECTS];
325
326 char defaultlanguage[MAX_LANGUAGE] = DEFAULT_LANGUAGE;
327
328 static int ast_el_add_history(char *);
329 static int ast_el_read_history(char *);
330 static int ast_el_write_history(char *);
331
332 struct _cfg_paths {
333         char config_dir[PATH_MAX];
334         char module_dir[PATH_MAX];
335         char spool_dir[PATH_MAX];
336         char monitor_dir[PATH_MAX];
337         char var_dir[PATH_MAX];
338         char data_dir[PATH_MAX];
339         char log_dir[PATH_MAX];
340         char agi_dir[PATH_MAX];
341         char run_dir[PATH_MAX];
342         char key_dir[PATH_MAX];
343
344         char config_file[PATH_MAX];
345         char db_path[PATH_MAX];
346         char sbin_dir[PATH_MAX];
347         char pid_path[PATH_MAX];
348         char socket_path[PATH_MAX];
349         char run_user[PATH_MAX];
350         char run_group[PATH_MAX];
351         char system_name[128];
352 };
353
354 static struct _cfg_paths cfg_paths;
355
356 const char *ast_config_AST_CONFIG_DIR   = cfg_paths.config_dir;
357 const char *ast_config_AST_CONFIG_FILE  = cfg_paths.config_file;
358 const char *ast_config_AST_MODULE_DIR   = cfg_paths.module_dir;
359 const char *ast_config_AST_SPOOL_DIR    = cfg_paths.spool_dir;
360 const char *ast_config_AST_MONITOR_DIR  = cfg_paths.monitor_dir;
361 const char *ast_config_AST_VAR_DIR      = cfg_paths.var_dir;
362 const char *ast_config_AST_DATA_DIR     = cfg_paths.data_dir;
363 const char *ast_config_AST_LOG_DIR      = cfg_paths.log_dir;
364 const char *ast_config_AST_AGI_DIR      = cfg_paths.agi_dir;
365 const char *ast_config_AST_KEY_DIR      = cfg_paths.key_dir;
366 const char *ast_config_AST_RUN_DIR      = cfg_paths.run_dir;
367 const char *ast_config_AST_SBIN_DIR = cfg_paths.sbin_dir;
368
369 const char *ast_config_AST_DB           = cfg_paths.db_path;
370 const char *ast_config_AST_PID          = cfg_paths.pid_path;
371 const char *ast_config_AST_SOCKET       = cfg_paths.socket_path;
372 const char *ast_config_AST_RUN_USER     = cfg_paths.run_user;
373 const char *ast_config_AST_RUN_GROUP    = cfg_paths.run_group;
374 const char *ast_config_AST_SYSTEM_NAME  = cfg_paths.system_name;
375
376 static char ast_config_AST_CTL_PERMISSIONS[PATH_MAX];
377 static char ast_config_AST_CTL_OWNER[PATH_MAX] = "\0";
378 static char ast_config_AST_CTL_GROUP[PATH_MAX] = "\0";
379 static char ast_config_AST_CTL[PATH_MAX] = "asterisk.ctl";
380
381 extern unsigned int ast_FD_SETSIZE;
382
383 static char *_argv[256];
384 typedef enum {
385         NOT_SHUTTING_DOWN = -2,
386         SHUTTING_DOWN = -1,
387         /* Valid values for quit_handler niceness below: */
388         SHUTDOWN_FAST,
389         SHUTDOWN_NORMAL,
390         SHUTDOWN_NICE,
391         SHUTDOWN_REALLY_NICE
392 } shutdown_nice_t;
393 static shutdown_nice_t shuttingdown = NOT_SHUTTING_DOWN;
394 static int restartnow;
395 static pthread_t consolethread = AST_PTHREADT_NULL;
396 static pthread_t mon_sig_flags;
397 static int canary_pid = 0;
398 static char canary_filename[128];
399 static int multi_thread_safe;
400
401 static char randompool[256];
402
403 static int sig_alert_pipe[2] = { -1, -1 };
404 static struct {
405          unsigned int need_reload:1;
406          unsigned int need_quit:1;
407          unsigned int need_quit_handler:1;
408 } sig_flags;
409
410 #if !defined(LOW_MEMORY)
411 struct file_version {
412         AST_RWLIST_ENTRY(file_version) list;
413         const char *file;
414         char *version;
415 };
416
417 static AST_RWLIST_HEAD_STATIC(file_versions, file_version);
418
419 void ast_register_file_version(const char *file, const char *version)
420 {
421         struct file_version *new;
422         char *work;
423         size_t version_length;
424
425         work = ast_strdupa(version);
426         work = ast_strip(ast_strip_quoted(work, "$", "$"));
427         version_length = strlen(work) + 1;
428
429         if (!(new = ast_calloc(1, sizeof(*new) + version_length)))
430                 return;
431
432         new->file = file;
433         new->version = (char *) new + sizeof(*new);
434         memcpy(new->version, work, version_length);
435         AST_RWLIST_WRLOCK(&file_versions);
436         AST_RWLIST_INSERT_HEAD(&file_versions, new, list);
437         AST_RWLIST_UNLOCK(&file_versions);
438 }
439
440 void ast_unregister_file_version(const char *file)
441 {
442         struct file_version *find;
443
444         AST_RWLIST_WRLOCK(&file_versions);
445         AST_RWLIST_TRAVERSE_SAFE_BEGIN(&file_versions, find, list) {
446                 if (!strcasecmp(find->file, file)) {
447                         AST_RWLIST_REMOVE_CURRENT(list);
448                         break;
449                 }
450         }
451         AST_RWLIST_TRAVERSE_SAFE_END;
452         AST_RWLIST_UNLOCK(&file_versions);
453
454         if (find)
455                 ast_free(find);
456 }
457
458 char *ast_complete_source_filename(const char *partial, int n)
459 {
460         struct file_version *find;
461         size_t len = strlen(partial);
462         int count = 0;
463         char *res = NULL;
464
465         AST_RWLIST_RDLOCK(&file_versions);
466         AST_RWLIST_TRAVERSE(&file_versions, find, list) {
467                 if (!strncasecmp(find->file, partial, len) && ++count > n) {
468                         res = ast_strdup(find->file);
469                         break;
470                 }
471         }
472         AST_RWLIST_UNLOCK(&file_versions);
473         return res;
474 }
475
476 /*! \brief Find version for given module name */
477 const char *ast_file_version_find(const char *file)
478 {
479         struct file_version *iterator;
480
481         AST_RWLIST_WRLOCK(&file_versions);
482         AST_RWLIST_TRAVERSE(&file_versions, iterator, list) {
483                 if (!strcasecmp(iterator->file, file))
484                         break;
485         }
486         AST_RWLIST_UNLOCK(&file_versions);
487         if (iterator)
488                 return iterator->version;
489         return NULL;
490 }
491
492 struct thread_list_t {
493         AST_RWLIST_ENTRY(thread_list_t) list;
494         char *name;
495         pthread_t id;
496         int lwp;
497 };
498
499 static AST_RWLIST_HEAD_STATIC(thread_list, thread_list_t);
500
501 void ast_register_thread(char *name)
502 {
503         struct thread_list_t *new = ast_calloc(1, sizeof(*new));
504
505         if (!new)
506                 return;
507
508         ast_assert(multi_thread_safe);
509         new->id = pthread_self();
510         new->lwp = ast_get_tid();
511         new->name = name; /* steal the allocated memory for the thread name */
512         AST_RWLIST_WRLOCK(&thread_list);
513         AST_RWLIST_INSERT_HEAD(&thread_list, new, list);
514         AST_RWLIST_UNLOCK(&thread_list);
515 }
516
517 void ast_unregister_thread(void *id)
518 {
519         struct thread_list_t *x;
520
521         AST_RWLIST_WRLOCK(&thread_list);
522         AST_RWLIST_TRAVERSE_SAFE_BEGIN(&thread_list, x, list) {
523                 if ((void *) x->id == id) {
524                         AST_RWLIST_REMOVE_CURRENT(list);
525                         break;
526                 }
527         }
528         AST_RWLIST_TRAVERSE_SAFE_END;
529         AST_RWLIST_UNLOCK(&thread_list);
530         if (x) {
531                 ast_free(x->name);
532                 ast_free(x);
533         }
534 }
535
536 /*! \brief Give an overview of core settings */
537 static char *handle_show_settings(struct ast_cli_entry *e, int cmd, struct ast_cli_args *a)
538 {
539         char buf[BUFSIZ];
540         struct ast_tm tm;
541         char eid_str[128];
542
543         switch (cmd) {
544         case CLI_INIT:
545                 e->command = "core show settings";
546                 e->usage = "Usage: core show settings\n"
547                            "       Show core misc settings";
548                 return NULL;
549         case CLI_GENERATE:
550                 return NULL;
551         }
552
553         ast_eid_to_str(eid_str, sizeof(eid_str), &ast_eid_default);
554
555         ast_cli(a->fd, "\nPBX Core settings\n");
556         ast_cli(a->fd, "-----------------\n");
557         ast_cli(a->fd, "  Version:                     %s\n", ast_get_version());
558         ast_cli(a->fd, "  Build Options:               %s\n", S_OR(AST_BUILDOPTS, "(none)"));
559         if (option_maxcalls)
560                 ast_cli(a->fd, "  Maximum calls:               %d (Current %d)\n", option_maxcalls, ast_active_channels());
561         else
562                 ast_cli(a->fd, "  Maximum calls:               Not set\n");
563         if (option_maxfiles)
564                 ast_cli(a->fd, "  Maximum open file handles:   %d\n", option_maxfiles);
565         else
566                 ast_cli(a->fd, "  Maximum open file handles:   Not set\n");
567         ast_cli(a->fd, "  Verbosity:                   %d\n", option_verbose);
568         ast_cli(a->fd, "  Debug level:                 %d\n", option_debug);
569         ast_cli(a->fd, "  Maximum load average:        %lf\n", option_maxload);
570 #if defined(HAVE_SYSINFO)
571         ast_cli(a->fd, "  Minimum free memory:         %ld MB\n", option_minmemfree);
572 #endif
573         if (ast_localtime(&ast_startuptime, &tm, NULL)) {
574                 ast_strftime(buf, sizeof(buf), "%H:%M:%S", &tm);
575                 ast_cli(a->fd, "  Startup time:                %s\n", buf);
576         }
577         if (ast_localtime(&ast_lastreloadtime, &tm, NULL)) {
578                 ast_strftime(buf, sizeof(buf), "%H:%M:%S", &tm);
579                 ast_cli(a->fd, "  Last reload time:            %s\n", buf);
580         }
581         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);
582         ast_cli(a->fd, "  System name:                 %s\n", ast_config_AST_SYSTEM_NAME);
583         ast_cli(a->fd, "  Entity ID:                   %s\n", eid_str);
584         ast_cli(a->fd, "  Default language:            %s\n", defaultlanguage);
585         ast_cli(a->fd, "  Language prefix:             %s\n", ast_language_is_prefix ? "Enabled" : "Disabled");
586         ast_cli(a->fd, "  User name and group:         %s/%s\n", ast_config_AST_RUN_USER, ast_config_AST_RUN_GROUP);
587         ast_cli(a->fd, "  Executable includes:         %s\n", ast_test_flag(&ast_options, AST_OPT_FLAG_EXEC_INCLUDES) ? "Enabled" : "Disabled");
588         ast_cli(a->fd, "  Transcode via SLIN:          %s\n", ast_test_flag(&ast_options, AST_OPT_FLAG_TRANSCODE_VIA_SLIN) ? "Enabled" : "Disabled");
589         ast_cli(a->fd, "  Internal timing:             %s\n", ast_test_flag(&ast_options, AST_OPT_FLAG_INTERNAL_TIMING) ? "Enabled" : "Disabled");
590         ast_cli(a->fd, "  Transmit silence during rec: %s\n", ast_test_flag(&ast_options, AST_OPT_FLAG_TRANSMIT_SILENCE) ? "Enabled" : "Disabled");
591         ast_cli(a->fd, "  Generic PLC:                 %s\n", ast_test_flag(&ast_options, AST_OPT_FLAG_GENERIC_PLC) ? "Enabled" : "Disabled");
592         ast_cli(a->fd, "  Min DTMF duration::          %u\n", option_dtmfminduration);
593
594         ast_cli(a->fd, "\n* Subsystems\n");
595         ast_cli(a->fd, "  -------------\n");
596         ast_cli(a->fd, "  Manager (AMI):               %s\n", check_manager_enabled() ? "Enabled" : "Disabled");
597         ast_cli(a->fd, "  Web Manager (AMI/HTTP):      %s\n", check_webmanager_enabled() ? "Enabled" : "Disabled");
598         ast_cli(a->fd, "  Call data records:           %s\n", check_cdr_enabled() ? "Enabled" : "Disabled");
599         ast_cli(a->fd, "  Realtime Architecture (ARA): %s\n", ast_realtime_enabled() ? "Enabled" : "Disabled");
600
601         /*! \todo we could check musiconhold, voicemail, smdi, adsi, queues  */
602
603         ast_cli(a->fd, "\n* Directories\n");
604         ast_cli(a->fd, "  -------------\n");
605         ast_cli(a->fd, "  Configuration file:          %s\n", ast_config_AST_CONFIG_FILE);
606         ast_cli(a->fd, "  Configuration directory:     %s\n", ast_config_AST_CONFIG_DIR);
607         ast_cli(a->fd, "  Module directory:            %s\n", ast_config_AST_MODULE_DIR);
608         ast_cli(a->fd, "  Spool directory:             %s\n", ast_config_AST_SPOOL_DIR);
609         ast_cli(a->fd, "  Log directory:               %s\n", ast_config_AST_LOG_DIR);
610         ast_cli(a->fd, "  Run/Sockets directory:       %s\n", ast_config_AST_RUN_DIR);
611         ast_cli(a->fd, "  PID file:                    %s\n", ast_config_AST_PID);
612         ast_cli(a->fd, "  VarLib directory:            %s\n", ast_config_AST_VAR_DIR);
613         ast_cli(a->fd, "  Data directory:              %s\n", ast_config_AST_DATA_DIR);
614         ast_cli(a->fd, "  ASTDB:                       %s\n", ast_config_AST_DB);
615         ast_cli(a->fd, "  IAX2 Keys directory:         %s\n", ast_config_AST_KEY_DIR);
616         ast_cli(a->fd, "  AGI Scripts directory:       %s\n", ast_config_AST_AGI_DIR);
617         ast_cli(a->fd, "\n\n");
618         return CLI_SUCCESS;
619 }
620
621 static char *handle_show_threads(struct ast_cli_entry *e, int cmd, struct ast_cli_args *a)
622 {
623         int count = 0;
624         struct thread_list_t *cur;
625         switch (cmd) {
626         case CLI_INIT:
627                 e->command = "core show threads";
628                 e->usage =
629                         "Usage: core show threads\n"
630                         "       List threads currently active in the system.\n";
631                 return NULL;
632         case CLI_GENERATE:
633                 return NULL;
634         }
635
636         AST_RWLIST_RDLOCK(&thread_list);
637         AST_RWLIST_TRAVERSE(&thread_list, cur, list) {
638                 ast_cli(a->fd, "%p %d %s\n", (void *)cur->id, cur->lwp, cur->name);
639                 count++;
640         }
641         AST_RWLIST_UNLOCK(&thread_list);
642         ast_cli(a->fd, "%d threads listed.\n", count);
643         return CLI_SUCCESS;
644 }
645
646 #if defined (HAVE_SYSCTL) && defined(HAVE_SWAPCTL)
647 /*
648  * swapmode is rewritten by Tobias Weingartner <weingart@openbsd.org>
649  * to be based on the new swapctl(2) system call.
650  */
651 static int swapmode(int *used, int *total)
652 {
653         struct swapent *swdev;
654         int nswap, rnswap, i;
655
656         nswap = swapctl(SWAP_NSWAP, 0, 0);
657         if (nswap == 0)
658                 return 0;
659
660         swdev = ast_calloc(nswap, sizeof(*swdev));
661         if (swdev == NULL)
662                 return 0;
663
664         rnswap = swapctl(SWAP_STATS, swdev, nswap);
665         if (rnswap == -1) {
666                 ast_free(swdev);
667                 return 0;
668         }
669
670         /* if rnswap != nswap, then what? */
671
672         /* Total things up */
673         *total = *used = 0;
674         for (i = 0; i < nswap; i++) {
675                 if (swdev[i].se_flags & SWF_ENABLE) {
676                         *used += (swdev[i].se_inuse / (1024 / DEV_BSIZE));
677                         *total += (swdev[i].se_nblks / (1024 / DEV_BSIZE));
678                 }
679         }
680         ast_free(swdev);
681         return 1;
682 }
683 #elif defined(HAVE_SYSCTL) && !defined(HAVE_SYSINFO)
684 static int swapmode(int *used, int *total)
685 {
686         *used = *total = 0;
687         return 1;
688 }
689 #endif
690
691 #if defined(HAVE_SYSINFO) || defined(HAVE_SYSCTL)
692 /*! \brief Give an overview of system statistics */
693 static char *handle_show_sysinfo(struct ast_cli_entry *e, int cmd, struct ast_cli_args *a)
694 {
695         uint64_t physmem, freeram;
696         uint64_t freeswap = 0;
697         int nprocs = 0;
698         long uptime = 0;
699         int totalswap = 0;
700 #if defined(HAVE_SYSINFO)
701         struct sysinfo sys_info;
702         sysinfo(&sys_info);
703         uptime = sys_info.uptime / 3600;
704         physmem = sys_info.totalram * sys_info.mem_unit;
705         freeram = (sys_info.freeram * sys_info.mem_unit) / 1024;
706         totalswap = (sys_info.totalswap * sys_info.mem_unit) / 1024;
707         freeswap = (sys_info.freeswap * sys_info.mem_unit) / 1024;
708         nprocs = sys_info.procs;
709 #elif defined(HAVE_SYSCTL)
710         static int pageshift;
711         struct vmtotal vmtotal;
712         struct timeval  boottime;
713         time_t  now;
714         int mib[2], pagesize, usedswap = 0;
715         size_t len;
716         /* calculate the uptime by looking at boottime */
717         time(&now);
718         mib[0] = CTL_KERN;
719         mib[1] = KERN_BOOTTIME;
720         len = sizeof(boottime);
721         if (sysctl(mib, 2, &boottime, &len, NULL, 0) != -1) {
722                 uptime = now - boottime.tv_sec;
723         }
724         uptime = uptime/3600;
725         /* grab total physical memory  */
726         mib[0] = CTL_HW;
727 #if defined(HW_PHYSMEM64)
728         mib[1] = HW_PHYSMEM64;
729 #else
730         mib[1] = HW_PHYSMEM;
731 #endif
732         len = sizeof(physmem);
733         sysctl(mib, 2, &physmem, &len, NULL, 0);
734
735         pagesize = getpagesize();
736         pageshift = 0;
737         while (pagesize > 1) {
738                 pageshift++;
739                 pagesize >>= 1;
740         }
741
742         /* we only need the amount of log(2)1024 for our conversion */
743         pageshift -= 10;
744
745         /* grab vm totals */
746         mib[0] = CTL_VM;
747         mib[1] = VM_METER;
748         len = sizeof(vmtotal);
749         sysctl(mib, 2, &vmtotal, &len, NULL, 0);
750         freeram = (vmtotal.t_free << pageshift);
751         /* generate swap usage and totals */
752         swapmode(&usedswap, &totalswap);
753         freeswap = (totalswap - usedswap);
754         /* grab number of processes */
755 #if defined(__OpenBSD__)
756         mib[0] = CTL_KERN;
757         mib[1] = KERN_NPROCS;
758         len = sizeof(nprocs);
759         sysctl(mib, 2, &nprocs, &len, NULL, 0);
760 #endif
761 #endif
762
763         switch (cmd) {
764         case CLI_INIT:
765                 e->command = "core show sysinfo";
766                 e->usage =
767                         "Usage: core show sysinfo\n"
768                         "       List current system information.\n";
769                 return NULL;
770         case CLI_GENERATE:
771                 return NULL;
772         }
773
774         ast_cli(a->fd, "\nSystem Statistics\n");
775         ast_cli(a->fd, "-----------------\n");
776         ast_cli(a->fd, "  System Uptime:             %lu hours\n", uptime);
777         ast_cli(a->fd, "  Total RAM:                 %" PRIu64 " KiB\n", physmem / 1024);
778         ast_cli(a->fd, "  Free RAM:                  %" PRIu64 " KiB\n", freeram);
779 #if defined(HAVE_SYSINFO)
780         ast_cli(a->fd, "  Buffer RAM:                %" PRIu64 " KiB\n", ((uint64_t) sys_info.bufferram * sys_info.mem_unit) / 1024);
781 #endif
782 #if defined (HAVE_SYSCTL) || defined(HAVE_SWAPCTL)
783         ast_cli(a->fd, "  Total Swap Space:          %u KiB\n", totalswap);
784         ast_cli(a->fd, "  Free Swap Space:           %" PRIu64 " KiB\n\n", freeswap);
785 #endif
786         ast_cli(a->fd, "  Number of Processes:       %d \n\n", nprocs);
787         return CLI_SUCCESS;
788 }
789 #endif
790
791 struct profile_entry {
792         const char *name;
793         uint64_t        scale;  /* if non-zero, values are scaled by this */
794         int64_t mark;
795         int64_t value;
796         int64_t events;
797 };
798
799 struct profile_data {
800         int entries;
801         int max_size;
802         struct profile_entry e[0];
803 };
804
805 static struct profile_data *prof_data;
806
807 /*! \brief allocates a counter with a given name and scale.
808  * \return Returns the identifier of the counter.
809  */
810 int ast_add_profile(const char *name, uint64_t scale)
811 {
812         int l = sizeof(struct profile_data);
813         int n = 10;     /* default entries */
814
815         if (prof_data == NULL) {
816                 prof_data = ast_calloc(1, l + n*sizeof(struct profile_entry));
817                 if (prof_data == NULL)
818                         return -1;
819                 prof_data->entries = 0;
820                 prof_data->max_size = n;
821         }
822         if (prof_data->entries >= prof_data->max_size) {
823                 void *p;
824                 n = prof_data->max_size + 20;
825                 p = ast_realloc(prof_data, l + n*sizeof(struct profile_entry));
826                 if (p == NULL)
827                         return -1;
828                 prof_data = p;
829                 prof_data->max_size = n;
830         }
831         n = prof_data->entries++;
832         prof_data->e[n].name = ast_strdup(name);
833         prof_data->e[n].value = 0;
834         prof_data->e[n].events = 0;
835         prof_data->e[n].mark = 0;
836         prof_data->e[n].scale = scale;
837         return n;
838 }
839
840 int64_t ast_profile(int i, int64_t delta)
841 {
842         if (!prof_data || i < 0 || i > prof_data->entries)      /* invalid index */
843                 return 0;
844         if (prof_data->e[i].scale > 1)
845                 delta /= prof_data->e[i].scale;
846         prof_data->e[i].value += delta;
847         prof_data->e[i].events++;
848         return prof_data->e[i].value;
849 }
850
851 /* The RDTSC instruction was introduced on the Pentium processor and is not
852  * implemented on certain clones, like the Cyrix 586. Hence, the previous
853  * expectation of __i386__ was in error. */
854 #if defined ( __i686__) && (defined(__FreeBSD__) || defined(linux))
855 #if defined(__FreeBSD__)
856 #include <machine/cpufunc.h>
857 #elif defined(linux)
858 static __inline uint64_t
859 rdtsc(void)
860 {
861         uint64_t rv;
862
863         __asm __volatile(".byte 0x0f, 0x31" : "=A" (rv));
864         return (rv);
865 }
866 #endif
867 #else   /* supply a dummy function on other platforms */
868 static __inline uint64_t
869 rdtsc(void)
870 {
871         return 0;
872 }
873 #endif
874
875 int64_t ast_mark(int i, int startstop)
876 {
877         if (!prof_data || i < 0 || i > prof_data->entries) /* invalid index */
878                 return 0;
879         if (startstop == 1)
880                 prof_data->e[i].mark = rdtsc();
881         else {
882                 prof_data->e[i].mark = (rdtsc() - prof_data->e[i].mark);
883                 if (prof_data->e[i].scale > 1)
884                         prof_data->e[i].mark /= prof_data->e[i].scale;
885                 prof_data->e[i].value += prof_data->e[i].mark;
886                 prof_data->e[i].events++;
887         }
888         return prof_data->e[i].mark;
889 }
890
891 #define DEFINE_PROFILE_MIN_MAX_VALUES min = 0; \
892         max = prof_data->entries;\
893         if  (a->argc > 3) { /* specific entries */ \
894                 if (isdigit(a->argv[3][0])) { \
895                         min = atoi(a->argv[3]); \
896                         if (a->argc == 5 && strcmp(a->argv[4], "-")) \
897                                 max = atoi(a->argv[4]); \
898                 } else \
899                         search = a->argv[3]; \
900         } \
901         if (max > prof_data->entries) \
902                 max = prof_data->entries;
903
904 static char *handle_show_profile(struct ast_cli_entry *e, int cmd, struct ast_cli_args *a)
905 {
906         int i, min, max;
907         const char *search = NULL;
908         switch (cmd) {
909         case CLI_INIT:
910                 e->command = "core show profile";
911                 e->usage = "Usage: core show profile\n"
912                            "       show profile information";
913                 return NULL;
914         case CLI_GENERATE:
915                 return NULL;
916         }
917
918         if (prof_data == NULL)
919                 return 0;
920
921         DEFINE_PROFILE_MIN_MAX_VALUES;
922         ast_cli(a->fd, "profile values (%d, allocated %d)\n-------------------\n",
923                 prof_data->entries, prof_data->max_size);
924         ast_cli(a->fd, "%6s   %8s  %10s %12s %12s  %s\n", "ID", "Scale", "Events",
925                         "Value", "Average", "Name");
926         for (i = min; i < max; i++) {
927                 struct profile_entry *entry = &prof_data->e[i];
928                 if (!search || strstr(entry->name, search))
929                     ast_cli(a->fd, "%6d: [%8ld] %10ld %12lld %12lld  %s\n",
930                         i,
931                         (long)entry->scale,
932                         (long)entry->events, (long long)entry->value,
933                         (long long)(entry->events ? entry->value / entry->events : entry->value),
934                         entry->name);
935         }
936         return CLI_SUCCESS;
937 }
938
939 static char *handle_clear_profile(struct ast_cli_entry *e, int cmd, struct ast_cli_args *a)
940 {
941         int i, min, max;
942         const char *search = NULL;
943         switch (cmd) {
944         case CLI_INIT:
945                 e->command = "core clear profile";
946                 e->usage = "Usage: core clear profile\n"
947                            "       clear profile information";
948                 return NULL;
949         case CLI_GENERATE:
950                 return NULL;
951         }
952
953         if (prof_data == NULL)
954                 return 0;
955
956         DEFINE_PROFILE_MIN_MAX_VALUES;
957         for (i= min; i < max; i++) {
958                 if (!search || strstr(prof_data->e[i].name, search)) {
959                         prof_data->e[i].value = 0;
960                         prof_data->e[i].events = 0;
961                 }
962         }
963         return CLI_SUCCESS;
964 }
965 #undef DEFINE_PROFILE_MIN_MAX_VALUES
966
967 /*! \brief CLI command to list module versions */
968 static char *handle_show_version_files(struct ast_cli_entry *e, int cmd, struct ast_cli_args *a)
969 {
970 #define FORMAT "%-25.25s %-40.40s\n"
971         struct file_version *iterator;
972         regex_t regexbuf;
973         int havepattern = 0;
974         int havename = 0;
975         int count_files = 0;
976         char *ret = NULL;
977         int matchlen, which = 0;
978         struct file_version *find;
979
980         switch (cmd) {
981         case CLI_INIT:
982                 e->command = "core show file version [like]";
983                 e->usage =
984                         "Usage: core show file version [like <pattern>]\n"
985                         "       Lists the revision numbers of the files used to build this copy of Asterisk.\n"
986                         "       Optional regular expression pattern is used to filter the file list.\n";
987                 return NULL;
988         case CLI_GENERATE:
989                 matchlen = strlen(a->word);
990                 if (a->pos != 3)
991                         return NULL;
992                 AST_RWLIST_RDLOCK(&file_versions);
993                 AST_RWLIST_TRAVERSE(&file_versions, find, list) {
994                         if (!strncasecmp(a->word, find->file, matchlen) && ++which > a->n) {
995                                 ret = ast_strdup(find->file);
996                                 break;
997                         }
998                 }
999                 AST_RWLIST_UNLOCK(&file_versions);
1000                 return ret;
1001         }
1002
1003
1004         switch (a->argc) {
1005         case 6:
1006                 if (!strcasecmp(a->argv[4], "like")) {
1007                         if (regcomp(&regexbuf, a->argv[5], REG_EXTENDED | REG_NOSUB))
1008                                 return CLI_SHOWUSAGE;
1009                         havepattern = 1;
1010                 } else
1011                         return CLI_SHOWUSAGE;
1012                 break;
1013         case 5:
1014                 havename = 1;
1015                 break;
1016         case 4:
1017                 break;
1018         default:
1019                 return CLI_SHOWUSAGE;
1020         }
1021
1022         ast_cli(a->fd, FORMAT, "File", "Revision");
1023         ast_cli(a->fd, FORMAT, "----", "--------");
1024         AST_RWLIST_RDLOCK(&file_versions);
1025         AST_RWLIST_TRAVERSE(&file_versions, iterator, list) {
1026                 if (havename && strcasecmp(iterator->file, a->argv[4]))
1027                         continue;
1028
1029                 if (havepattern && regexec(&regexbuf, iterator->file, 0, NULL, 0))
1030                         continue;
1031
1032                 ast_cli(a->fd, FORMAT, iterator->file, iterator->version);
1033                 count_files++;
1034                 if (havename)
1035                         break;
1036         }
1037         AST_RWLIST_UNLOCK(&file_versions);
1038         if (!havename) {
1039                 ast_cli(a->fd, "%d files listed.\n", count_files);
1040         }
1041
1042         if (havepattern)
1043                 regfree(&regexbuf);
1044
1045         return CLI_SUCCESS;
1046 #undef FORMAT
1047 }
1048
1049 #endif /* ! LOW_MEMORY */
1050
1051 static void ast_run_atexits(void)
1052 {
1053         struct ast_atexit *ae;
1054
1055         AST_LIST_LOCK(&atexits);
1056         while ((ae = AST_LIST_REMOVE_HEAD(&atexits, list))) {
1057                 if (ae->func) {
1058                         ae->func();
1059                 }
1060                 ast_free(ae);
1061         }
1062         AST_LIST_UNLOCK(&atexits);
1063 }
1064
1065 static void __ast_unregister_atexit(void (*func)(void))
1066 {
1067         struct ast_atexit *ae;
1068
1069         AST_LIST_TRAVERSE_SAFE_BEGIN(&atexits, ae, list) {
1070                 if (ae->func == func) {
1071                         AST_LIST_REMOVE_CURRENT(list);
1072                         ast_free(ae);
1073                         break;
1074                 }
1075         }
1076         AST_LIST_TRAVERSE_SAFE_END;
1077 }
1078
1079 int ast_register_atexit(void (*func)(void))
1080 {
1081         struct ast_atexit *ae;
1082
1083         ae = ast_calloc(1, sizeof(*ae));
1084         if (!ae) {
1085                 return -1;
1086         }
1087         ae->func = func;
1088
1089         AST_LIST_LOCK(&atexits);
1090         __ast_unregister_atexit(func);
1091         AST_LIST_INSERT_HEAD(&atexits, ae, list);
1092         AST_LIST_UNLOCK(&atexits);
1093
1094         return 0;
1095 }
1096
1097 void ast_unregister_atexit(void (*func)(void))
1098 {
1099         AST_LIST_LOCK(&atexits);
1100         __ast_unregister_atexit(func);
1101         AST_LIST_UNLOCK(&atexits);
1102 }
1103
1104 /* Sending commands from consoles back to the daemon requires a terminating NULL */
1105 static int fdsend(int fd, const char *s)
1106 {
1107         return write(fd, s, strlen(s) + 1);
1108 }
1109
1110 /* Sending messages from the daemon back to the display requires _excluding_ the terminating NULL */
1111 static int fdprint(int fd, const char *s)
1112 {
1113         return write(fd, s, strlen(s));
1114 }
1115
1116 /*! \brief NULL handler so we can collect the child exit status */
1117 static void _null_sig_handler(int sig)
1118 {
1119 }
1120
1121 static struct sigaction null_sig_handler = {
1122         .sa_handler = _null_sig_handler,
1123         .sa_flags = SA_RESTART,
1124 };
1125
1126 static struct sigaction ignore_sig_handler = {
1127         .sa_handler = SIG_IGN,
1128 };
1129
1130 AST_MUTEX_DEFINE_STATIC(safe_system_lock);
1131 /*! \brief Keep track of how many threads are currently trying to wait*() on
1132  *  a child process
1133  */
1134 static unsigned int safe_system_level = 0;
1135 static struct sigaction safe_system_prev_handler;
1136
1137 void ast_replace_sigchld(void)
1138 {
1139         unsigned int level;
1140
1141         ast_mutex_lock(&safe_system_lock);
1142         level = safe_system_level++;
1143
1144         /* only replace the handler if it has not already been done */
1145         if (level == 0) {
1146                 sigaction(SIGCHLD, &null_sig_handler, &safe_system_prev_handler);
1147         }
1148
1149         ast_mutex_unlock(&safe_system_lock);
1150 }
1151
1152 void ast_unreplace_sigchld(void)
1153 {
1154         unsigned int level;
1155
1156         ast_mutex_lock(&safe_system_lock);
1157         level = --safe_system_level;
1158
1159         /* only restore the handler if we are the last one */
1160         if (level == 0) {
1161                 sigaction(SIGCHLD, &safe_system_prev_handler, NULL);
1162         }
1163
1164         ast_mutex_unlock(&safe_system_lock);
1165 }
1166
1167 int ast_safe_system(const char *s)
1168 {
1169         pid_t pid;
1170         int res;
1171         struct rusage rusage;
1172         int status;
1173
1174 #if defined(HAVE_WORKING_FORK) || defined(HAVE_WORKING_VFORK)
1175         ast_replace_sigchld();
1176
1177 #ifdef HAVE_WORKING_FORK
1178         pid = fork();
1179 #else
1180         pid = vfork();
1181 #endif
1182
1183         if (pid == 0) {
1184 #ifdef HAVE_CAP
1185                 cap_t cap = cap_from_text("cap_net_admin-eip");
1186
1187                 if (cap_set_proc(cap)) {
1188                         /* Careful with order! Logging cannot happen after we close FDs */
1189                         ast_log(LOG_WARNING, "Unable to remove capabilities.\n");
1190                 }
1191                 cap_free(cap);
1192 #endif
1193 #ifdef HAVE_WORKING_FORK
1194                 if (ast_opt_high_priority)
1195                         ast_set_priority(0);
1196                 /* Close file descriptors and launch system command */
1197                 ast_close_fds_above_n(STDERR_FILENO);
1198 #endif
1199                 execl("/bin/sh", "/bin/sh", "-c", s, (char *) NULL);
1200                 _exit(1);
1201         } else if (pid > 0) {
1202                 for (;;) {
1203                         res = wait4(pid, &status, 0, &rusage);
1204                         if (res > -1) {
1205                                 res = WIFEXITED(status) ? WEXITSTATUS(status) : -1;
1206                                 break;
1207                         } else if (errno != EINTR)
1208                                 break;
1209                 }
1210         } else {
1211                 ast_log(LOG_WARNING, "Fork failed: %s\n", strerror(errno));
1212                 res = -1;
1213         }
1214
1215         ast_unreplace_sigchld();
1216 #else /* !defined(HAVE_WORKING_FORK) && !defined(HAVE_WORKING_VFORK) */
1217         res = -1;
1218 #endif
1219
1220         return res;
1221 }
1222
1223 /*!
1224  * \brief enable or disable a logging level to a specified console
1225  */
1226 void ast_console_toggle_loglevel(int fd, int level, int state)
1227 {
1228         int x;
1229
1230         if (level >= NUMLOGLEVELS) {
1231                 level = NUMLOGLEVELS - 1;
1232         }
1233
1234         for (x = 0;x < AST_MAX_CONNECTS; x++) {
1235                 if (fd == consoles[x].fd) {
1236                         /*
1237                          * Since the logging occurs when levels are false, set to
1238                          * flipped iinput because this function accepts 0 as off and 1 as on
1239                          */
1240                         consoles[x].levels[level] = state ? 0 : 1;
1241                         return;
1242                 }
1243         }
1244 }
1245
1246 /*!
1247  * \brief mute or unmute a console from logging
1248  */
1249 void ast_console_toggle_mute(int fd, int silent)
1250 {
1251         int x;
1252         for (x = 0;x < AST_MAX_CONNECTS; x++) {
1253                 if (fd == consoles[x].fd) {
1254                         if (consoles[x].mute) {
1255                                 consoles[x].mute = 0;
1256                                 if (!silent)
1257                                         ast_cli(fd, "Console is not muted anymore.\n");
1258                         } else {
1259                                 consoles[x].mute = 1;
1260                                 if (!silent)
1261                                         ast_cli(fd, "Console is muted.\n");
1262                         }
1263                         return;
1264                 }
1265         }
1266         ast_cli(fd, "Couldn't find remote console.\n");
1267 }
1268
1269 /*!
1270  * \brief log the string to all attached console clients
1271  */
1272 static void ast_network_puts_mutable(const char *string, int level)
1273 {
1274         int x;
1275         for (x = 0;x < AST_MAX_CONNECTS; x++) {
1276                 if (consoles[x].mute)
1277                         continue;
1278                 if (consoles[x].fd > -1) {
1279                         if (!consoles[x].levels[level])
1280                                 fdprint(consoles[x].p[1], string);
1281                 }
1282         }
1283 }
1284
1285 /*!
1286  * \brief log the string to the console, and all attached
1287  * console clients
1288  */
1289 void ast_console_puts_mutable(const char *string, int level)
1290 {
1291         fputs(string, stdout);
1292         fflush(stdout);
1293         ast_network_puts_mutable(string, level);
1294 }
1295
1296 /*!
1297  * \brief write the string to all attached console clients
1298  */
1299 static void ast_network_puts(const char *string)
1300 {
1301         int x;
1302         for (x = 0; x < AST_MAX_CONNECTS; x++) {
1303                 if (consoles[x].fd > -1)
1304                         fdprint(consoles[x].p[1], string);
1305         }
1306 }
1307
1308 /*!
1309  * \brief write the string to the console, and all attached
1310  * console clients
1311  */
1312 void ast_console_puts(const char *string)
1313 {
1314         fputs(string, stdout);
1315         fflush(stdout);
1316         ast_network_puts(string);
1317 }
1318
1319 static void network_verboser(const char *s)
1320 {
1321         ast_network_puts_mutable(s, __LOG_VERBOSE);
1322 }
1323
1324 static pthread_t lthread;
1325
1326 /*!
1327  * \brief read() function supporting the reception of user credentials.
1328  *
1329  * \param fd Socket file descriptor.
1330  * \param buffer Receive buffer.
1331  * \param size 'buffer' size.
1332  * \param con Console structure to set received credentials
1333  * \retval -1 on error
1334  * \retval the number of bytes received on success.
1335  */
1336 static int read_credentials(int fd, char *buffer, size_t size, struct console *con)
1337 {
1338 #if defined(SO_PEERCRED)
1339 #ifdef HAVE_STRUCT_SOCKPEERCRED_UID
1340 #define HAVE_STRUCT_UCRED_UID
1341         struct sockpeercred cred;
1342 #else
1343         struct ucred cred;
1344 #endif
1345         socklen_t len = sizeof(cred);
1346 #endif
1347 #if defined(HAVE_GETPEEREID)
1348         uid_t uid;
1349         gid_t gid;
1350 #else
1351         int uid, gid;
1352 #endif
1353         int result;
1354
1355         result = read(fd, buffer, size);
1356         if (result < 0) {
1357                 return result;
1358         }
1359
1360 #if defined(SO_PEERCRED) && (defined(HAVE_STRUCT_UCRED_UID) || defined(HAVE_STRUCT_UCRED_CR_UID))
1361         if (getsockopt(fd, SOL_SOCKET, SO_PEERCRED, &cred, &len)) {
1362                 return result;
1363         }
1364 #if defined(HAVE_STRUCT_UCRED_UID)
1365         uid = cred.uid;
1366         gid = cred.gid;
1367 #else /* defined(HAVE_STRUCT_UCRED_CR_UID) */
1368         uid = cred.cr_uid;
1369         gid = cred.cr_gid;
1370 #endif /* defined(HAVE_STRUCT_UCRED_UID) */
1371
1372 #elif defined(HAVE_GETPEEREID)
1373         if (getpeereid(fd, &uid, &gid)) {
1374                 return result;
1375         }
1376 #else
1377         return result;
1378 #endif
1379         con->uid = uid;
1380         con->gid = gid;
1381
1382         return result;
1383 }
1384
1385 static void *netconsole(void *vconsole)
1386 {
1387         struct console *con = vconsole;
1388         char hostname[MAXHOSTNAMELEN] = "";
1389         char inbuf[512];
1390         char outbuf[512];
1391         const char * const end_buf = inbuf + sizeof(inbuf);
1392         char *start_read = inbuf;
1393         int res;
1394         struct pollfd fds[2];
1395
1396         if (gethostname(hostname, sizeof(hostname)-1))
1397                 ast_copy_string(hostname, "<Unknown>", sizeof(hostname));
1398         snprintf(outbuf, sizeof(outbuf), "%s/%ld/%s\n", hostname, (long)ast_mainpid, ast_get_version());
1399         fdprint(con->fd, outbuf);
1400         for (;;) {
1401                 fds[0].fd = con->fd;
1402                 fds[0].events = POLLIN;
1403                 fds[0].revents = 0;
1404                 fds[1].fd = con->p[0];
1405                 fds[1].events = POLLIN;
1406                 fds[1].revents = 0;
1407
1408                 res = ast_poll(fds, 2, -1);
1409                 if (res < 0) {
1410                         if (errno != EINTR)
1411                                 ast_log(LOG_WARNING, "poll returned < 0: %s\n", strerror(errno));
1412                         continue;
1413                 }
1414                 if (fds[0].revents) {
1415                         int cmds_read, bytes_read;
1416                         if ((bytes_read = read_credentials(con->fd, start_read, end_buf - start_read, con)) < 1) {
1417                                 break;
1418                         }
1419                         /* XXX This will only work if it is the first command, and I'm not sure fixing it is worth the effort. */
1420                         if (strncmp(inbuf, "cli quit after ", 15) == 0) {
1421                                 ast_cli_command_multiple_full(con->uid, con->gid, con->fd, bytes_read - 15, inbuf + 15);
1422                                 break;
1423                         }
1424                         /* ast_cli_command_multiple_full will only process individual commands terminated by a
1425                          * NULL and not trailing partial commands. */
1426                         if (!(cmds_read = ast_cli_command_multiple_full(con->uid, con->gid, con->fd, bytes_read + start_read - inbuf, inbuf))) {
1427                                 /* No commands were read. We either have a short read on the first command
1428                                  * with space left, or a command that is too long */
1429                                 if (start_read + bytes_read < end_buf) {
1430                                         start_read += bytes_read;
1431                                 } else {
1432                                         ast_log(LOG_ERROR, "Command too long! Skipping\n");
1433                                         start_read = inbuf;
1434                                 }
1435                                 continue;
1436                         }
1437                         if (start_read[bytes_read - 1] == '\0') {
1438                                 /* The read ended on a command boundary, start reading again at the head of inbuf */
1439                                 start_read = inbuf;
1440                                 continue;
1441                         }
1442                         /* If we get this far, we have left over characters that have not been processed.
1443                          * Advance to the character after the last command read by ast_cli_command_multiple_full.
1444                          * We are guaranteed to have at least cmds_read NULLs */
1445                         while (cmds_read-- && (start_read = strchr(start_read, '\0'))) {
1446                                 start_read++;
1447                         }
1448                         memmove(inbuf, start_read, end_buf - start_read);
1449                         start_read = end_buf - start_read + inbuf;
1450                 }
1451                 if (fds[1].revents) {
1452                         res = read_credentials(con->p[0], outbuf, sizeof(outbuf), con);
1453                         if (res < 1) {
1454                                 ast_log(LOG_ERROR, "read returned %d\n", res);
1455                                 break;
1456                         }
1457                         res = write(con->fd, outbuf, res);
1458                         if (res < 1)
1459                                 break;
1460                 }
1461         }
1462         if (!ast_opt_hide_connect) {
1463                 ast_verb(3, "Remote UNIX connection disconnected\n");
1464         }
1465         close(con->fd);
1466         close(con->p[0]);
1467         close(con->p[1]);
1468         con->fd = -1;
1469
1470         return NULL;
1471 }
1472
1473 static void *listener(void *unused)
1474 {
1475         struct sockaddr_un sunaddr;
1476         int s;
1477         socklen_t len;
1478         int x;
1479         int flags;
1480         struct pollfd fds[1];
1481         for (;;) {
1482                 if (ast_socket < 0)
1483                         return NULL;
1484                 fds[0].fd = ast_socket;
1485                 fds[0].events = POLLIN;
1486                 s = ast_poll(fds, 1, -1);
1487                 pthread_testcancel();
1488                 if (s < 0) {
1489                         if (errno != EINTR)
1490                                 ast_log(LOG_WARNING, "poll returned error: %s\n", strerror(errno));
1491                         continue;
1492                 }
1493                 len = sizeof(sunaddr);
1494                 s = accept(ast_socket, (struct sockaddr *)&sunaddr, &len);
1495                 if (s < 0) {
1496                         if (errno != EINTR)
1497                                 ast_log(LOG_WARNING, "Accept returned %d: %s\n", s, strerror(errno));
1498                 } else {
1499 #if !defined(SO_PASSCRED)
1500                         {
1501 #else
1502                         int sckopt = 1;
1503                         /* turn on socket credentials passing. */
1504                         if (setsockopt(s, SOL_SOCKET, SO_PASSCRED, &sckopt, sizeof(sckopt)) < 0) {
1505                                 ast_log(LOG_WARNING, "Unable to turn on socket credentials passing\n");
1506                         } else {
1507 #endif
1508                                 for (x = 0; x < AST_MAX_CONNECTS; x++) {
1509                                         if (consoles[x].fd >= 0) {
1510                                                 continue;
1511                                         }
1512                                         if (socketpair(AF_LOCAL, SOCK_STREAM, 0, consoles[x].p)) {
1513                                                 ast_log(LOG_ERROR, "Unable to create pipe: %s\n", strerror(errno));
1514                                                 consoles[x].fd = -1;
1515                                                 fdprint(s, "Server failed to create pipe\n");
1516                                                 close(s);
1517                                                 break;
1518                                         }
1519                                         flags = fcntl(consoles[x].p[1], F_GETFL);
1520                                         fcntl(consoles[x].p[1], F_SETFL, flags | O_NONBLOCK);
1521                                         consoles[x].fd = s;
1522                                         consoles[x].mute = 1; /* Default is muted, we will un-mute if necessary */
1523                                         /* Default uid and gid to -2, so then in cli.c/cli_has_permissions() we will be able
1524                                            to know if the user didn't send the credentials. */
1525                                         consoles[x].uid = -2;
1526                                         consoles[x].gid = -2;
1527                                         if (ast_pthread_create_detached_background(&consoles[x].t, NULL, netconsole, &consoles[x])) {
1528                                                 ast_log(LOG_ERROR, "Unable to spawn thread to handle connection: %s\n", strerror(errno));
1529                                                 close(consoles[x].p[0]);
1530                                                 close(consoles[x].p[1]);
1531                                                 consoles[x].fd = -1;
1532                                                 fdprint(s, "Server failed to spawn thread\n");
1533                                                 close(s);
1534                                         }
1535                                         break;
1536                                 }
1537                                 if (x >= AST_MAX_CONNECTS) {
1538                                         fdprint(s, "No more connections allowed\n");
1539                                         ast_log(LOG_WARNING, "No more connections allowed\n");
1540                                         close(s);
1541                                 } else if ((consoles[x].fd > -1) && (!ast_opt_hide_connect)) {
1542                                         ast_verb(3, "Remote UNIX connection\n");
1543                                 }
1544                         }
1545                 }
1546         }
1547         return NULL;
1548 }
1549
1550 static int ast_makesocket(void)
1551 {
1552         struct sockaddr_un sunaddr;
1553         int res;
1554         int x;
1555         uid_t uid = -1;
1556         gid_t gid = -1;
1557
1558         for (x = 0; x < AST_MAX_CONNECTS; x++)
1559                 consoles[x].fd = -1;
1560         unlink(ast_config_AST_SOCKET);
1561         ast_socket = socket(PF_LOCAL, SOCK_STREAM, 0);
1562         if (ast_socket < 0) {
1563                 ast_log(LOG_WARNING, "Unable to create control socket: %s\n", strerror(errno));
1564                 return -1;
1565         }
1566         memset(&sunaddr, 0, sizeof(sunaddr));
1567         sunaddr.sun_family = AF_LOCAL;
1568         ast_copy_string(sunaddr.sun_path, ast_config_AST_SOCKET, sizeof(sunaddr.sun_path));
1569         res = bind(ast_socket, (struct sockaddr *)&sunaddr, sizeof(sunaddr));
1570         if (res) {
1571                 ast_log(LOG_WARNING, "Unable to bind socket to %s: %s\n", ast_config_AST_SOCKET, strerror(errno));
1572                 close(ast_socket);
1573                 ast_socket = -1;
1574                 return -1;
1575         }
1576         res = listen(ast_socket, 2);
1577         if (res < 0) {
1578                 ast_log(LOG_WARNING, "Unable to listen on socket %s: %s\n", ast_config_AST_SOCKET, strerror(errno));
1579                 close(ast_socket);
1580                 ast_socket = -1;
1581                 return -1;
1582         }
1583         if (ast_register_verbose(network_verboser)) {
1584                 ast_log(LOG_WARNING, "Unable to register network verboser?\n");
1585         }
1586
1587         if (ast_pthread_create_background(&lthread, NULL, listener, NULL)) {
1588                 ast_log(LOG_WARNING, "Unable to create listener thread.\n");
1589                 close(ast_socket);
1590                 return -1;
1591         }
1592
1593         if (!ast_strlen_zero(ast_config_AST_CTL_OWNER)) {
1594                 struct passwd *pw;
1595                 if ((pw = getpwnam(ast_config_AST_CTL_OWNER)) == NULL)
1596                         ast_log(LOG_WARNING, "Unable to find uid of user %s\n", ast_config_AST_CTL_OWNER);
1597                 else
1598                         uid = pw->pw_uid;
1599         }
1600
1601         if (!ast_strlen_zero(ast_config_AST_CTL_GROUP)) {
1602                 struct group *grp;
1603                 if ((grp = getgrnam(ast_config_AST_CTL_GROUP)) == NULL)
1604                         ast_log(LOG_WARNING, "Unable to find gid of group %s\n", ast_config_AST_CTL_GROUP);
1605                 else
1606                         gid = grp->gr_gid;
1607         }
1608
1609         if (chown(ast_config_AST_SOCKET, uid, gid) < 0)
1610                 ast_log(LOG_WARNING, "Unable to change ownership of %s: %s\n", ast_config_AST_SOCKET, strerror(errno));
1611
1612         if (!ast_strlen_zero(ast_config_AST_CTL_PERMISSIONS)) {
1613                 int p1;
1614                 mode_t p;
1615                 sscanf(ast_config_AST_CTL_PERMISSIONS, "%30o", &p1);
1616                 p = p1;
1617                 if ((chmod(ast_config_AST_SOCKET, p)) < 0)
1618                         ast_log(LOG_WARNING, "Unable to change file permissions of %s: %s\n", ast_config_AST_SOCKET, strerror(errno));
1619         }
1620
1621         return 0;
1622 }
1623
1624 static int ast_tryconnect(void)
1625 {
1626         struct sockaddr_un sunaddr;
1627         int res;
1628         ast_consock = socket(PF_LOCAL, SOCK_STREAM, 0);
1629         if (ast_consock < 0) {
1630                 fprintf(stderr, "Unable to create socket: %s\n", strerror(errno));
1631                 return 0;
1632         }
1633         memset(&sunaddr, 0, sizeof(sunaddr));
1634         sunaddr.sun_family = AF_LOCAL;
1635         ast_copy_string(sunaddr.sun_path, ast_config_AST_SOCKET, sizeof(sunaddr.sun_path));
1636         res = connect(ast_consock, (struct sockaddr *)&sunaddr, sizeof(sunaddr));
1637         if (res) {
1638                 close(ast_consock);
1639                 ast_consock = -1;
1640                 return 0;
1641         } else
1642                 return 1;
1643 }
1644
1645 /*! \brief Urgent handler
1646  *
1647  * Called by soft_hangup to interrupt the poll, read, or other
1648  * system call.  We don't actually need to do anything though.
1649  * Remember: Cannot EVER ast_log from within a signal handler
1650  */
1651 static void _urg_handler(int num)
1652 {
1653         return;
1654 }
1655
1656 static struct sigaction urg_handler = {
1657         .sa_handler = _urg_handler,
1658         .sa_flags = SA_RESTART,
1659 };
1660
1661 static void _hup_handler(int num)
1662 {
1663         int a = 0, save_errno = errno;
1664         printf("Received HUP signal -- Reloading configs\n");
1665         if (restartnow)
1666                 execvp(_argv[0], _argv);
1667         sig_flags.need_reload = 1;
1668         if (sig_alert_pipe[1] != -1) {
1669                 if (write(sig_alert_pipe[1], &a, sizeof(a)) < 0) {
1670                         fprintf(stderr, "hup_handler: write() failed: %s\n", strerror(errno));
1671                 }
1672         }
1673         errno = save_errno;
1674 }
1675
1676 static struct sigaction hup_handler = {
1677         .sa_handler = _hup_handler,
1678         .sa_flags = SA_RESTART,
1679 };
1680
1681 static void _child_handler(int sig)
1682 {
1683         /* Must not ever ast_log or ast_verbose within signal handler */
1684         int n, status, save_errno = errno;
1685
1686         /*
1687          * Reap all dead children -- not just one
1688          */
1689         for (n = 0; wait4(-1, &status, WNOHANG, NULL) > 0; n++)
1690                 ;
1691         if (n == 0 && option_debug)
1692                 printf("Huh?  Child handler, but nobody there?\n");
1693         errno = save_errno;
1694 }
1695
1696 static struct sigaction child_handler = {
1697         .sa_handler = _child_handler,
1698         .sa_flags = SA_RESTART,
1699 };
1700
1701 /*! \brief Set maximum open files */
1702 static void set_ulimit(int value)
1703 {
1704         struct rlimit l = {0, 0};
1705
1706         if (value <= 0) {
1707                 ast_log(LOG_WARNING, "Unable to change max files open to invalid value %i\n",value);
1708                 return;
1709         }
1710
1711         l.rlim_cur = value;
1712         l.rlim_max = value;
1713
1714         if (setrlimit(RLIMIT_NOFILE, &l)) {
1715                 ast_log(LOG_WARNING, "Unable to disable core size resource limit: %s\n",strerror(errno));
1716                 return;
1717         }
1718
1719         ast_log(LOG_NOTICE, "Setting max files open to %d\n",value);
1720
1721         return;
1722 }
1723
1724 /*! \brief Set an X-term or screen title */
1725 static void set_title(char *text)
1726 {
1727         if (getenv("TERM") && strstr(getenv("TERM"), "xterm"))
1728                 fprintf(stdout, "\033]2;%s\007", text);
1729 }
1730
1731 static void set_icon(char *text)
1732 {
1733         if (getenv("TERM") && strstr(getenv("TERM"), "xterm"))
1734                 fprintf(stdout, "\033]1;%s\007", text);
1735 }
1736
1737 /*! \brief We set ourselves to a high priority, that we might pre-empt
1738  * everything else.  If your PBX has heavy activity on it, this is a
1739  * good thing.
1740  */
1741 int ast_set_priority(int pri)
1742 {
1743         struct sched_param sched;
1744         memset(&sched, 0, sizeof(sched));
1745 #ifdef __linux__
1746         if (pri) {
1747                 sched.sched_priority = 10;
1748                 if (sched_setscheduler(0, SCHED_RR, &sched)) {
1749                         ast_log(LOG_WARNING, "Unable to set high priority\n");
1750                         return -1;
1751                 } else
1752                         ast_verb(1, "Set to realtime thread\n");
1753         } else {
1754                 sched.sched_priority = 0;
1755                 /* According to the manpage, these parameters can never fail. */
1756                 sched_setscheduler(0, SCHED_OTHER, &sched);
1757         }
1758 #else
1759         if (pri) {
1760                 if (setpriority(PRIO_PROCESS, 0, -10) == -1) {
1761                         ast_log(LOG_WARNING, "Unable to set high priority\n");
1762                         return -1;
1763                 } else
1764                         ast_verb(1, "Set to high priority\n");
1765         } else {
1766                 /* According to the manpage, these parameters can never fail. */
1767                 setpriority(PRIO_PROCESS, 0, 0);
1768         }
1769 #endif
1770         return 0;
1771 }
1772
1773 static int can_safely_quit(shutdown_nice_t niceness, int restart);
1774 static void really_quit(int num, shutdown_nice_t niceness, int restart);
1775
1776 static void quit_handler(int num, shutdown_nice_t niceness, int restart)
1777 {
1778         if (can_safely_quit(niceness, restart)) {
1779                 really_quit(num, niceness, restart);
1780                 /* No one gets here. */
1781         }
1782         /* It wasn't our time. */
1783 }
1784
1785 static int can_safely_quit(shutdown_nice_t niceness, int restart)
1786 {
1787         /* Check if someone else isn't already doing this. */
1788         ast_mutex_lock(&safe_system_lock);
1789         if (shuttingdown != NOT_SHUTTING_DOWN && niceness >= shuttingdown) {
1790                 /* Already in progress and other request was less nice. */
1791                 ast_mutex_unlock(&safe_system_lock);
1792                 ast_verbose("Ignoring asterisk %s request, already in progress.\n", restart ? "restart" : "shutdown");
1793                 return 0;
1794         }
1795         shuttingdown = niceness;
1796         ast_mutex_unlock(&safe_system_lock);
1797
1798         /* Try to get as many CDRs as possible submitted to the backend engines
1799          * (if in batch mode). really_quit happens to call it again when running
1800          * the atexit handlers, otherwise this would be a bit early. */
1801         ast_cdr_engine_term();
1802
1803         /* Shutdown the message queue for the technology agnostic message channel.
1804          * This has to occur before we pause shutdown pending ast_undestroyed_channels. */
1805         ast_msg_shutdown();
1806
1807         if (niceness == SHUTDOWN_NORMAL) {
1808                 time_t s, e;
1809                 /* Begin shutdown routine, hanging up active channels */
1810                 ast_begin_shutdown(1);
1811                 if (option_verbose && ast_opt_console) {
1812                         ast_verbose("Beginning asterisk %s....\n", restart ? "restart" : "shutdown");
1813                 }
1814                 time(&s);
1815                 for (;;) {
1816                         time(&e);
1817                         /* Wait up to 15 seconds for all channels to go away */
1818                         if ((e - s) > 15 || !ast_undestroyed_channels() || shuttingdown != niceness) {
1819                                 break;
1820                         }
1821                         /* Sleep 1/10 of a second */
1822                         usleep(100000);
1823                 }
1824         } else if (niceness >= SHUTDOWN_NICE) {
1825                 if (niceness != SHUTDOWN_REALLY_NICE) {
1826                         ast_begin_shutdown(0);
1827                 }
1828                 if (option_verbose && ast_opt_console) {
1829                         ast_verb(0, "Waiting for inactivity to perform %s...\n", restart ? "restart" : "halt");
1830                 }
1831                 for (;;) {
1832                         if (!ast_undestroyed_channels() || shuttingdown != niceness) {
1833                                 break;
1834                         }
1835                         sleep(1);
1836                 }
1837         }
1838
1839         /* Re-acquire lock and check if someone changed the niceness, in which
1840          * case someone else has taken over the shutdown.
1841          */
1842         ast_mutex_lock(&safe_system_lock);
1843         if (shuttingdown != niceness) {
1844                 if (shuttingdown == NOT_SHUTTING_DOWN && option_verbose && ast_opt_console) {
1845                         ast_verb(0, "Asterisk %s cancelled.\n", restart ? "restart" : "shutdown");
1846                 }
1847                 ast_mutex_unlock(&safe_system_lock);
1848                 return 0;
1849         }
1850         shuttingdown = SHUTTING_DOWN;
1851         ast_mutex_unlock(&safe_system_lock);
1852
1853         return 1;
1854 }
1855
1856 /*! Called when exiting is certain. */
1857 static void really_quit(int num, shutdown_nice_t niceness, int restart)
1858 {
1859         int active_channels;
1860
1861         if (niceness >= SHUTDOWN_NICE) {
1862                 ast_module_shutdown();
1863         }
1864
1865         if (ast_opt_console || (ast_opt_remote && !ast_opt_exec)) {
1866                 char filename[80] = "";
1867                 if (getenv("HOME")) {
1868                         snprintf(filename, sizeof(filename), "%s/.asterisk_history", getenv("HOME"));
1869                 }
1870                 if (!ast_strlen_zero(filename)) {
1871                         ast_el_write_history(filename);
1872                 }
1873                 if (consolethread == AST_PTHREADT_NULL || consolethread == pthread_self()) {
1874                         /* Only end if we are the consolethread, otherwise there's a race with that thread. */
1875                         if (el != NULL) {
1876                                 el_end(el);
1877                         }
1878                         if (el_hist != NULL) {
1879                                 history_end(el_hist);
1880                         }
1881                 } else if (mon_sig_flags == pthread_self()) {
1882                         if (consolethread != AST_PTHREADT_NULL) {
1883                                 pthread_kill(consolethread, SIGURG);
1884                         }
1885                 }
1886         }
1887         active_channels = ast_active_channels();
1888         /* The manager event for shutdown must happen prior to ast_run_atexits, as
1889          * the manager interface will dispose of its sessions as part of its
1890          * shutdown.
1891          */
1892         /*** DOCUMENTATION
1893                 <managerEventInstance>
1894                         <synopsis>Raised when Asterisk is shutdown or restarted.</synopsis>
1895                         <syntax>
1896                                 <parameter name="Shutdown">
1897                                         <enumlist>
1898                                                 <enum name="Uncleanly"/>
1899                                                 <enum name="Cleanly"/>
1900                                         </enumlist>
1901                                 </parameter>
1902                                 <parameter name="Restart">
1903                                         <enumlist>
1904                                                 <enum name="True"/>
1905                                                 <enum name="False"/>
1906                                         </enumlist>
1907                                 </parameter>
1908                         </syntax>
1909                 </managerEventInstance>
1910         ***/
1911         manager_event(EVENT_FLAG_SYSTEM, "Shutdown", "Shutdown: %s\r\n"
1912                 "Restart: %s\r\n",
1913                 active_channels ? "Uncleanly" : "Cleanly",
1914                 restart ? "True" : "False");
1915         ast_verb(0, "Asterisk %s ending (%d).\n",
1916                 active_channels ? "uncleanly" : "cleanly", num);
1917
1918         ast_verb(0, "Executing last minute cleanups\n");
1919         ast_run_atexits();
1920
1921         ast_debug(1, "Asterisk ending (%d).\n", num);
1922         if (ast_socket > -1) {
1923                 pthread_cancel(lthread);
1924                 close(ast_socket);
1925                 ast_socket = -1;
1926                 unlink(ast_config_AST_SOCKET);
1927         }
1928         if (ast_consock > -1)
1929                 close(ast_consock);
1930         if (!ast_opt_remote)
1931                 unlink(ast_config_AST_PID);
1932         printf("%s", term_quit());
1933         if (restart) {
1934                 int i;
1935                 ast_verb(0, "Preparing for Asterisk restart...\n");
1936                 /* Mark all FD's for closing on exec */
1937                 for (i = 3; i < 32768; i++) {
1938                         fcntl(i, F_SETFD, FD_CLOEXEC);
1939                 }
1940                 ast_verb(0, "Asterisk is now restarting...\n");
1941                 restartnow = 1;
1942
1943                 /* close logger */
1944                 close_logger();
1945                 clean_time_zones();
1946
1947                 /* If there is a consolethread running send it a SIGHUP
1948                    so it can execvp, otherwise we can do it ourselves */
1949                 if ((consolethread != AST_PTHREADT_NULL) && (consolethread != pthread_self())) {
1950                         pthread_kill(consolethread, SIGHUP);
1951                         /* Give the signal handler some time to complete */
1952                         sleep(2);
1953                 } else
1954                         execvp(_argv[0], _argv);
1955
1956         } else {
1957                 /* close logger */
1958                 close_logger();
1959                 clean_time_zones();
1960         }
1961
1962         exit(0);
1963 }
1964
1965 static void __quit_handler(int num)
1966 {
1967         int a = 0;
1968         sig_flags.need_quit = 1;
1969         if (sig_alert_pipe[1] != -1) {
1970                 if (write(sig_alert_pipe[1], &a, sizeof(a)) < 0) {
1971                         fprintf(stderr, "quit_handler: write() failed: %s\n", strerror(errno));
1972                 }
1973         }
1974         /* There is no need to restore the signal handler here, since the app
1975          * is going to exit */
1976 }
1977
1978 static void __remote_quit_handler(int num)
1979 {
1980         sig_flags.need_quit = 1;
1981 }
1982
1983 static const char *fix_header(char *outbuf, int maxout, const char *s, char *cmp)
1984 {
1985         const char *c;
1986
1987         if (!strncmp(s, cmp, strlen(cmp))) {
1988                 c = s + strlen(cmp);
1989                 term_color(outbuf, cmp, COLOR_GRAY, 0, maxout);
1990                 return c;
1991         }
1992         return NULL;
1993 }
1994
1995 /* These gymnastics are due to platforms which designate char as unsigned by
1996  * default. Level is the negative character -- offset by 1, because \0 is the
1997  * EOS delimiter. */
1998 #define VERBOSE_MAGIC2LEVEL(x) (((char) -*(signed char *) (x)) - 1)
1999 #define VERBOSE_HASMAGIC(x)     (*(signed char *) (x) < 0)
2000
2001 static void console_verboser(const char *s)
2002 {
2003         char tmp[80];
2004         const char *c = NULL;
2005         char level = 0;
2006
2007         if (VERBOSE_HASMAGIC(s)) {
2008                 level = VERBOSE_MAGIC2LEVEL(s);
2009                 s++;
2010                 if (level > option_verbose) {
2011                         return;
2012                 }
2013         }
2014
2015         if ((c = fix_header(tmp, sizeof(tmp), s, VERBOSE_PREFIX_4)) ||
2016             (c = fix_header(tmp, sizeof(tmp), s, VERBOSE_PREFIX_3)) ||
2017             (c = fix_header(tmp, sizeof(tmp), s, VERBOSE_PREFIX_2)) ||
2018             (c = fix_header(tmp, sizeof(tmp), s, VERBOSE_PREFIX_1))) {
2019                 fputs(tmp, stdout);
2020                 fputs(c, stdout);
2021         } else {
2022                 fputs(s, stdout);
2023         }
2024
2025         fflush(stdout);
2026
2027         /* Wake up a poll()ing console */
2028         if (ast_opt_console && consolethread != AST_PTHREADT_NULL) {
2029                 pthread_kill(consolethread, SIGURG);
2030         }
2031 }
2032
2033 static int ast_all_zeros(char *s)
2034 {
2035         while (*s) {
2036                 if (*s > 32)
2037                         return 0;
2038                 s++;
2039         }
2040         return 1;
2041 }
2042
2043 static void consolehandler(char *s)
2044 {
2045         printf("%s", term_end());
2046         fflush(stdout);
2047
2048         /* Called when readline data is available */
2049         if (!ast_all_zeros(s))
2050                 ast_el_add_history(s);
2051         /* The real handler for bang */
2052         if (s[0] == '!') {
2053                 if (s[1])
2054                         ast_safe_system(s+1);
2055                 else
2056                         ast_safe_system(getenv("SHELL") ? getenv("SHELL") : "/bin/sh");
2057         } else
2058                 ast_cli_command(STDOUT_FILENO, s);
2059 }
2060
2061 static int remoteconsolehandler(char *s)
2062 {
2063         int ret = 0;
2064
2065         /* Called when readline data is available */
2066         if (!ast_all_zeros(s))
2067                 ast_el_add_history(s);
2068         /* The real handler for bang */
2069         if (s[0] == '!') {
2070                 if (s[1])
2071                         ast_safe_system(s+1);
2072                 else
2073                         ast_safe_system(getenv("SHELL") ? getenv("SHELL") : "/bin/sh");
2074                 ret = 1;
2075         } else if (strncasecmp(s, "core set verbose ", 17) == 0) {
2076                 int old_verbose = option_verbose;
2077                 if (strncasecmp(s + 17, "atleast ", 8) == 0) {
2078                         int tmp;
2079                         if (sscanf(s + 25, "%d", &tmp) != 1) {
2080                                 fprintf(stderr, "Usage: core set verbose [atleast] <level>\n");
2081                         } else {
2082                                 if (tmp > option_verbose) {
2083                                         option_verbose = tmp;
2084                                 }
2085                                 if (old_verbose != option_verbose) {
2086                                         fprintf(stdout, "Set remote console verbosity from %d to %d\n", old_verbose, option_verbose);
2087                                 } else {
2088                                         fprintf(stdout, "Verbosity level unchanged.\n");
2089                                 }
2090                         }
2091                 } else {
2092                         if (sscanf(s + 17, "%d", &option_verbose) != 1) {
2093                                 fprintf(stderr, "Usage: core set verbose [atleast] <level>\n");
2094                         } else {
2095                                 if (old_verbose != option_verbose) {
2096                                         fprintf(stdout, "Set remote console verbosity to %d\n", option_verbose);
2097                                 } else {
2098                                         fprintf(stdout, "Verbosity level unchanged.\n");
2099                                 }
2100                         }
2101                 }
2102                 ret = 1;
2103         } else if ((strncasecmp(s, "quit", 4) == 0 || strncasecmp(s, "exit", 4) == 0) &&
2104             (s[4] == '\0' || isspace(s[4]))) {
2105                 quit_handler(0, SHUTDOWN_FAST, 0);
2106                 ret = 1;
2107         }
2108
2109         return ret;
2110 }
2111
2112 static char *handle_version(struct ast_cli_entry *e, int cmd, struct ast_cli_args *a)
2113 {
2114         switch (cmd) {
2115         case CLI_INIT:
2116                 e->command = "core show version";
2117                 e->usage =
2118                         "Usage: core show version\n"
2119                         "       Shows Asterisk version information.\n";
2120                 return NULL;
2121         case CLI_GENERATE:
2122                 return NULL;
2123         }
2124
2125         if (a->argc != 3)
2126                 return CLI_SHOWUSAGE;
2127         ast_cli(a->fd, "Asterisk %s built by %s @ %s on a %s running %s on %s\n",
2128                 ast_get_version(), ast_build_user, ast_build_hostname,
2129                 ast_build_machine, ast_build_os, ast_build_date);
2130         return CLI_SUCCESS;
2131 }
2132
2133 #if 0
2134 static int handle_quit(int fd, int argc, char *argv[])
2135 {
2136         if (argc != 1)
2137                 return RESULT_SHOWUSAGE;
2138         quit_handler(0, SHUTDOWN_NORMAL, 0);
2139         return RESULT_SUCCESS;
2140 }
2141 #endif
2142
2143 static char *handle_stop_now(struct ast_cli_entry *e, int cmd, struct ast_cli_args *a)
2144 {
2145         switch (cmd) {
2146         case CLI_INIT:
2147                 e->command = "core stop now";
2148                 e->usage =
2149                         "Usage: core stop now\n"
2150                         "       Shuts down a running Asterisk immediately, hanging up all active calls .\n";
2151                 return NULL;
2152         case CLI_GENERATE:
2153                 return NULL;
2154         }
2155
2156         if (a->argc != e->args)
2157                 return CLI_SHOWUSAGE;
2158         quit_handler(0, SHUTDOWN_NORMAL, 0 /* not restart */);
2159         return CLI_SUCCESS;
2160 }
2161
2162 static char *handle_stop_gracefully(struct ast_cli_entry *e, int cmd, struct ast_cli_args *a)
2163 {
2164         switch (cmd) {
2165         case CLI_INIT:
2166                 e->command = "core stop gracefully";
2167                 e->usage =
2168                         "Usage: core stop gracefully\n"
2169                         "       Causes Asterisk to not accept new calls, and exit when all\n"
2170                         "       active calls have terminated normally.\n";
2171                 return NULL;
2172         case CLI_GENERATE:
2173                 return NULL;
2174         }
2175
2176         if (a->argc != e->args)
2177                 return CLI_SHOWUSAGE;
2178         quit_handler(0, SHUTDOWN_NICE, 0 /* no restart */);
2179         return CLI_SUCCESS;
2180 }
2181
2182 static char *handle_stop_when_convenient(struct ast_cli_entry *e, int cmd, struct ast_cli_args *a)
2183 {
2184         switch (cmd) {
2185         case CLI_INIT:
2186                 e->command = "core stop when convenient";
2187                 e->usage =
2188                         "Usage: core stop when convenient\n"
2189                         "       Causes Asterisk to perform a shutdown when all active calls have ended.\n";
2190                 return NULL;
2191         case CLI_GENERATE:
2192                 return NULL;
2193         }
2194
2195         if (a->argc != e->args)
2196                 return CLI_SHOWUSAGE;
2197         ast_cli(a->fd, "Waiting for inactivity to perform halt\n");
2198         quit_handler(0, SHUTDOWN_REALLY_NICE, 0 /* don't restart */);
2199         return CLI_SUCCESS;
2200 }
2201
2202 static char *handle_restart_now(struct ast_cli_entry *e, int cmd, struct ast_cli_args *a)
2203 {
2204         switch (cmd) {
2205         case CLI_INIT:
2206                 e->command = "core restart now";
2207                 e->usage =
2208                         "Usage: core restart now\n"
2209                         "       Causes Asterisk to hangup all calls and exec() itself performing a cold\n"
2210                         "       restart.\n";
2211                 return NULL;
2212         case CLI_GENERATE:
2213                 return NULL;
2214         }
2215
2216         if (a->argc != e->args)
2217                 return CLI_SHOWUSAGE;
2218         quit_handler(0, SHUTDOWN_NORMAL, 1 /* restart */);
2219         return CLI_SUCCESS;
2220 }
2221
2222 static char *handle_restart_gracefully(struct ast_cli_entry *e, int cmd, struct ast_cli_args *a)
2223 {
2224         switch (cmd) {
2225         case CLI_INIT:
2226                 e->command = "core restart gracefully";
2227                 e->usage =
2228                         "Usage: core restart gracefully\n"
2229                         "       Causes Asterisk to stop accepting new calls and exec() itself performing a cold\n"
2230                         "       restart when all active calls have ended.\n";
2231                 return NULL;
2232         case CLI_GENERATE:
2233                 return NULL;
2234         }
2235
2236         if (a->argc != e->args)
2237                 return CLI_SHOWUSAGE;
2238         quit_handler(0, SHUTDOWN_NICE, 1 /* restart */);
2239         return CLI_SUCCESS;
2240 }
2241
2242 static char *handle_restart_when_convenient(struct ast_cli_entry *e, int cmd, struct ast_cli_args *a)
2243 {
2244         switch (cmd) {
2245         case CLI_INIT:
2246                 e->command = "core restart when convenient";
2247                 e->usage =
2248                         "Usage: core restart when convenient\n"
2249                         "       Causes Asterisk to perform a cold restart when all active calls have ended.\n";
2250                 return NULL;
2251         case CLI_GENERATE:
2252                 return NULL;
2253         }
2254
2255         if (a->argc != e->args)
2256                 return CLI_SHOWUSAGE;
2257         ast_cli(a->fd, "Waiting for inactivity to perform restart\n");
2258         quit_handler(0, SHUTDOWN_REALLY_NICE, 1 /* restart */);
2259         return CLI_SUCCESS;
2260 }
2261
2262 static char *handle_abort_shutdown(struct ast_cli_entry *e, int cmd, struct ast_cli_args *a)
2263 {
2264         int aborting_shutdown = 0;
2265
2266         switch (cmd) {
2267         case CLI_INIT:
2268                 e->command = "core abort shutdown";
2269                 e->usage =
2270                         "Usage: core abort shutdown\n"
2271                         "       Causes Asterisk to abort an executing shutdown or restart, and resume normal\n"
2272                         "       call operations.\n";
2273                 return NULL;
2274         case CLI_GENERATE:
2275                 return NULL;
2276         }
2277
2278         if (a->argc != e->args)
2279                 return CLI_SHOWUSAGE;
2280
2281         ast_mutex_lock(&safe_system_lock);
2282         if (shuttingdown >= SHUTDOWN_FAST) {
2283                 aborting_shutdown = 1;
2284                 shuttingdown = NOT_SHUTTING_DOWN;
2285         }
2286         ast_mutex_unlock(&safe_system_lock);
2287
2288         if (aborting_shutdown) {
2289                 ast_cancel_shutdown();
2290         }
2291         return CLI_SUCCESS;
2292 }
2293
2294 static char *handle_bang(struct ast_cli_entry *e, int cmd, struct ast_cli_args *a)
2295 {
2296         switch (cmd) {
2297         case CLI_INIT:
2298                 e->command = "!";
2299                 e->usage =
2300                         "Usage: !<command>\n"
2301                         "       Executes a given shell command\n";
2302                 return NULL;
2303         case CLI_GENERATE:
2304                 return NULL;
2305         }
2306
2307         return CLI_SUCCESS;
2308 }
2309 static const char warranty_lines[] = {
2310         "\n"
2311         "                           NO WARRANTY\n"
2312         "\n"
2313         "BECAUSE THE PROGRAM IS LICENSED FREE OF CHARGE, THERE IS NO WARRANTY\n"
2314         "FOR THE PROGRAM, TO THE EXTENT PERMITTED BY APPLICABLE LAW.  EXCEPT WHEN\n"
2315         "OTHERWISE STATED IN WRITING THE COPYRIGHT HOLDERS AND/OR OTHER PARTIES\n"
2316         "PROVIDE THE PROGRAM \"AS IS\" WITHOUT WARRANTY OF ANY KIND, EITHER EXPRESSED\n"
2317         "OR IMPLIED, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF\n"
2318         "MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE.  THE ENTIRE RISK AS\n"
2319         "TO THE QUALITY AND PERFORMANCE OF THE PROGRAM IS WITH YOU.  SHOULD THE\n"
2320         "PROGRAM PROVE DEFECTIVE, YOU ASSUME THE COST OF ALL NECESSARY SERVICING,\n"
2321         "REPAIR OR CORRECTION.\n"
2322         "\n"
2323         "IN NO EVENT UNLESS REQUIRED BY APPLICABLE LAW OR AGREED TO IN WRITING\n"
2324         "WILL ANY COPYRIGHT HOLDER, OR ANY OTHER PARTY WHO MAY MODIFY AND/OR\n"
2325         "REDISTRIBUTE THE PROGRAM AS PERMITTED ABOVE, BE LIABLE TO YOU FOR DAMAGES,\n"
2326         "INCLUDING ANY GENERAL, SPECIAL, INCIDENTAL OR CONSEQUENTIAL DAMAGES ARISING\n"
2327         "OUT OF THE USE OR INABILITY TO USE THE PROGRAM (INCLUDING BUT NOT LIMITED\n"
2328         "TO LOSS OF DATA OR DATA BEING RENDERED INACCURATE OR LOSSES SUSTAINED BY\n"
2329         "YOU OR THIRD PARTIES OR A FAILURE OF THE PROGRAM TO OPERATE WITH ANY OTHER\n"
2330         "PROGRAMS), EVEN IF SUCH HOLDER OR OTHER PARTY HAS BEEN ADVISED OF THE\n"
2331         "POSSIBILITY OF SUCH DAMAGES.\n"
2332 };
2333
2334 static char *show_warranty(struct ast_cli_entry *e, int cmd, struct ast_cli_args *a)
2335 {
2336         switch (cmd) {
2337         case CLI_INIT:
2338                 e->command = "core show warranty";
2339                 e->usage =
2340                         "Usage: core show warranty\n"
2341                         "       Shows the warranty (if any) for this copy of Asterisk.\n";
2342                 return NULL;
2343         case CLI_GENERATE:
2344                 return NULL;
2345         }
2346
2347         ast_cli(a->fd, "%s", warranty_lines);
2348
2349         return CLI_SUCCESS;
2350 }
2351
2352 static const char license_lines[] = {
2353         "\n"
2354         "This program is free software; you can redistribute it and/or modify\n"
2355         "it under the terms of the GNU General Public License version 2 as\n"
2356         "published by the Free Software Foundation.\n"
2357         "\n"
2358         "This program also contains components licensed under other licenses.\n"
2359         "They include:\n"
2360         "\n"
2361         "This program is distributed in the hope that it will be useful,\n"
2362         "but WITHOUT ANY WARRANTY; without even the implied warranty of\n"
2363         "MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the\n"
2364         "GNU General Public License for more details.\n"
2365         "\n"
2366         "You should have received a copy of the GNU General Public License\n"
2367         "along with this program; if not, write to the Free Software\n"
2368         "Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA\n"
2369 };
2370
2371 static char *show_license(struct ast_cli_entry *e, int cmd, struct ast_cli_args *a)
2372 {
2373         switch (cmd) {
2374         case CLI_INIT:
2375                 e->command = "core show license";
2376                 e->usage =
2377                         "Usage: core show license\n"
2378                         "       Shows the license(s) for this copy of Asterisk.\n";
2379                 return NULL;
2380         case CLI_GENERATE:
2381                 return NULL;
2382         }
2383
2384         ast_cli(a->fd, "%s", license_lines);
2385
2386         return CLI_SUCCESS;
2387 }
2388
2389 #define ASTERISK_PROMPT "*CLI> "
2390
2391 #define ASTERISK_PROMPT2 "%s*CLI> "
2392
2393 /*!
2394  * \brief Shutdown Asterisk CLI commands.
2395  *
2396  * \note These CLI commands cannot be unregistered at shutdown
2397  * because one of them is likely the reason for the shutdown.
2398  * The CLI generates a warning if a command is in-use when it is
2399  * unregistered.
2400  */
2401 static struct ast_cli_entry cli_asterisk_shutdown[] = {
2402         AST_CLI_DEFINE(handle_stop_now, "Shut down Asterisk immediately"),
2403         AST_CLI_DEFINE(handle_stop_gracefully, "Gracefully shut down Asterisk"),
2404         AST_CLI_DEFINE(handle_stop_when_convenient, "Shut down Asterisk at empty call volume"),
2405         AST_CLI_DEFINE(handle_restart_now, "Restart Asterisk immediately"),
2406         AST_CLI_DEFINE(handle_restart_gracefully, "Restart Asterisk gracefully"),
2407         AST_CLI_DEFINE(handle_restart_when_convenient, "Restart Asterisk at empty call volume"),
2408 };
2409
2410 static struct ast_cli_entry cli_asterisk[] = {
2411         AST_CLI_DEFINE(handle_abort_shutdown, "Cancel a running shutdown"),
2412         AST_CLI_DEFINE(show_warranty, "Show the warranty (if any) for this copy of Asterisk"),
2413         AST_CLI_DEFINE(show_license, "Show the license(s) for this copy of Asterisk"),
2414         AST_CLI_DEFINE(handle_version, "Display version info"),
2415         AST_CLI_DEFINE(handle_bang, "Execute a shell command"),
2416 #if !defined(LOW_MEMORY)
2417         AST_CLI_DEFINE(handle_show_version_files, "List versions of files used to build Asterisk"),
2418         AST_CLI_DEFINE(handle_show_threads, "Show running threads"),
2419 #if defined(HAVE_SYSINFO) || defined(HAVE_SYSCTL)
2420         AST_CLI_DEFINE(handle_show_sysinfo, "Show System Information"),
2421 #endif
2422         AST_CLI_DEFINE(handle_show_profile, "Display profiling info"),
2423         AST_CLI_DEFINE(handle_show_settings, "Show some core settings"),
2424         AST_CLI_DEFINE(handle_clear_profile, "Clear profiling info"),
2425 #endif /* ! LOW_MEMORY */
2426 };
2427
2428 struct el_read_char_state_struct {
2429         unsigned int line_full:1;
2430         unsigned int prev_line_full:1;
2431         char prev_line_verbosity;
2432 };
2433
2434 static int el_read_char_state_init(void *ptr)
2435 {
2436         struct el_read_char_state_struct *state = ptr;
2437         state->line_full = 1;
2438         state->prev_line_full = 1;
2439         state->prev_line_verbosity = 0;
2440         return 0;
2441 }
2442
2443 AST_THREADSTORAGE_CUSTOM(el_read_char_state, el_read_char_state_init, ast_free_ptr);
2444
2445 static int ast_el_read_char(EditLine *editline, char *cp)
2446 {
2447         int num_read = 0;
2448         int lastpos = 0;
2449         struct pollfd fds[2];
2450         int res;
2451         int max;
2452 #define EL_BUF_SIZE 512
2453         char buf[EL_BUF_SIZE];
2454         struct el_read_char_state_struct *state = ast_threadstorage_get(&el_read_char_state, sizeof(*state));
2455
2456         for (;;) {
2457                 max = 1;
2458                 fds[0].fd = ast_consock;
2459                 fds[0].events = POLLIN;
2460                 if (!ast_opt_exec) {
2461                         fds[1].fd = STDIN_FILENO;
2462                         fds[1].events = POLLIN;
2463                         max++;
2464                 }
2465                 res = ast_poll(fds, max, -1);
2466                 if (res < 0) {
2467                         if (sig_flags.need_quit || sig_flags.need_quit_handler)
2468                                 break;
2469                         if (errno == EINTR)
2470                                 continue;
2471                         fprintf(stderr, "poll failed: %s\n", strerror(errno));
2472                         break;
2473                 }
2474
2475                 if (!ast_opt_exec && fds[1].revents) {
2476                         num_read = read(STDIN_FILENO, cp, 1);
2477                         if (num_read < 1) {
2478                                 break;
2479                         } else {
2480                                 return (num_read);
2481                         }
2482                 }
2483                 if (fds[0].revents) {
2484                         char level = 0;
2485                         char *curline = buf, *nextline;
2486                         res = read(ast_consock, buf, sizeof(buf) - 1);
2487                         /* if the remote side disappears exit */
2488                         if (res < 1) {
2489                                 fprintf(stderr, "\nDisconnected from Asterisk server\n");
2490                                 if (!ast_opt_reconnect) {
2491                                         quit_handler(0, SHUTDOWN_FAST, 0);
2492                                 } else {
2493                                         int tries;
2494                                         int reconnects_per_second = 20;
2495                                         fprintf(stderr, "Attempting to reconnect for 30 seconds\n");
2496                                         for (tries = 0; tries < 30 * reconnects_per_second; tries++) {
2497                                                 if (ast_tryconnect()) {
2498                                                         fprintf(stderr, "Reconnect succeeded after %.3f seconds\n", 1.0 / reconnects_per_second * tries);
2499                                                         printf("%s", term_quit());
2500                                                         WELCOME_MESSAGE;
2501                                                         if (!ast_opt_mute)
2502                                                                 fdsend(ast_consock, "logger mute silent");
2503                                                         else
2504                                                                 printf("log and verbose output currently muted ('logger mute' to unmute)\n");
2505                                                         break;
2506                                                 } else
2507                                                         usleep(1000000 / reconnects_per_second);
2508                                         }
2509                                         if (tries >= 30 * reconnects_per_second) {
2510                                                 fprintf(stderr, "Failed to reconnect for 30 seconds.  Quitting.\n");
2511                                                 quit_handler(0, SHUTDOWN_FAST, 0);
2512                                         }
2513                                 }
2514                                 continue;
2515                         }
2516
2517                         buf[res] = '\0';
2518
2519                         /* Write over the CLI prompt */
2520                         if (!ast_opt_exec && !lastpos) {
2521                                 if (write(STDOUT_FILENO, "\r\e[0K", 5) < 0) {
2522                                 }
2523                         }
2524
2525                         do {
2526                                 state->prev_line_full = state->line_full;
2527                                 if ((nextline = strchr(curline, '\n'))) {
2528                                         state->line_full = 1;
2529                                         nextline++;
2530                                 } else {
2531                                         state->line_full = 0;
2532                                         nextline = strchr(curline, '\0');
2533                                 }
2534
2535                                 if (state->prev_line_full && VERBOSE_HASMAGIC(curline)) {
2536                                         level = VERBOSE_MAGIC2LEVEL(curline);
2537                                         curline++;
2538                                 } else if (state->prev_line_full && !VERBOSE_HASMAGIC(curline)) {
2539                                         /* Non-verbose output */
2540                                         level = 0;
2541                                 } else {
2542                                         level = state->prev_line_verbosity;
2543                                 }
2544                                 if ((!state->prev_line_full && state->prev_line_verbosity <= option_verbose) || (state->prev_line_full && level <= option_verbose)) {
2545                                         if (write(STDOUT_FILENO, curline, nextline - curline) < 0) {
2546                                         }
2547                                 }
2548
2549                                 state->prev_line_verbosity = level;
2550                                 curline = nextline;
2551                         } while (!ast_strlen_zero(curline));
2552
2553                         if ((res < EL_BUF_SIZE - 1) && ((buf[res-1] == '\n') || (buf[res-2] == '\n'))) {
2554                                 *cp = CC_REFRESH;
2555                                 return(1);
2556                         } else
2557                                 lastpos = 1;
2558                 }
2559         }
2560
2561         *cp = '\0';
2562         return (0);
2563 }
2564
2565 static struct ast_str *prompt = NULL;
2566
2567 static char *cli_prompt(EditLine *editline)
2568 {
2569         char tmp[100];
2570         char *pfmt;
2571         int color_used = 0;
2572         static int cli_prompt_changes = 0;
2573         char term_code[20];
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_str_append(&prompt, 0, "%s", term_color_code(term_code, fgcolor, bgcolor, sizeof(term_code)));
2601                                                 t += i - 1;
2602                                         } else if (sscanf(t, "%30d%n", &fgcolor, &i) == 1) {
2603                                                 ast_str_append(&prompt, 0, "%s", term_color_code(term_code, fgcolor, 0, sizeof(term_code)));
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_str_append(&prompt, 0, "%s", term_color_code(term_code, 0, 0, sizeof(term_code)));
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) {
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] = "";