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