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