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