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