df5561860ff13dba7c194de9774f702f252681d3
[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/optional_api.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         int newline;
2061         char verbose_line_level;
2062 };
2063
2064 static int console_state_init(void *ptr)
2065 {
2066         struct console_state_data *state = ptr;
2067         state->newline = 1;
2068         state->verbose_line_level = 0;
2069         return 0;
2070 }
2071
2072 AST_THREADSTORAGE_CUSTOM(console_state, console_state_init, ast_free_ptr);
2073
2074 /* These gymnastics are due to platforms which designate char as unsigned by
2075  * default. Level is the negative character -- offset by 1, because \0 is the
2076  * EOS delimiter. */
2077 #define VERBOSE_MAGIC2LEVEL(x) (((char) -*(signed char *) (x)) - 1)
2078 #define VERBOSE_HASMAGIC(x)     (*(signed char *) (x) < 0)
2079
2080 static int console_log_verbose(const char *s)
2081 {
2082         /* verbose level of 0 evaluates to a magic of -1, 1 to -2, etc...
2083            search up to -7 (level = 6) as this is currently the largest
2084            level used */
2085         static const char find_set[9] = { -1, -2, -3, -4, -5, -6, -7, '\n'};
2086
2087         struct console_state_data *state =
2088                 ast_threadstorage_get(&console_state, sizeof(*state));
2089
2090         char prefix[80];
2091         const char *c = s;
2092         int res = 0;
2093
2094         do {
2095                 if (VERBOSE_HASMAGIC(s)) {
2096                         /* if it has one always use the given line's level,
2097                            otherwise we'll use the last line's level */
2098                         state->verbose_line_level = VERBOSE_MAGIC2LEVEL(s);
2099                         /* move past magic */
2100                         s++;
2101                 }
2102
2103                 c = fix_header(prefix, sizeof(prefix), s,
2104                                state->verbose_line_level);
2105
2106                 if (!state->newline) {
2107                         /* don't use the prefix if line continuation */
2108                         *prefix = '\0';
2109                 }
2110
2111                 /* for a given line separate on verbose magic and newlines */
2112                 if (!(s = strpbrk(c, find_set))) {
2113                         s = strchr(c, '\0');
2114                 } else if (*s == '\n') {
2115                         ++s;
2116                 }
2117
2118                 /* check if we should write this line after calculating begin/end
2119                    so we process the case of a higher level line embedded within
2120                    two lower level lines */
2121                 if (state->verbose_line_level > option_verbose) {
2122                         continue;
2123                 }
2124
2125                 state->newline = *(s - 1) == '\n';
2126                 if (!ast_strlen_zero(prefix)) {
2127                         fputs(prefix, stdout);
2128                 }
2129
2130                 fwrite(c, sizeof(char), s - c, stdout);
2131
2132                 if (!res) {
2133                         /* if at least some info has been written
2134                            we'll want to return true */
2135                         res = 1;
2136                 }
2137                 c = s;
2138         } while (*s);
2139
2140         if (res) {
2141                 fflush(stdout);
2142         }
2143
2144         return res;
2145 }
2146
2147 static void console_verboser(const char *s)
2148 {
2149         if (!console_log_verbose(s)) {
2150                 return;
2151         }
2152
2153         /* Wake up a poll()ing console */
2154         if (ast_opt_console && consolethread != AST_PTHREADT_NULL) {
2155                 pthread_kill(consolethread, SIGURG);
2156         }
2157 }
2158
2159 static int ast_all_zeros(char *s)
2160 {
2161         while (*s) {
2162                 if (*s > 32)
2163                         return 0;
2164                 s++;
2165         }
2166         return 1;
2167 }
2168
2169 static void consolehandler(char *s)
2170 {
2171         printf("%s", term_end());
2172         fflush(stdout);
2173
2174         /* Called when readline data is available */
2175         if (!ast_all_zeros(s))
2176                 ast_el_add_history(s);
2177         /* The real handler for bang */
2178         if (s[0] == '!') {
2179                 if (s[1])
2180                         ast_safe_system(s+1);
2181                 else
2182                         ast_safe_system(getenv("SHELL") ? getenv("SHELL") : "/bin/sh");
2183         } else
2184                 ast_cli_command(STDOUT_FILENO, s);
2185 }
2186
2187 static int remoteconsolehandler(char *s)
2188 {
2189         int ret = 0;
2190
2191         /* Called when readline data is available */
2192         if (!ast_all_zeros(s))
2193                 ast_el_add_history(s);
2194
2195         while (isspace(*s)) {
2196                 s++;
2197         }
2198
2199         /* The real handler for bang */
2200         if (s[0] == '!') {
2201                 if (s[1])
2202                         ast_safe_system(s+1);
2203                 else
2204                         ast_safe_system(getenv("SHELL") ? getenv("SHELL") : "/bin/sh");
2205                 ret = 1;
2206         } else if (strncasecmp(s, "core set verbose ", 17) == 0) {
2207                 int old_verbose = option_verbose;
2208                 if (strncasecmp(s + 17, "atleast ", 8) == 0) {
2209                         int tmp;
2210                         if (sscanf(s + 25, "%d", &tmp) != 1) {
2211                                 fprintf(stderr, "Usage: core set verbose [atleast] <level>\n");
2212                         } else {
2213                                 if (tmp > option_verbose) {
2214                                         option_verbose = tmp;
2215                                 }
2216                                 if (old_verbose != option_verbose) {
2217                                         fprintf(stdout, "Set remote console verbosity from %d to %d\n", old_verbose, option_verbose);
2218                                 } else {
2219                                         fprintf(stdout, "Verbosity level unchanged.\n");
2220                                 }
2221                         }
2222                 } else {
2223                         if (sscanf(s + 17, "%d", &option_verbose) != 1) {
2224                                 fprintf(stderr, "Usage: core set verbose [atleast] <level>\n");
2225                         } else {
2226                                 if (old_verbose != option_verbose) {
2227                                         fprintf(stdout, "Set remote console verbosity to %d\n", option_verbose);
2228                                 } else {
2229                                         fprintf(stdout, "Verbosity level unchanged.\n");
2230                                 }
2231                         }
2232                 }
2233                 ret = 1;
2234         } else if ((strncasecmp(s, "quit", 4) == 0 || strncasecmp(s, "exit", 4) == 0) &&
2235             (s[4] == '\0' || isspace(s[4]))) {
2236                 quit_handler(0, SHUTDOWN_FAST, 0);
2237                 ret = 1;
2238         }
2239
2240         return ret;
2241 }
2242
2243 static char *handle_version(struct ast_cli_entry *e, int cmd, struct ast_cli_args *a)
2244 {
2245         switch (cmd) {
2246         case CLI_INIT:
2247                 e->command = "core show version";
2248                 e->usage =
2249                         "Usage: core show version\n"
2250                         "       Shows Asterisk version information.\n";
2251                 return NULL;
2252         case CLI_GENERATE:
2253                 return NULL;
2254         }
2255
2256         if (a->argc != 3)
2257                 return CLI_SHOWUSAGE;
2258         ast_cli(a->fd, "Asterisk %s built by %s @ %s on a %s running %s on %s\n",
2259                 ast_get_version(), ast_build_user, ast_build_hostname,
2260                 ast_build_machine, ast_build_os, ast_build_date);
2261         return CLI_SUCCESS;
2262 }
2263
2264 #if 0
2265 static int handle_quit(int fd, int argc, char *argv[])
2266 {
2267         if (argc != 1)
2268                 return RESULT_SHOWUSAGE;
2269         quit_handler(0, SHUTDOWN_NORMAL, 0);
2270         return RESULT_SUCCESS;
2271 }
2272 #endif
2273
2274 static char *handle_stop_now(struct ast_cli_entry *e, int cmd, struct ast_cli_args *a)
2275 {
2276         switch (cmd) {
2277         case CLI_INIT:
2278                 e->command = "core stop now";
2279                 e->usage =
2280                         "Usage: core stop now\n"
2281                         "       Shuts down a running Asterisk immediately, hanging up all active calls .\n";
2282                 return NULL;
2283         case CLI_GENERATE:
2284                 return NULL;
2285         }
2286
2287         if (a->argc != e->args)
2288                 return CLI_SHOWUSAGE;
2289         quit_handler(0, SHUTDOWN_NORMAL, 0 /* not restart */);
2290         return CLI_SUCCESS;
2291 }
2292
2293 static char *handle_stop_gracefully(struct ast_cli_entry *e, int cmd, struct ast_cli_args *a)
2294 {
2295         switch (cmd) {
2296         case CLI_INIT:
2297                 e->command = "core stop gracefully";
2298                 e->usage =
2299                         "Usage: core stop gracefully\n"
2300                         "       Causes Asterisk to not accept new calls, and exit when all\n"
2301                         "       active calls have terminated normally.\n";
2302                 return NULL;
2303         case CLI_GENERATE:
2304                 return NULL;
2305         }
2306
2307         if (a->argc != e->args)
2308                 return CLI_SHOWUSAGE;
2309         quit_handler(0, SHUTDOWN_NICE, 0 /* no restart */);
2310         return CLI_SUCCESS;
2311 }
2312
2313 static char *handle_stop_when_convenient(struct ast_cli_entry *e, int cmd, struct ast_cli_args *a)
2314 {
2315         switch (cmd) {
2316         case CLI_INIT:
2317                 e->command = "core stop when convenient";
2318                 e->usage =
2319                         "Usage: core stop when convenient\n"
2320                         "       Causes Asterisk to perform a shutdown when all active calls have ended.\n";
2321                 return NULL;
2322         case CLI_GENERATE:
2323                 return NULL;
2324         }
2325
2326         if (a->argc != e->args)
2327                 return CLI_SHOWUSAGE;
2328         ast_cli(a->fd, "Waiting for inactivity to perform halt\n");
2329         quit_handler(0, SHUTDOWN_REALLY_NICE, 0 /* don't restart */);
2330         return CLI_SUCCESS;
2331 }
2332
2333 static char *handle_restart_now(struct ast_cli_entry *e, int cmd, struct ast_cli_args *a)
2334 {
2335         switch (cmd) {
2336         case CLI_INIT:
2337                 e->command = "core restart now";
2338                 e->usage =
2339                         "Usage: core restart now\n"
2340                         "       Causes Asterisk to hangup all calls and exec() itself performing a cold\n"
2341                         "       restart.\n";
2342                 return NULL;
2343         case CLI_GENERATE:
2344                 return NULL;
2345         }
2346
2347         if (a->argc != e->args)
2348                 return CLI_SHOWUSAGE;
2349         quit_handler(0, SHUTDOWN_NORMAL, 1 /* restart */);
2350         return CLI_SUCCESS;
2351 }
2352
2353 static char *handle_restart_gracefully(struct ast_cli_entry *e, int cmd, struct ast_cli_args *a)
2354 {
2355         switch (cmd) {
2356         case CLI_INIT:
2357                 e->command = "core restart gracefully";
2358                 e->usage =
2359                         "Usage: core restart gracefully\n"
2360                         "       Causes Asterisk to stop accepting new calls and exec() itself performing a cold\n"
2361                         "       restart when all active calls have ended.\n";
2362                 return NULL;
2363         case CLI_GENERATE:
2364                 return NULL;
2365         }
2366
2367         if (a->argc != e->args)
2368                 return CLI_SHOWUSAGE;
2369         quit_handler(0, SHUTDOWN_NICE, 1 /* restart */);
2370         return CLI_SUCCESS;
2371 }
2372
2373 static char *handle_restart_when_convenient(struct ast_cli_entry *e, int cmd, struct ast_cli_args *a)
2374 {
2375         switch (cmd) {
2376         case CLI_INIT:
2377                 e->command = "core restart when convenient";
2378                 e->usage =
2379                         "Usage: core restart when convenient\n"
2380                         "       Causes Asterisk to perform a cold restart when all active calls have ended.\n";
2381                 return NULL;
2382         case CLI_GENERATE:
2383                 return NULL;
2384         }
2385
2386         if (a->argc != e->args)
2387                 return CLI_SHOWUSAGE;
2388         ast_cli(a->fd, "Waiting for inactivity to perform restart\n");
2389         quit_handler(0, SHUTDOWN_REALLY_NICE, 1 /* restart */);
2390         return CLI_SUCCESS;
2391 }
2392
2393 static char *handle_abort_shutdown(struct ast_cli_entry *e, int cmd, struct ast_cli_args *a)
2394 {
2395         int aborting_shutdown = 0;
2396
2397         switch (cmd) {
2398         case CLI_INIT:
2399                 e->command = "core abort shutdown";
2400                 e->usage =
2401                         "Usage: core abort shutdown\n"
2402                         "       Causes Asterisk to abort an executing shutdown or restart, and resume normal\n"
2403                         "       call operations.\n";
2404                 return NULL;
2405         case CLI_GENERATE:
2406                 return NULL;
2407         }
2408
2409         if (a->argc != e->args)
2410                 return CLI_SHOWUSAGE;
2411
2412         ast_mutex_lock(&safe_system_lock);
2413         if (shuttingdown >= SHUTDOWN_FAST) {
2414                 aborting_shutdown = 1;
2415                 shuttingdown = NOT_SHUTTING_DOWN;
2416         }
2417         ast_mutex_unlock(&safe_system_lock);
2418
2419         if (aborting_shutdown) {
2420                 ast_cancel_shutdown();
2421         }
2422         return CLI_SUCCESS;
2423 }
2424
2425 static char *handle_bang(struct ast_cli_entry *e, int cmd, struct ast_cli_args *a)
2426 {
2427         switch (cmd) {
2428         case CLI_INIT:
2429                 e->command = "!";
2430                 e->usage =
2431                         "Usage: !<command>\n"
2432                         "       Executes a given shell command\n";
2433                 return NULL;
2434         case CLI_GENERATE:
2435                 return NULL;
2436         }
2437
2438         return CLI_SUCCESS;
2439 }
2440 static const char warranty_lines[] = {
2441         "\n"
2442         "                           NO WARRANTY\n"
2443         "\n"
2444         "BECAUSE THE PROGRAM IS LICENSED FREE OF CHARGE, THERE IS NO WARRANTY\n"
2445         "FOR THE PROGRAM, TO THE EXTENT PERMITTED BY APPLICABLE LAW.  EXCEPT WHEN\n"
2446         "OTHERWISE STATED IN WRITING THE COPYRIGHT HOLDERS AND/OR OTHER PARTIES\n"
2447         "PROVIDE THE PROGRAM \"AS IS\" WITHOUT WARRANTY OF ANY KIND, EITHER EXPRESSED\n"
2448         "OR IMPLIED, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF\n"
2449         "MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE.  THE ENTIRE RISK AS\n"
2450         "TO THE QUALITY AND PERFORMANCE OF THE PROGRAM IS WITH YOU.  SHOULD THE\n"
2451         "PROGRAM PROVE DEFECTIVE, YOU ASSUME THE COST OF ALL NECESSARY SERVICING,\n"
2452         "REPAIR OR CORRECTION.\n"
2453         "\n"
2454         "IN NO EVENT UNLESS REQUIRED BY APPLICABLE LAW OR AGREED TO IN WRITING\n"
2455         "WILL ANY COPYRIGHT HOLDER, OR ANY OTHER PARTY WHO MAY MODIFY AND/OR\n"
2456         "REDISTRIBUTE THE PROGRAM AS PERMITTED ABOVE, BE LIABLE TO YOU FOR DAMAGES,\n"
2457         "INCLUDING ANY GENERAL, SPECIAL, INCIDENTAL OR CONSEQUENTIAL DAMAGES ARISING\n"
2458         "OUT OF THE USE OR INABILITY TO USE THE PROGRAM (INCLUDING BUT NOT LIMITED\n"
2459         "TO LOSS OF DATA OR DATA BEING RENDERED INACCURATE OR LOSSES SUSTAINED BY\n"
2460         "YOU OR THIRD PARTIES OR A FAILURE OF THE PROGRAM TO OPERATE WITH ANY OTHER\n"
2461         "PROGRAMS), EVEN IF SUCH HOLDER OR OTHER PARTY HAS BEEN ADVISED OF THE\n"
2462         "POSSIBILITY OF SUCH DAMAGES.\n"
2463 };
2464
2465 static char *show_warranty(struct ast_cli_entry *e, int cmd, struct ast_cli_args *a)
2466 {
2467         switch (cmd) {
2468         case CLI_INIT:
2469                 e->command = "core show warranty";
2470                 e->usage =
2471                         "Usage: core show warranty\n"
2472                         "       Shows the warranty (if any) for this copy of Asterisk.\n";
2473                 return NULL;
2474         case CLI_GENERATE:
2475                 return NULL;
2476         }
2477
2478         ast_cli(a->fd, "%s", warranty_lines);
2479
2480         return CLI_SUCCESS;
2481 }
2482
2483 static const char license_lines[] = {
2484         "\n"
2485         "This program is free software; you can redistribute it and/or modify\n"
2486         "it under the terms of the GNU General Public License version 2 as\n"
2487         "published by the Free Software Foundation.\n"
2488         "\n"
2489         "This program also contains components licensed under other licenses.\n"
2490         "They include:\n"
2491         "\n"
2492         "This program is distributed in the hope that it will be useful,\n"
2493         "but WITHOUT ANY WARRANTY; without even the implied warranty of\n"
2494         "MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the\n"
2495         "GNU General Public License for more details.\n"
2496         "\n"
2497         "You should have received a copy of the GNU General Public License\n"
2498         "along with this program; if not, write to the Free Software\n"
2499         "Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA\n"
2500 };
2501
2502 static char *show_license(struct ast_cli_entry *e, int cmd, struct ast_cli_args *a)
2503 {
2504         switch (cmd) {
2505         case CLI_INIT:
2506                 e->command = "core show license";
2507                 e->usage =
2508                         "Usage: core show license\n"
2509                         "       Shows the license(s) for this copy of Asterisk.\n";
2510                 return NULL;
2511         case CLI_GENERATE:
2512                 return NULL;
2513         }
2514
2515         ast_cli(a->fd, "%s", license_lines);
2516
2517         return CLI_SUCCESS;
2518 }
2519
2520 #define ASTERISK_PROMPT "*CLI> "
2521
2522 #define ASTERISK_PROMPT2 "%s*CLI> "
2523
2524 /*!
2525  * \brief Shutdown Asterisk CLI commands.
2526  *
2527  * \note These CLI commands cannot be unregistered at shutdown
2528  * because one of them is likely the reason for the shutdown.
2529  * The CLI generates a warning if a command is in-use when it is
2530  * unregistered.
2531  */
2532 static struct ast_cli_entry cli_asterisk_shutdown[] = {
2533         AST_CLI_DEFINE(handle_stop_now, "Shut down Asterisk immediately"),
2534         AST_CLI_DEFINE(handle_stop_gracefully, "Gracefully shut down Asterisk"),
2535         AST_CLI_DEFINE(handle_stop_when_convenient, "Shut down Asterisk at empty call volume"),
2536         AST_CLI_DEFINE(handle_restart_now, "Restart Asterisk immediately"),
2537         AST_CLI_DEFINE(handle_restart_gracefully, "Restart Asterisk gracefully"),
2538         AST_CLI_DEFINE(handle_restart_when_convenient, "Restart Asterisk at empty call volume"),
2539 };
2540
2541 static struct ast_cli_entry cli_asterisk[] = {
2542         AST_CLI_DEFINE(handle_abort_shutdown, "Cancel a running shutdown"),
2543         AST_CLI_DEFINE(show_warranty, "Show the warranty (if any) for this copy of Asterisk"),
2544         AST_CLI_DEFINE(show_license, "Show the license(s) for this copy of Asterisk"),
2545         AST_CLI_DEFINE(handle_version, "Display version info"),
2546         AST_CLI_DEFINE(handle_bang, "Execute a shell command"),
2547 #if !defined(LOW_MEMORY)
2548         AST_CLI_DEFINE(handle_show_version_files, "List versions of files used to build Asterisk"),
2549         AST_CLI_DEFINE(handle_show_threads, "Show running threads"),
2550 #if defined(HAVE_SYSINFO) || defined(HAVE_SYSCTL)
2551         AST_CLI_DEFINE(handle_show_sysinfo, "Show System Information"),
2552 #endif
2553         AST_CLI_DEFINE(handle_show_profile, "Display profiling info"),
2554         AST_CLI_DEFINE(handle_show_settings, "Show some core settings"),
2555         AST_CLI_DEFINE(handle_clear_profile, "Clear profiling info"),
2556 #endif /* ! LOW_MEMORY */
2557 };
2558
2559 static int ast_el_read_char(EditLine *editline, char *cp)
2560 {
2561         int num_read = 0;
2562         int lastpos = 0;
2563         struct pollfd fds[2];
2564         int res;
2565         int max;
2566 #define EL_BUF_SIZE 512
2567         char buf[EL_BUF_SIZE];
2568
2569         for (;;) {
2570                 max = 1;
2571                 fds[0].fd = ast_consock;
2572                 fds[0].events = POLLIN;
2573                 if (!ast_opt_exec) {
2574                         fds[1].fd = STDIN_FILENO;
2575                         fds[1].events = POLLIN;
2576                         max++;
2577                 }
2578                 res = ast_poll(fds, max, -1);
2579                 if (res < 0) {
2580                         if (sig_flags.need_quit || sig_flags.need_quit_handler)
2581                                 break;
2582                         if (errno == EINTR)
2583                                 continue;
2584                         fprintf(stderr, "poll failed: %s\n", strerror(errno));
2585                         break;
2586                 }
2587
2588                 if (!ast_opt_exec && fds[1].revents) {
2589                         num_read = read(STDIN_FILENO, cp, 1);
2590                         if (num_read < 1) {
2591                                 break;
2592                         } else {
2593                                 return (num_read);
2594                         }
2595                 }
2596                 if (fds[0].revents) {
2597                         res = read(ast_consock, buf, sizeof(buf) - 1);
2598                         /* if the remote side disappears exit */
2599                         if (res < 1) {
2600                                 fprintf(stderr, "\nDisconnected from Asterisk server\n");
2601                                 if (!ast_opt_reconnect) {
2602                                         quit_handler(0, SHUTDOWN_FAST, 0);
2603                                 } else {
2604                                         int tries;
2605                                         int reconnects_per_second = 20;
2606                                         fprintf(stderr, "Attempting to reconnect for 30 seconds\n");
2607                                         for (tries = 0; tries < 30 * reconnects_per_second; tries++) {
2608                                                 if (ast_tryconnect()) {
2609                                                         fprintf(stderr, "Reconnect succeeded after %.3f seconds\n", 1.0 / reconnects_per_second * tries);
2610                                                         printf("%s", term_quit());
2611                                                         WELCOME_MESSAGE;
2612                                                         if (!ast_opt_mute)
2613                                                                 fdsend(ast_consock, "logger mute silent");
2614                                                         else
2615                                                                 printf("log and verbose output currently muted ('logger mute' to unmute)\n");
2616                                                         break;
2617                                                 } else
2618                                                         usleep(1000000 / reconnects_per_second);
2619                                         }
2620                                         if (tries >= 30 * reconnects_per_second) {
2621                                                 fprintf(stderr, "Failed to reconnect for 30 seconds.  Quitting.\n");
2622                                                 quit_handler(0, SHUTDOWN_FAST, 0);
2623                                         }
2624                                 }
2625                                 continue;
2626                         }
2627
2628                         buf[res] = '\0';
2629
2630                         /* Write over the CLI prompt */
2631                         if (!ast_opt_exec && !lastpos) {
2632                                 if (write(STDOUT_FILENO, "\r\e[0K", 5) < 0) {
2633                                 }
2634                         }
2635
2636                         console_log_verbose(buf);
2637
2638                         if ((res < EL_BUF_SIZE - 1) && ((buf[res-1] == '\n') || (buf[res-2] == '\n'))) {
2639                                 *cp = CC_REFRESH;
2640                                 return(1);
2641                         } else
2642                                 lastpos = 1;
2643                 }
2644         }
2645
2646         *cp = '\0';
2647         return (0);
2648 }
2649
2650 static struct ast_str *prompt = NULL;
2651
2652 static char *cli_prompt(EditLine *editline)
2653 {
2654         char tmp[100];
2655         char *pfmt;
2656         int color_used = 0;
2657         static int cli_prompt_changes = 0;
2658         struct passwd *pw;
2659         struct group *gr;
2660
2661         if (prompt == NULL) {
2662                 prompt = ast_str_create(100);
2663         } else if (!cli_prompt_changes) {
2664                 return ast_str_buffer(prompt);
2665         } else {
2666                 ast_str_reset(prompt);
2667         }
2668
2669         if ((pfmt = getenv("ASTERISK_PROMPT"))) {
2670                 char *t = pfmt;
2671                 struct timeval ts = ast_tvnow();
2672                 while (*t != '\0') {
2673                         if (*t == '%') {
2674                                 char hostname[MAXHOSTNAMELEN] = "";
2675                                 int i, which;
2676                                 struct ast_tm tm = { 0, };
2677                                 int fgcolor = COLOR_WHITE, bgcolor = COLOR_BLACK;
2678
2679                                 t++;
2680                                 switch (*t) {
2681                                 case 'C': /* color */
2682                                         t++;
2683                                         if (sscanf(t, "%30d;%30d%n", &fgcolor, &bgcolor, &i) == 2) {
2684                                                 ast_term_color_code(&prompt, fgcolor, bgcolor);
2685                                                 t += i - 1;
2686                                         } else if (sscanf(t, "%30d%n", &fgcolor, &i) == 1) {
2687                                                 ast_term_color_code(&prompt, fgcolor, 0);
2688                                                 t += i - 1;
2689                                         }
2690
2691                                         /* If the color has been reset correctly, then there's no need to reset it later */
2692                                         color_used = ((fgcolor == COLOR_WHITE) && (bgcolor == COLOR_BLACK)) ? 0 : 1;
2693                                         break;
2694                                 case 'd': /* date */
2695                                         if (ast_localtime(&ts, &tm, NULL)) {
2696                                                 ast_strftime(tmp, sizeof(tmp), "%Y-%m-%d", &tm);
2697                                                 ast_str_append(&prompt, 0, "%s", tmp);
2698                                                 cli_prompt_changes++;
2699                                         }
2700                                         break;
2701                                 case 'g': /* group */
2702                                         if ((gr = getgrgid(getgid()))) {
2703                                                 ast_str_append(&prompt, 0, "%s", gr->gr_name);
2704                                         }
2705                                         break;
2706                                 case 'h': /* hostname */
2707                                         if (!gethostname(hostname, sizeof(hostname) - 1)) {
2708                                                 ast_str_append(&prompt, 0, "%s", hostname);
2709                                         } else {
2710                                                 ast_str_append(&prompt, 0, "%s", "localhost");
2711                                         }
2712                                         break;
2713                                 case 'H': /* short hostname */
2714                                         if (!gethostname(hostname, sizeof(hostname) - 1)) {
2715                                                 char *dotptr;
2716                                                 if ((dotptr = strchr(hostname, '.'))) {
2717                                                         *dotptr = '\0';
2718                                                 }
2719                                                 ast_str_append(&prompt, 0, "%s", hostname);
2720                                         } else {
2721                                                 ast_str_append(&prompt, 0, "%s", "localhost");
2722                                         }
2723                                         break;
2724 #ifdef HAVE_GETLOADAVG
2725                                 case 'l': /* load avg */
2726                                         t++;
2727                                         if (sscanf(t, "%30d", &which) == 1 && which > 0 && which <= 3) {
2728                                                 double list[3];
2729                                                 getloadavg(list, 3);
2730                                                 ast_str_append(&prompt, 0, "%.2f", list[which - 1]);
2731                                                 cli_prompt_changes++;
2732                                         }
2733                                         break;
2734 #endif
2735                                 case 's': /* Asterisk system name (from asterisk.conf) */
2736                                         ast_str_append(&prompt, 0, "%s", ast_config_AST_SYSTEM_NAME);
2737                                         break;
2738                                 case 't': /* time */
2739                                         if (ast_localtime(&ts, &tm, NULL)) {
2740                                                 ast_strftime(tmp, sizeof(tmp), "%H:%M:%S", &tm);
2741                                                 ast_str_append(&prompt, 0, "%s", tmp);
2742                                                 cli_prompt_changes++;
2743                                         }
2744                                         break;
2745                                 case 'u': /* username */
2746                                         if ((pw = getpwuid(getuid()))) {
2747                                                 ast_str_append(&prompt, 0, "%s", pw->pw_name);
2748                                         }
2749                                         break;
2750                                 case '#': /* process console or remote? */
2751                                         ast_str_append(&prompt, 0, "%c", ast_opt_remote ? '>' : '#');
2752                                         break;
2753                                 case '%': /* literal % */
2754                                         ast_str_append(&prompt, 0, "%c", '%');
2755                                         break;
2756                                 case '\0': /* % is last character - prevent bug */
2757                                         t--;
2758                                         break;
2759                                 }
2760                         } else {
2761                                 ast_str_append(&prompt, 0, "%c", *t);
2762                         }
2763                         t++;
2764                 }
2765                 if (color_used) {
2766                         /* Force colors back to normal at end */
2767                         ast_term_color_code(&prompt, 0, 0);
2768                 }
2769         } else if (remotehostname) {
2770                 ast_str_set(&prompt, 0, ASTERISK_PROMPT2, remotehostname);
2771         } else {
2772                 ast_str_set(&prompt, 0, "%s", ASTERISK_PROMPT);
2773         }
2774
2775         return ast_str_buffer(prompt);
2776 }
2777
2778 static char **ast_el_strtoarr(char *buf)
2779 {
2780         char **match_list = NULL, **match_list_tmp, *retstr;
2781         size_t match_list_len;
2782         int matches = 0;
2783
2784         match_list_len = 1;
2785         while ( (retstr = strsep(&buf, " ")) != NULL) {
2786
2787                 if (!strcmp(retstr, AST_CLI_COMPLETE_EOF))
2788                         break;
2789                 if (matches + 1 >= match_list_len) {
2790                         match_list_len <<= 1;
2791                         if ((match_list_tmp = ast_realloc(match_list, match_list_len * sizeof(char *)))) {
2792                                 match_list = match_list_tmp;
2793                         } else {
2794                                 if (match_list)
2795                                         ast_free(match_list);
2796                                 return (char **) NULL;
2797                         }
2798                 }
2799
2800                 match_list[matches++] = ast_strdup(retstr);
2801         }
2802
2803         if (!match_list)
2804                 return (char **) NULL;
2805
2806         if (matches >= match_list_len) {
2807                 if ((match_list_tmp = ast_realloc(match_list, (match_list_len + 1) * sizeof(char *)))) {
2808                         match_list = match_list_tmp;
2809                 } else {
2810                         if (match_list)
2811                                 ast_free(match_list);
2812                         return (char **) NULL;
2813                 }
2814         }
2815
2816         match_list[matches] = (char *) NULL;
2817
2818         return match_list;
2819 }
2820
2821 static int ast_el_sort_compare(const void *i1, const void *i2)
2822 {
2823         char *s1, *s2;
2824
2825         s1 = ((char **)i1)[0];
2826         s2 = ((char **)i2)[0];
2827
2828         return strcasecmp(s1, s2);
2829 }
2830
2831 static int ast_cli_display_match_list(char **matches, int len, int max)
2832 {
2833         int i, idx, limit, count;
2834         int screenwidth = 0;
2835         int numoutput = 0, numoutputline = 0;
2836
2837         screenwidth = ast_get_termcols(STDOUT_FILENO);
2838
2839         /* find out how many entries can be put on one line, with two spaces between strings */
2840         limit = screenwidth / (max + 2);
2841         if (limit == 0)
2842                 limit = 1;
2843
2844         /* how many lines of output */
2845         count = len / limit;
2846         if (count * limit < len)
2847                 count++;
2848
2849         idx = 1;
2850
2851         qsort(&matches[0], (size_t)(len), sizeof(char *), ast_el_sort_compare);
2852
2853         for (; count > 0; count--) {
2854                 numoutputline = 0;
2855                 for (i = 0; i < limit && matches[idx]; i++, idx++) {
2856
2857                         /* Don't print dupes */
2858                         if ( (matches[idx+1] != NULL && strcmp(matches[idx], matches[idx+1]) == 0 ) ) {
2859                                 i--;
2860                                 ast_free(matches[idx]);
2861                                 matches[idx] = NULL;
2862                                 continue;
2863                         }
2864
2865                         numoutput++;
2866                         numoutputline++;
2867                         fprintf(stdout, "%-*s  ", max, matches[idx]);
2868                         ast_free(matches[idx]);
2869                         matches[idx] = NULL;
2870                 }
2871                 if (numoutputline > 0)
2872                         fprintf(stdout, "\n");
2873         }
2874
2875         return numoutput;
2876 }
2877
2878
2879 static char *cli_complete(EditLine *editline, int ch)
2880 {
2881         int len = 0;
2882         char *ptr;
2883         int nummatches = 0;
2884         char **matches;
2885         int retval = CC_ERROR;
2886         char buf[2048], savechr;
2887         int res;
2888
2889         LineInfo *lf = (LineInfo *)el_line(editline);
2890
2891         savechr = *(char *)lf->cursor;
2892         *(char *)lf->cursor = '\0';
2893         ptr = (char *)lf->cursor;
2894         if (ptr) {
2895                 while (ptr > lf->buffer) {
2896                         if (isspace(*ptr)) {
2897                                 ptr++;
2898                                 break;
2899                         }
2900                         ptr--;
2901                 }
2902         }
2903
2904         len = lf->cursor - ptr;
2905
2906         if (ast_opt_remote) {
2907                 snprintf(buf, sizeof(buf), "_COMMAND NUMMATCHES \"%s\" \"%s\"", lf->buffer, ptr);
2908                 fdsend(ast_consock, buf);
2909                 if ((res = read(ast_consock, buf, sizeof(buf) - 1)) < 0) {
2910                         return (char*)(CC_ERROR);
2911                 }
2912                 buf[res] = '\0';
2913                 nummatches = atoi(buf);
2914
2915                 if (nummatches > 0) {
2916                         char *mbuf;
2917                         int mlen = 0, maxmbuf = 2048;
2918                         /* Start with a 2048 byte buffer */
2919                         if (!(mbuf = ast_malloc(maxmbuf))) {
2920                                 *((char *) lf->cursor) = savechr;
2921                                 return (char *)(CC_ERROR);
2922                         }
2923                         snprintf(buf, sizeof(buf), "_COMMAND MATCHESARRAY \"%s\" \"%s\"", lf->buffer, ptr);
2924                         fdsend(ast_consock, buf);
2925                         res = 0;
2926                         mbuf[0] = '\0';
2927                         while (!strstr(mbuf, AST_CLI_COMPLETE_EOF) && res != -1) {
2928                                 if (mlen + 1024 > maxmbuf) {
2929                                         /* Every step increment buffer 1024 bytes */
2930                                         maxmbuf += 1024;
2931                                         if (!(mbuf = ast_realloc(mbuf, maxmbuf))) {
2932                                                 *((char *) lf->cursor) = savechr;
2933                                                 return (char *)(CC_ERROR);
2934                                         }
2935                                 }
2936                                 /* Only read 1024 bytes at a time */
2937                                 res = read(ast_consock, mbuf + mlen, 1024);
2938                                 if (res > 0)
2939                                         mlen += res;
2940                         }
2941                         mbuf[mlen] = '\0';
2942
2943                         matches = ast_el_strtoarr(mbuf);
2944                         ast_free(mbuf);
2945                 } else
2946                         matches = (char **) NULL;
2947         } else {
2948                 char **p, *oldbuf=NULL;
2949                 nummatches = 0;
2950                 matches = ast_cli_completion_matches((char *)lf->buffer,ptr);
2951                 for (p = matches; p && *p; p++) {
2952                         if (!oldbuf || strcmp(*p,oldbuf))
2953                                 nummatches++;
2954                         oldbuf = *p;
2955                 }
2956         }
2957
2958         if (matches) {
2959                 int i;
2960                 int matches_num, maxlen, match_len;
2961
2962                 if (matches[0][0] != '\0') {
2963                         el_deletestr(editline, (int) len);
2964                         el_insertstr(editline, matches[0]);
2965                         retval = CC_REFRESH;
2966                 }
2967
2968                 if (nummatches == 1) {
2969                         /* Found an exact match */
2970                         el_insertstr(editline, " ");
2971                         retval = CC_REFRESH;
2972                 } else {
2973                         /* Must be more than one match */
2974                         for (i = 1, maxlen = 0; matches[i]; i++) {
2975                                 match_len = strlen(matches[i]);
2976                                 if (match_len > maxlen)
2977                                         maxlen = match_len;
2978                         }
2979                         matches_num = i - 1;
2980                         if (matches_num >1) {
2981                                 fprintf(stdout, "\n");
2982                                 ast_cli_display_match_list(matches, nummatches, maxlen);
2983                                 retval = CC_REDISPLAY;
2984                         } else {
2985                                 el_insertstr(editline," ");
2986                                 retval = CC_REFRESH;
2987                         }
2988                 }
2989                 for (i = 0; matches[i]; i++)
2990                         ast_free(matches[i]);
2991                 ast_free(matches);
2992         }
2993
2994         *((char *) lf->cursor) = savechr;
2995
2996         return (char *)(long)retval;
2997 }
2998
2999 static int ast_el_initialize(void)
3000 {
3001         HistEvent ev;
3002         char *editor, *editrc = getenv("EDITRC");
3003
3004         if (!(editor = getenv("AST_EDITMODE"))) {
3005                 if (!(editor = getenv("AST_EDITOR"))) {
3006                         editor = "emacs";
3007                 }
3008         }
3009
3010         if (el != NULL)
3011                 el_end(el);
3012         if (el_hist != NULL)
3013                 history_end(el_hist);
3014
3015         el = el_init("asterisk", stdin, stdout, stderr);
3016         el_set(el, EL_PROMPT, cli_prompt);
3017
3018         el_set(el, EL_EDITMODE, 1);
3019         el_set(el, EL_EDITOR, editor);
3020         el_hist = history_init();
3021         if (!el || !el_hist)
3022                 return -1;
3023
3024         /* setup history with 100 entries */
3025         history(el_hist, &ev, H_SETSIZE, 100);
3026
3027         el_set(el, EL_HIST, history, el_hist);
3028
3029         el_set(el, EL_ADDFN, "ed-complete", "Complete argument", cli_complete);
3030         /* Bind <tab> to command completion */
3031         el_set(el, EL_BIND, "^I", "ed-complete", NULL);
3032         /* Bind ? to command completion */
3033         el_set(el, EL_BIND, "?", "ed-complete", NULL);
3034         /* Bind ^D to redisplay */
3035         el_set(el, EL_BIND, "^D", "ed-redisplay", NULL);
3036         /* Bind Delete to delete char left */
3037         el_set(el, EL_BIND, "\\e[3~", "ed-delete-next-char", NULL);
3038         /* Bind Home and End to move to line start and end */
3039         el_set(el, EL_BIND, "\\e[1~", "ed-move-to-beg", NULL);
3040         el_set(el, EL_BIND, "\\e[4~", "ed-move-to-end", NULL);
3041         /* Bind C-left and C-right to move by word (not all terminals) */
3042         el_set(el, EL_BIND, "\\eOC", "vi-next-word", NULL);
3043         el_set(el, EL_BIND, "\\eOD", "vi-prev-word", NULL);
3044
3045         if (editrc) {
3046                 el_source(el, editrc);
3047         }
3048
3049         return 0;
3050 }
3051
3052 #define MAX_HISTORY_COMMAND_LENGTH 256
3053
3054 static int ast_el_add_history(char *buf)
3055 {
3056         HistEvent ev;
3057         char *stripped_buf;
3058
3059         if (el_hist == NULL || el == NULL) {
3060                 ast_el_initialize();
3061         }
3062         if (strlen(buf) > (MAX_HISTORY_COMMAND_LENGTH - 1)) {
3063                 return 0;
3064         }
3065
3066         stripped_buf = ast_strip(ast_strdupa(buf));
3067
3068         /* HISTCONTROL=ignoredups */
3069         if (!history(el_hist, &ev, H_FIRST) && strcmp(ev.str, stripped_buf) == 0) {
3070                 return 0;
3071         }
3072
3073         return history(el_hist, &ev, H_ENTER, stripped_buf);
3074 }
3075
3076 static int ast_el_write_history(char *filename)
3077 {
3078         HistEvent ev;
3079
3080         if (el_hist == NULL || el == NULL)
3081                 ast_el_initialize();
3082
3083         return (history(el_hist, &ev, H_SAVE, filename));
3084 }
3085
3086 static int ast_el_read_history(char *filename)
3087 {
3088         HistEvent ev;
3089
3090         if (el_hist == NULL || el == NULL) {
3091                 ast_el_initialize();
3092         }
3093
3094         return history(el_hist, &ev, H_LOAD, filename);
3095 }
3096
3097 static void ast_remotecontrol(char *data)
3098 {
3099         char buf[80];
3100         int res;
3101         char filename[80] = "";
3102         char *hostname;
3103         char *cpid;
3104         char *version;
3105         int pid;
3106         char *stringp = NULL;
3107
3108         char *ebuf;
3109         int num = 0;
3110
3111         memset(&sig_flags, 0, sizeof(sig_flags));
3112         signal(SIGINT, __remote_quit_handler);
3113         signal(SIGTERM, __remote_quit_handler);
3114         signal(SIGHUP, __remote_quit_handler);
3115
3116         if (read(ast_consock, buf, sizeof(buf)) < 0) {
3117                 ast_log(LOG_ERROR, "read() failed: %s\n", strerror(errno));
3118                 return;
3119         }
3120         if (data) {
3121                 char prefix[] = "cli quit after ";
3122                 char *tmp = ast_alloca(strlen(data) + strlen(prefix) + 1);
3123                 sprintf(tmp, "%s%s", prefix, data);
3124                 if (write(ast_consock, tmp, strlen(tmp) + 1) < 0) {
3125                         ast_log(LOG_ERROR, "write() failed: %s\n", strerror(errno));
3126                         if (sig_flags.need_quit || sig_flags.need_quit_handler) {
3127                                 return;
3128                         }
3129                 }
3130         }
3131         stringp = buf;
3132         hostname = strsep(&stringp, "/");
3133         cpid = strsep(&stringp, "/");
3134         version = strsep(&stringp, "\n");
3135         if (!version)
3136                 version = "<Version Unknown>";
3137         stringp = hostname;
3138         strsep(&stringp, ".");
3139         if (cpid)
3140                 pid = atoi(cpid);
3141         else
3142                 pid = -1;
3143         if (!data) {
3144                 if (!ast_opt_mute) {
3145                         fdsend(ast_consock, "logger mute silent");
3146                 } else {
3147                         printf("log and verbose output currently muted ('logger mute' to unmute)\n");
3148                 }
3149         }
3150
3151         if (ast_opt_exec && data) {  /* hack to print output then exit if asterisk -rx is used */
3152                 int linefull = 1, prev_linefull = 1, prev_line_verbose = 0;
3153                 struct pollfd fds;
3154                 fds.fd = ast_consock;
3155                 fds.events = POLLIN;
3156                 fds.revents = 0;
3157
3158                 while (ast_poll(&fds, 1, 60000) > 0) {
3159                         char buffer[512] = "", *curline = buffer, *nextline;
3160                         int not_written = 1;
3161
3162                         if (sig_flags.need_quit || sig_flags.need_quit_handler) {
3163                                 break;
3164                         }
3165
3166                         if (read(ast_consock, buffer, sizeof(buffer) - 1) <= 0) {
3167                                 break;
3168                         }
3169
3170                         do {
3171                                 prev_linefull = linefull;
3172                                 if ((nextline = strchr(curline, '\n'))) {
3173                                         linefull = 1;
3174                                         nextline++;
3175                                 } else {
3176                                         linefull = 0;
3177                                         nextline = strchr(curline, '\0');
3178                                 }
3179
3180                                 /* Skip verbose lines */
3181                                 /* Prev line full? | Line is verbose | Last line verbose? | Print
3182                                  * TRUE            | TRUE*           | TRUE               | FALSE
3183                                  * TRUE            | TRUE*           | FALSE              | FALSE
3184                                  * TRUE            | FALSE*          | TRUE               | TRUE
3185                                  * TRUE            | FALSE*          | FALSE              | TRUE
3186                                  * FALSE           | TRUE            | TRUE*              | FALSE
3187                                  * FALSE           | TRUE            | FALSE*             | TRUE
3188                                  * FALSE           | FALSE           | TRUE*              | FALSE
3189                                  * FALSE           | FALSE           | FALSE*             | TRUE
3190                                  */
3191                                 if ((!prev_linefull && !prev_line_verbose) || (prev_linefull && *curline > 0)) {
3192                                         prev_line_verbose = 0;
3193                                         not_written = 0;
3194                                         if (write(STDOUT_FILENO, curline, nextline - curline) < 0) {
3195                                                 ast_log(LOG_WARNING, "write() failed: %s\n", strerror(errno));
3196                                         }
3197                                 } else {
3198                                         prev_line_verbose = 1;
3199                                 }
3200                                 curline = nextline;
3201                         } while (!ast_strlen_zero(curline));
3202
3203                         /* No non-verbose output in 60 seconds. */
3204                         if (not_written) {
3205                                 break;
3206                         }
3207                 }
3208                 return;
3209         }
3210
3211         ast_verbose("Connected to Asterisk %s currently running on %s (pid = %d)\n", version, hostname, pid);
3212         remotehostname = hostname;
3213         if (getenv("HOME"))
3214                 snprintf(filename, sizeof(filename), "%s/.asterisk_history", getenv("HOME"));
3215         if (el_hist == NULL || el == NULL)
3216                 ast_el_initialize();
3217
3218         el_set(el, EL_GETCFN, ast_el_read_char);
3219
3220         if (!ast_strlen_zero(filename))
3221                 ast_el_read_history(filename);
3222
3223         for (;;) {
3224                 ebuf = (char *)el_gets(el, &num);
3225
3226                 if (sig_flags.need_quit || sig_flags.need_quit_handler) {
3227                         break;
3228                 }
3229
3230                 if (!ebuf && write(1, "", 1) < 0)
3231                         break;
3232
3233                 if (!ast_strlen_zero(ebuf)) {
3234                         if (ebuf[strlen(ebuf)-1] == '\n')
3235                                 ebuf[strlen(ebuf)-1] = '\0';
3236                         if (!remoteconsolehandler(ebuf)) {
3237                                 res = write(ast_consock, ebuf, strlen(ebuf) + 1);
3238                                 if (res < 1) {
3239                                         ast_log(LOG_WARNING, "Unable to write: %s\n", strerror(errno));
3240                                         break;
3241                                 }
3242                         }
3243                 }
3244         }
3245         printf("\nDisconnected from Asterisk server\n");
3246 }
3247
3248 static int show_version(void)
3249 {
3250         printf("Asterisk %s\n", ast_get_version());
3251         return 0;
3252 }
3253
3254 static int show_cli_help(void)
3255 {
3256         printf("Asterisk %s, Copyright (C) 1999 - 2013, Digium, Inc. and others.\n", ast_get_version());
3257         printf("Usage: asterisk [OPTIONS]\n");
3258         printf("Valid Options:\n");
3259         printf("   -V              Display version number and exit\n");
3260         printf("   -C <configfile> Use an alternate configuration file\n");
3261         printf("   -G <group>      Run as a group other than the caller\n");
3262         printf("   -U <user>       Run as a user other than the caller\n");
3263         printf("   -c              Provide console CLI\n");
3264         printf("   -d              Enable extra debugging\n");
3265 #if HAVE_WORKING_FORK
3266         printf("   -f              Do not fork\n");
3267         printf("   -F              Always fork\n");
3268 #endif
3269         printf("   -g              Dump core in case of a crash\n");
3270         printf("   -h              This help screen\n");
3271         printf("   -i              Initialize crypto keys at startup\n");
3272         printf("   -I              Enable internal timing if DAHDI timer is available\n");
3273         printf("   -L <load>       Limit the maximum load average before rejecting new calls\n");
3274         printf("   -M <value>      Limit the maximum number of calls to the specified value\n");
3275         printf("   -m              Mute debugging and console output on the console\n");
3276         printf("   -n              Disable console colorization\n");
3277         printf("   -p              Run as pseudo-realtime thread\n");
3278         printf("   -q              Quiet mode (suppress output)\n");
3279         printf("   -r              Connect to Asterisk on this machine\n");
3280         printf("   -R              Same as -r, except attempt to reconnect if disconnected\n");
3281         printf("   -s <socket>     Connect to Asterisk via socket <socket> (only valid with -r)\n");
3282         printf("   -t              Record soundfiles in /var/tmp and move them where they\n");
3283         printf("                   belong after they are done\n");
3284         printf("   -T              Display the time in [Mmm dd hh:mm:ss] format for each line\n");
3285         printf("                   of output to the CLI\n");
3286         printf("   -v              Increase verbosity (multiple v's = more verbose)\n");
3287         printf("   -x <cmd>        Execute command <cmd> (implies -r)\n");
3288         printf("   -X              Execute includes by default (allows #exec in asterisk.conf)\n");
3289         printf("   -W              Adjust terminal colors to compensate for a light background\n");
3290         printf("\n");
3291         return 0;
3292 }
3293
3294 static void ast_readconfig(void)
3295 {
3296         struct ast_config *cfg;
3297         struct ast_variable *v;
3298         char *config = DEFAULT_CONFIG_FILE;
3299         char hostname[MAXHOSTNAMELEN] = "";
3300         struct ast_flags config_flags = { CONFIG_FLAG_NOREALTIME };
3301         struct {
3302                 unsigned int dbdir:1;
3303                 unsigned int keydir:1;
3304         } found = { 0, 0 };
3305
3306         /* Set default value */
3307         option_dtmfminduration = AST_MIN_DTMF_DURATION;
3308
3309         if (ast_opt_override_config) {
3310                 cfg = ast_config_load2(ast_config_AST_CONFIG_FILE, "" /* core, can't reload */, config_flags);
3311                 if (cfg == CONFIG_STATUS_FILEMISSING || cfg == CONFIG_STATUS_FILEUNCHANGED || cfg == CONFIG_STATUS_FILEINVALID) {
3312                         fprintf(stderr, "Unable to open specified master config file '%s', using built-in defaults\n", ast_config_AST_CONFIG_FILE);
3313                 }
3314         } else {
3315                 cfg = ast_config_load2(config, "" /* core, can't reload */, config_flags);
3316         }
3317
3318         /* init with buildtime config */
3319         ast_copy_string(cfg_paths.config_dir, DEFAULT_CONFIG_DIR, sizeof(cfg_paths.config_dir));
3320         ast_copy_string(cfg_paths.spool_dir, DEFAULT_SPOOL_DIR, sizeof(cfg_paths.spool_dir));
3321         ast_copy_string(cfg_paths.module_dir, DEFAULT_MODULE_DIR, sizeof(cfg_paths.module_dir));
3322         snprintf(cfg_paths.monitor_dir, sizeof(cfg_paths.monitor_dir), "%s/monitor", cfg_paths.spool_dir);
3323         snprintf(cfg_paths.recording_dir, sizeof(cfg_paths.recording_dir), "%s/recording", cfg_paths.spool_dir);
3324         ast_copy_string(cfg_paths.var_dir, DEFAULT_VAR_DIR, sizeof(cfg_paths.var_dir));
3325         ast_copy_string(cfg_paths.data_dir, DEFAULT_DATA_DIR, sizeof(cfg_paths.data_dir));
3326         ast_copy_string(cfg_paths.log_dir, DEFAULT_LOG_DIR, sizeof(cfg_paths.log_dir));
3327         ast_copy_string(cfg_paths.agi_dir, DEFAULT_AGI_DIR, sizeof(cfg_paths.agi_dir));
3328         ast_copy_string(cfg_paths.db_path, DEFAULT_DB, sizeof(cfg_paths.db_path));
3329         ast_copy_string(cfg_paths.sbin_dir, DEFAULT_SBIN_DIR, sizeof(cfg_paths.sbin_dir));
3330         ast_copy_string(cfg_paths.key_dir, DEFAULT_KEY_DIR, sizeof(cfg_paths.key_dir));
3331         ast_copy_string(cfg_paths.pid_path, DEFAULT_PID, sizeof(cfg_paths.pid_path));
3332         ast_copy_string(cfg_paths.socket_path, DEFAULT_SOCKET, sizeof(cfg_paths.socket_path));
3333         ast_copy_string(cfg_paths.run_dir, DEFAULT_RUN_DIR, sizeof(cfg_paths.run_dir));
3334
3335         ast_set_default_eid(&ast_eid_default);
3336
3337         /* no asterisk.conf? no problem, use buildtime config! */
3338         if (cfg == CONFIG_STATUS_FILEMISSING || cfg == CONFIG_STATUS_FILEUNCHANGED || cfg == CONFIG_STATUS_FILEINVALID) {
3339                 return;
3340         }
3341
3342         for (v = ast_variable_browse(cfg, "files"); v; v = v->next) {
3343                 if (!strcasecmp(v->name, "astctlpermissions"))
3344                         ast_copy_string(ast_config_AST_CTL_PERMISSIONS, v->value, sizeof(ast_config_AST_CTL_PERMISSIONS));
3345                 else if (!strcasecmp(v->name, "astctlowner"))
3346                         ast_copy_string(ast_config_AST_CTL_OWNER, v->value, sizeof(ast_config_AST_CTL_OWNER));
3347                 else if (!strcasecmp(v->name, "astctlgroup"))
3348                         ast_copy_string(ast_config_AST_CTL_GROUP, v->value, sizeof(ast_config_AST_CTL_GROUP));
3349                 else if (!strcasecmp(v->name, "astctl"))
3350                         ast_copy_string(ast_config_AST_CTL, v->value, sizeof(ast_config_AST_CTL));
3351         }
3352
3353         for (v = ast_variable_browse(cfg, "directories"); v; v = v->next) {
3354                 if (!strcasecmp(v->name, "astetcdir")) {
3355                         ast_copy_string(cfg_paths.config_dir, v->value, sizeof(cfg_paths.config_dir));
3356                 } else if (!strcasecmp(v->name, "astspooldir")) {
3357                         ast_copy_string(cfg_paths.spool_dir, v->value, sizeof(cfg_paths.spool_dir));
3358                         snprintf(cfg_paths.monitor_dir, sizeof(cfg_paths.monitor_dir), "%s/monitor", v->value);
3359                         snprintf(cfg_paths.recording_dir, sizeof(cfg_paths.recording_dir), "%s/recording", v->value);
3360                 } else if (!strcasecmp(v->name, "astvarlibdir")) {
3361                         ast_copy_string(cfg_paths.var_dir, v->value, sizeof(cfg_paths.var_dir));
3362                         if (!found.dbdir)
3363                                 snprintf(cfg_paths.db_path, sizeof(cfg_paths.db_path), "%s/astdb", v->value);
3364                 } else if (!strcasecmp(v->name, "astdbdir")) {
3365                         snprintf(cfg_paths.db_path, sizeof(cfg_paths.db_path), "%s/astdb", v->value);
3366                         found.dbdir = 1;
3367                 } else if (!strcasecmp(v->name, "astdatadir")) {
3368                         ast_copy_string(cfg_paths.data_dir, v->value, sizeof(cfg_paths.data_dir));
3369                         if (!found.keydir)
3370                                 snprintf(cfg_paths.key_dir, sizeof(cfg_paths.key_dir), "%s/keys", v->value);
3371                 } else if (!strcasecmp(v->name, "astkeydir")) {
3372                         snprintf(cfg_paths.key_dir, sizeof(cfg_paths.key_dir), "%s/keys", v->value);
3373                         found.keydir = 1;
3374                 } else if (!strcasecmp(v->name, "astlogdir")) {
3375                         ast_copy_string(cfg_paths.log_dir, v->value, sizeof(cfg_paths.log_dir));
3376                 } else if (!strcasecmp(v->name, "astagidir")) {
3377                         ast_copy_string(cfg_paths.agi_dir, v->value, sizeof(cfg_paths.agi_dir));
3378                 } else if (!strcasecmp(v->name, "astrundir")) {
3379                         snprintf(cfg_paths.pid_path, sizeof(cfg_paths.pid_path), "%s/%s", v->value, "asterisk.pid");
3380                         snprintf(cfg_paths.socket_path, sizeof(cfg_paths.socket_path), "%s/%s", v->value, ast_config_AST_CTL);
3381                         ast_copy_string(cfg_paths.run_dir, v->value, sizeof(cfg_paths.run_dir));
3382                 } else if (!strcasecmp(v->name, "astmoddir")) {
3383                         ast_copy_string(cfg_paths.module_dir, v->value, sizeof(cfg_paths.module_dir));
3384                 } else if (!strcasecmp(v->name, "astsbindir")) {
3385                         ast_copy_string(cfg_paths.sbin_dir, v->value, sizeof(cfg_paths.sbin_dir));
3386                 }
3387         }
3388
3389         for (v = ast_variable_browse(cfg, "options"); v; v = v->next) {
3390                 /* verbose level (-v at startup) */
3391                 if (!strcasecmp(v->name, "verbose")) {
3392                         option_verbose = atoi(v->value);
3393                 /* whether or not to force timestamping in CLI verbose output. (-T at startup) */
3394                 } else if (!strcasecmp(v->name, "timestamp")) {
3395                         ast_set2_flag(&ast_options, ast_true(v->value), AST_OPT_FLAG_TIMESTAMP);
3396                 /* whether or not to support #exec in config files */
3397                 } else if (!strcasecmp(v->name, "execincludes")) {
3398                         ast_set2_flag(&ast_options, ast_true(v->value), AST_OPT_FLAG_EXEC_INCLUDES);
3399                 /* debug level (-d at startup) */
3400                 } else if (!strcasecmp(v->name, "debug")) {
3401                         option_debug = 0;
3402                         if (sscanf(v->value, "%30d", &option_debug) != 1) {
3403                                 option_debug = ast_true(v->value);
3404                         }
3405 #if HAVE_WORKING_FORK
3406                 /* Disable forking (-f at startup) */
3407                 } else if (!strcasecmp(v->name, "nofork")) {
3408                         ast_set2_flag(&ast_options, ast_true(v->value), AST_OPT_FLAG_NO_FORK);
3409                 /* Always fork, even if verbose or debug are enabled (-F at startup) */
3410                 } else if (!strcasecmp(v->name, "alwaysfork")) {
3411                         ast_set2_flag(&ast_options, ast_true(v->value), AST_OPT_FLAG_ALWAYS_FORK);
3412 #endif
3413                 /* Run quietly (-q at startup ) */
3414                 } else if (!strcasecmp(v->name, "quiet")) {
3415                         ast_set2_flag(&ast_options, ast_true(v->value), AST_OPT_FLAG_QUIET);
3416                 /* Run as console (-c at startup, implies nofork) */
3417                 } else if (!strcasecmp(v->name, "console")) {
3418                         ast_set2_flag(&ast_options, ast_true(v->value), AST_OPT_FLAG_NO_FORK | AST_OPT_FLAG_CONSOLE);
3419                 /* Run with high priority if the O/S permits (-p at startup) */
3420                 } else if (!strcasecmp(v->name, "highpriority")) {
3421                         ast_set2_flag(&ast_options, ast_true(v->value), AST_OPT_FLAG_HIGH_PRIORITY);
3422                 /* Initialize RSA auth keys (IAX2) (-i at startup) */
3423                 } else if (!strcasecmp(v->name, "initcrypto")) {
3424                         ast_set2_flag(&ast_options, ast_true(v->value), AST_OPT_FLAG_INIT_KEYS);
3425                 /* Disable ANSI colors for console (-c at startup) */
3426                 } else if (!strcasecmp(v->name, "nocolor")) {
3427                         ast_set2_flag(&ast_options, ast_true(v->value), AST_OPT_FLAG_NO_COLOR);
3428                 /* Disable some usage warnings for picky people :p */
3429                 } else if (!strcasecmp(v->name, "dontwarn")) {
3430                         ast_set2_flag(&ast_options, ast_true(v->value), AST_OPT_FLAG_DONT_WARN);
3431                 /* Dump core in case of crash (-g) */
3432                 } else if (!strcasecmp(v->name, "dumpcore")) {
3433                         ast_set2_flag(&ast_options, ast_true(v->value), AST_OPT_FLAG_DUMP_CORE);
3434                 /* Cache recorded sound files to another directory during recording */
3435                 } else if (!strcasecmp(v->name, "cache_record_files")) {
3436                         ast_set2_flag(&ast_options, ast_true(v->value), AST_OPT_FLAG_CACHE_RECORD_FILES);
3437                 /* Specify cache directory */
3438                 }  else if (!strcasecmp(v->name, "record_cache_dir")) {
3439                         ast_copy_string(record_cache_dir, v->value, AST_CACHE_DIR_LEN);
3440                 /* Build transcode paths via SLINEAR, instead of directly */
3441                 } else if (!strcasecmp(v->name, "transcode_via_sln")) {
3442                         ast_set2_flag(&ast_options, ast_true(v->value), AST_OPT_FLAG_TRANSCODE_VIA_SLIN);
3443                 /* Transmit SLINEAR silence while a channel is being recorded or DTMF is being generated on a channel */
3444                 } else if (!strcasecmp(v->name, "transmit_silence_during_record") || !strcasecmp(v->name, "transmit_silence")) {
3445                         ast_set2_flag(&ast_options, ast_true(v->value), AST_OPT_FLAG_TRANSMIT_SILENCE);
3446                 /* Enable internal timing */
3447                 } else if (!strcasecmp(v->name, "internal_timing")) {
3448                         ast_set2_flag(&ast_options, ast_true(v->value), AST_OPT_FLAG_INTERNAL_TIMING);
3449                 } else if (!strcasecmp(v->name, "mindtmfduration")) {
3450                         if (sscanf(v->value, "%30u", &option_dtmfminduration) != 1) {
3451                                 option_dtmfminduration = AST_MIN_DTMF_DURATION;
3452                         }
3453                 } else if (!strcasecmp(v->name, "maxcalls")) {
3454                         if ((sscanf(v->value, "%30d", &ast_option_maxcalls) != 1) || (ast_option_maxcalls < 0)) {
3455                                 ast_option_maxcalls = 0;
3456                         }
3457                 } else if (!strcasecmp(v->name, "maxload")) {
3458                         double test[1];
3459
3460                         if (getloadavg(test, 1) == -1) {
3461                                 ast_log(LOG_ERROR, "Cannot obtain load average on this system. 'maxload' option disabled.\n");
3462                                 ast_option_maxload = 0.0;
3463                         } else if ((sscanf(v->value, "%30lf", &ast_option_maxload) != 1) || (ast_option_maxload < 0.0)) {
3464                                 ast_option_maxload = 0.0;
3465                         }
3466                 /* Set the maximum amount of open files */
3467                 } else if (!strcasecmp(v->name, "maxfiles")) {
3468                         ast_option_maxfiles = atoi(v->value);
3469                         set_ulimit(ast_option_maxfiles);
3470                 /* What user to run as */
3471                 } else if (!strcasecmp(v->name, "runuser")) {
3472                         ast_copy_string(cfg_paths.run_user, v->value, sizeof(cfg_paths.run_user));
3473                 /* What group to run as */
3474                 } else if (!strcasecmp(v->name, "rungroup")) {
3475                         ast_copy_string(cfg_paths.run_group, v->value, sizeof(cfg_paths.run_group));
3476                 } else if (!strcasecmp(v->name, "systemname")) {
3477                         ast_copy_string(cfg_paths.system_name, v->value, sizeof(cfg_paths.system_name));
3478                 } else if (!strcasecmp(v->name, "autosystemname")) {
3479                         if (ast_true(v->value)) {
3480                                 if (!gethostname(hostname, sizeof(hostname) - 1))
3481                                         ast_copy_string(cfg_paths.system_name, hostname, sizeof(cfg_paths.system_name));
3482                                 else {
3483                                         if (ast_strlen_zero(ast_config_AST_SYSTEM_NAME)){
3484                                                 ast_copy_string(cfg_paths.system_name, "localhost", sizeof(cfg_paths.system_name));
3485                                         }
3486                                         ast_log(LOG_ERROR, "Cannot obtain hostname for this system.  Using '%s' instead.\n", ast_config_AST_SYSTEM_NAME);
3487                                 }
3488                         }
3489                 } else if (!strcasecmp(v->name, "languageprefix")) {
3490                         ast_language_is_prefix = ast_true(v->value);
3491                 } else if (!strcasecmp(v->name, "defaultlanguage")) {
3492                         ast_copy_string(ast_defaultlanguage, v->value, MAX_LANGUAGE);
3493                 } else if (!strcasecmp(v->name, "lockmode")) {
3494                         if (!strcasecmp(v->value, "lockfile")) {
3495                                 ast_set_lock_type(AST_LOCK_TYPE_LOCKFILE);
3496                         } else if (!strcasecmp(v->value, "flock")) {
3497                                 ast_set_lock_type(AST_LOCK_TYPE_FLOCK);
3498                         } else {
3499                                 ast_log(LOG_WARNING, "'%s' is not a valid setting for the lockmode option, "
3500                                         "defaulting to 'lockfile'\n", v->value);
3501                                 ast_set_lock_type(AST_LOCK_TYPE_LOCKFILE);
3502                         }
3503 #if defined(HAVE_SYSINFO)
3504                 } else if (!strcasecmp(v->name, "minmemfree")) {
3505                         /* specify the minimum amount of free memory to retain.  Asterisk should stop accepting new calls
3506                          * if the amount of free memory falls below this watermark */
3507                         if ((sscanf(v->value, "%30ld", &option_minmemfree) != 1) || (option_minmemfree < 0)) {
3508                                 option_minmemfree = 0;
3509                         }
3510 #endif
3511                 } else if (!strcasecmp(v->name, "entityid")) {
3512                         struct ast_eid tmp_eid;
3513                         if (!ast_str_to_eid(&tmp_eid, v->value)) {
3514                                 ast_verbose("Successfully set global EID to '%s'\n", v->value);
3515                                 ast_eid_default = tmp_eid;
3516                         } else
3517                                 ast_verbose("Invalid Entity ID '%s' provided\n", v->value);
3518                 } else if (!strcasecmp(v->name, "lightbackground")) {
3519                         ast_set2_flag(&ast_options, ast_true(v->value), AST_OPT_FLAG_LIGHT_BACKGROUND);
3520                 } else if (!strcasecmp(v->name, "forceblackbackground")) {
3521                         ast_set2_flag(&ast_options, ast_true(v->value), AST_OPT_FLAG_FORCE_BLACK_BACKGROUND);
3522                 } else if (!strcasecmp(v->name, "hideconnect")) {
3523                         ast_set2_flag(&ast_options, ast_true(v->value), AST_OPT_FLAG_HIDE_CONSOLE_CONNECT);
3524                 } else if (!strcasecmp(v->name, "lockconfdir")) {
3525                         ast_set2_flag(&ast_options, ast_true(v->value), AST_OPT_FLAG_LOCK_CONFIG_DIR);
3526                 } else if (!strcasecmp(v->name, "stdexten")) {
3527                         /* Choose how to invoke the extensions.conf stdexten */
3528                         if (!strcasecmp(v->value, "gosub")) {
3529                                 ast_clear_flag(&ast_options, AST_OPT_FLAG_STDEXTEN_MACRO);
3530                         } else if (!strcasecmp(v->value, "macro")) {
3531                                 ast_set_flag(&ast_options, AST_OPT_FLAG_STDEXTEN_MACRO);
3532                         } else {
3533                                 ast_log(LOG_WARNING,
3534                                         "'%s' is not a valid setting for the stdexten option, defaulting to 'gosub'\n",
3535                                         v->value);
3536                                 ast_clear_flag(&ast_options, AST_OPT_FLAG_STDEXTEN_MACRO);
3537                         }
3538                 }
3539         }
3540         for (v = ast_variable_browse(cfg, "compat"); v; v = v->next) {
3541                 float version;
3542                 if (sscanf(v->value, "%30f", &version) != 1) {
3543                         fprintf(stderr, "Compatibility version for option '%s' is not a number: '%s'\n", v->name, v->value);
3544                         continue;
3545                 }
3546                 if (!strcasecmp(v->name, "app_set")) {
3547                         ast_set2_flag(&ast_compat, version < 1.5 ? 1 : 0, AST_COMPAT_APP_SET);
3548                 } else if (!strcasecmp(v->name, "res_agi")) {
3549                         ast_set2_flag(&ast_compat, version < 1.5 ? 1 : 0, AST_COMPAT_DELIM_RES_AGI);
3550                 } else if (!strcasecmp(v->name, "pbx_realtime")) {
3551                         ast_set2_flag(&ast_compat, version < 1.5 ? 1 : 0, AST_COMPAT_DELIM_PBX_REALTIME);
3552                 }
3553         }
3554         ast_config_destroy(cfg);
3555 }
3556
3557 static void *monitor_sig_flags(void *unused)
3558 {
3559         for (;;) {
3560                 struct pollfd p = { sig_alert_pipe[0], POLLIN, 0 };
3561                 int a;
3562                 ast_poll(&p, 1, -1);
3563                 if (sig_flags.need_reload) {
3564                         sig_flags.need_reload = 0;
3565                         ast_module_reload(NULL);
3566                 }
3567                 if (sig_flags.need_quit) {
3568                         sig_flags.need_quit = 0;
3569                         if ((consolethread != AST_PTHREADT_NULL) && (consolethread != pthread_self())) {
3570                                 sig_flags.need_quit_handler = 1;
3571                                 pthread_kill(consolethread, SIGURG);
3572                         } else {
3573                                 quit_handler(0, SHUTDOWN_NORMAL, 0);
3574                         }
3575                 }
3576                 if (read(sig_alert_pipe[0], &a, sizeof(a)) != sizeof(a)) {
3577                 }
3578         }
3579
3580         return NULL;
3581 }
3582
3583 static void *canary_thread(void *unused)
3584 {
3585         struct stat canary_stat;
3586         struct timeval now;
3587
3588         /* Give the canary time to sing */
3589         sleep(120);
3590
3591         for (;;) {
3592                 now = ast_tvnow();
3593                 if (stat(canary_filename, &canary_stat) || now.tv_sec > canary_stat.st_mtime + 60) {
3594                         ast_log(LOG_WARNING,
3595                                 "The canary is no more.  He has ceased to be!  "
3596                                 "He's expired and gone to meet his maker!  "
3597                                 "He's a stiff!  Bereft of life, he rests in peace.  "
3598                                 "His metabolic processes are now history!  He's off the twig!  "
3599                                 "He's kicked the bucket.  He's shuffled off his mortal coil, "
3600                                 "run down the curtain, and joined the bleeding choir invisible!!  "
3601                                 "THIS is an EX-CANARY.  (Reducing priority)\n");
3602                         ast_set_priority(0);
3603                         pthread_exit(NULL);
3604                 }
3605
3606                 /* Check the canary once a minute */
3607                 sleep(60);
3608         }
3609 }
3610
3611 /* Used&nbs