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