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