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