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