73d390fad23766170d876b2e5acdf2d99c89c23a
[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         event_info = ast_json_pack("{s: s, s: i, s: o}",
1144                         "type", message_type,
1145                         "class_type", EVENT_FLAG_SYSTEM,
1146                         "event", obj);
1147         if (!event_info) {
1148                 return;
1149         }
1150
1151         payload = ast_json_payload_create(event_info);
1152         if (!payload) {
1153                 return;
1154         }
1155
1156         message = stasis_message_create(ast_manager_get_generic_type(), payload);
1157         if (!message) {
1158                 return;
1159         }
1160         stasis_publish(ast_manager_get_topic(), message);
1161 }
1162
1163 static void publish_fully_booted(void)
1164 {
1165         RAII_VAR(struct ast_json *, json_object, NULL, ast_json_unref);
1166
1167         json_object = ast_json_pack("{s: s}",
1168                         "Status", "Fully Booted");
1169         publish_system_message("FullyBooted", json_object);
1170 }
1171
1172 static void ast_run_atexits(void)
1173 {
1174         struct ast_atexit *ae;
1175
1176         AST_LIST_LOCK(&atexits);
1177         while ((ae = AST_LIST_REMOVE_HEAD(&atexits, list))) {
1178                 if (ae->func) {
1179                         ae->func();
1180                 }
1181                 ast_free(ae);
1182         }
1183         AST_LIST_UNLOCK(&atexits);
1184 }
1185
1186 static void __ast_unregister_atexit(void (*func)(void))
1187 {
1188         struct ast_atexit *ae;
1189
1190         AST_LIST_TRAVERSE_SAFE_BEGIN(&atexits, ae, list) {
1191                 if (ae->func == func) {
1192                         AST_LIST_REMOVE_CURRENT(list);
1193                         ast_free(ae);
1194                         break;
1195                 }
1196         }
1197         AST_LIST_TRAVERSE_SAFE_END;
1198 }
1199
1200 int ast_register_atexit(void (*func)(void))
1201 {
1202         struct ast_atexit *ae;
1203
1204         ae = ast_calloc(1, sizeof(*ae));
1205         if (!ae) {
1206                 return -1;
1207         }
1208         ae->func = func;
1209
1210         AST_LIST_LOCK(&atexits);
1211         __ast_unregister_atexit(func);
1212         AST_LIST_INSERT_HEAD(&atexits, ae, list);
1213         AST_LIST_UNLOCK(&atexits);
1214
1215         return 0;
1216 }
1217
1218 void ast_unregister_atexit(void (*func)(void))
1219 {
1220         AST_LIST_LOCK(&atexits);
1221         __ast_unregister_atexit(func);
1222         AST_LIST_UNLOCK(&atexits);
1223 }
1224
1225 /* Sending commands from consoles back to the daemon requires a terminating NULL */
1226 static int fdsend(int fd, const char *s)
1227 {
1228         return write(fd, s, strlen(s) + 1);
1229 }
1230
1231 /* Sending messages from the daemon back to the display requires _excluding_ the terminating NULL */
1232 static int fdprint(int fd, const char *s)
1233 {
1234         return write(fd, s, strlen(s));
1235 }
1236
1237 /*! \brief NULL handler so we can collect the child exit status */
1238 static void _null_sig_handler(int sig)
1239 {
1240 }
1241
1242 static struct sigaction null_sig_handler = {
1243         .sa_handler = _null_sig_handler,
1244         .sa_flags = SA_RESTART,
1245 };
1246
1247 static struct sigaction ignore_sig_handler = {
1248         .sa_handler = SIG_IGN,
1249 };
1250
1251 AST_MUTEX_DEFINE_STATIC(safe_system_lock);
1252 /*! \brief Keep track of how many threads are currently trying to wait*() on
1253  *  a child process
1254  */
1255 static unsigned int safe_system_level = 0;
1256 static struct sigaction safe_system_prev_handler;
1257
1258 void ast_replace_sigchld(void)
1259 {
1260         unsigned int level;
1261
1262         ast_mutex_lock(&safe_system_lock);
1263         level = safe_system_level++;
1264
1265         /* only replace the handler if it has not already been done */
1266         if (level == 0) {
1267                 sigaction(SIGCHLD, &null_sig_handler, &safe_system_prev_handler);
1268         }
1269
1270         ast_mutex_unlock(&safe_system_lock);
1271 }
1272
1273 void ast_unreplace_sigchld(void)
1274 {
1275         unsigned int level;
1276
1277         ast_mutex_lock(&safe_system_lock);
1278         level = --safe_system_level;
1279
1280         /* only restore the handler if we are the last one */
1281         if (level == 0) {
1282                 sigaction(SIGCHLD, &safe_system_prev_handler, NULL);
1283         }
1284
1285         ast_mutex_unlock(&safe_system_lock);
1286 }
1287
1288 int ast_safe_system(const char *s)
1289 {
1290         pid_t pid;
1291         int res;
1292         struct rusage rusage;
1293         int status;
1294
1295 #if defined(HAVE_WORKING_FORK) || defined(HAVE_WORKING_VFORK)
1296         ast_replace_sigchld();
1297
1298 #ifdef HAVE_WORKING_FORK
1299         pid = fork();
1300 #else
1301         pid = vfork();
1302 #endif
1303
1304         if (pid == 0) {
1305 #ifdef HAVE_CAP
1306                 cap_t cap = cap_from_text("cap_net_admin-eip");
1307
1308                 if (cap_set_proc(cap)) {
1309                         /* Careful with order! Logging cannot happen after we close FDs */
1310                         ast_log(LOG_WARNING, "Unable to remove capabilities.\n");
1311                 }
1312                 cap_free(cap);
1313 #endif
1314 #ifdef HAVE_WORKING_FORK
1315                 if (ast_opt_high_priority)
1316                         ast_set_priority(0);
1317                 /* Close file descriptors and launch system command */
1318                 ast_close_fds_above_n(STDERR_FILENO);
1319 #endif
1320                 execl("/bin/sh", "/bin/sh", "-c", s, (char *) NULL);
1321                 _exit(1);
1322         } else if (pid > 0) {
1323                 for (;;) {
1324                         res = wait4(pid, &status, 0, &rusage);
1325                         if (res > -1) {
1326                                 res = WIFEXITED(status) ? WEXITSTATUS(status) : -1;
1327                                 break;
1328                         } else if (errno != EINTR)
1329                                 break;
1330                 }
1331         } else {
1332                 ast_log(LOG_WARNING, "Fork failed: %s\n", strerror(errno));
1333                 res = -1;
1334         }
1335
1336         ast_unreplace_sigchld();
1337 #else /* !defined(HAVE_WORKING_FORK) && !defined(HAVE_WORKING_VFORK) */
1338         res = -1;
1339 #endif
1340
1341         return res;
1342 }
1343
1344 /*!
1345  * \brief enable or disable a logging level to a specified console
1346  */
1347 void ast_console_toggle_loglevel(int fd, int level, int state)
1348 {
1349         int x;
1350
1351         if (level >= NUMLOGLEVELS) {
1352                 level = NUMLOGLEVELS - 1;
1353         }
1354
1355         for (x = 0;x < AST_MAX_CONNECTS; x++) {
1356                 if (fd == consoles[x].fd) {
1357                         /*
1358                          * Since the logging occurs when levels are false, set to
1359                          * flipped iinput because this function accepts 0 as off and 1 as on
1360                          */
1361                         consoles[x].levels[level] = state ? 0 : 1;
1362                         return;
1363                 }
1364         }
1365 }
1366
1367 /*!
1368  * \brief mute or unmute a console from logging
1369  */
1370 void ast_console_toggle_mute(int fd, int silent)
1371 {
1372         int x;
1373         for (x = 0;x < AST_MAX_CONNECTS; x++) {
1374                 if (fd == consoles[x].fd) {
1375                         if (consoles[x].mute) {
1376                                 consoles[x].mute = 0;
1377                                 if (!silent)
1378                                         ast_cli(fd, "Console is not muted anymore.\n");
1379                         } else {
1380                                 consoles[x].mute = 1;
1381                                 if (!silent)
1382                                         ast_cli(fd, "Console is muted.\n");
1383                         }
1384                         return;
1385                 }
1386         }
1387         ast_cli(fd, "Couldn't find remote console.\n");
1388 }
1389
1390 /*!
1391  * \brief log the string to all attached console clients
1392  */
1393 static void ast_network_puts_mutable(const char *string, int level)
1394 {
1395         int x;
1396         for (x = 0;x < AST_MAX_CONNECTS; x++) {
1397                 if (consoles[x].mute)
1398                         continue;
1399                 if (consoles[x].fd > -1) {
1400                         if (!consoles[x].levels[level])
1401                                 fdprint(consoles[x].p[1], string);
1402                 }
1403         }
1404 }
1405
1406 /*!
1407  * \brief log the string to the console, and all attached
1408  * console clients
1409  */
1410 void ast_console_puts_mutable(const char *string, int level)
1411 {
1412         fputs(string, stdout);
1413         fflush(stdout);
1414         ast_network_puts_mutable(string, level);
1415 }
1416
1417 /*!
1418  * \brief write the string to all attached console clients
1419  */
1420 static void ast_network_puts(const char *string)
1421 {
1422         int x;
1423         for (x = 0; x < AST_MAX_CONNECTS; x++) {
1424                 if (consoles[x].fd > -1)
1425                         fdprint(consoles[x].p[1], string);
1426         }
1427 }
1428
1429 /*!
1430  * \brief write the string to the console, and all attached
1431  * console clients
1432  */
1433 void ast_console_puts(const char *string)
1434 {
1435         fputs(string, stdout);
1436         fflush(stdout);
1437         ast_network_puts(string);
1438 }
1439
1440 static void network_verboser(const char *s)
1441 {
1442         ast_network_puts_mutable(s, __LOG_VERBOSE);
1443 }
1444
1445 static pthread_t lthread;
1446
1447 /*!
1448  * \brief read() function supporting the reception of user credentials.
1449  *
1450  * \param fd Socket file descriptor.
1451  * \param buffer Receive buffer.
1452  * \param size 'buffer' size.
1453  * \param con Console structure to set received credentials
1454  * \retval -1 on error
1455  * \retval the number of bytes received on success.
1456  */
1457 static int read_credentials(int fd, char *buffer, size_t size, struct console *con)
1458 {
1459 #if defined(SO_PEERCRED)
1460 #ifdef HAVE_STRUCT_SOCKPEERCRED_UID
1461 #define HAVE_STRUCT_UCRED_UID
1462         struct sockpeercred cred;
1463 #else
1464         struct ucred cred;
1465 #endif
1466         socklen_t len = sizeof(cred);
1467 #endif
1468 #if defined(HAVE_GETPEEREID)
1469         uid_t uid;
1470         gid_t gid;
1471 #else
1472         int uid, gid;
1473 #endif
1474         int result;
1475
1476         result = read(fd, buffer, size);
1477         if (result < 0) {
1478                 return result;
1479         }
1480
1481 #if defined(SO_PEERCRED) && (defined(HAVE_STRUCT_UCRED_UID) || defined(HAVE_STRUCT_UCRED_CR_UID))
1482         if (getsockopt(fd, SOL_SOCKET, SO_PEERCRED, &cred, &len)) {
1483                 return result;
1484         }
1485 #if defined(HAVE_STRUCT_UCRED_UID)
1486         uid = cred.uid;
1487         gid = cred.gid;
1488 #else /* defined(HAVE_STRUCT_UCRED_CR_UID) */
1489         uid = cred.cr_uid;
1490         gid = cred.cr_gid;
1491 #endif /* defined(HAVE_STRUCT_UCRED_UID) */
1492
1493 #elif defined(HAVE_GETPEEREID)
1494         if (getpeereid(fd, &uid, &gid)) {
1495                 return result;
1496         }
1497 #else
1498         return result;
1499 #endif
1500         con->uid = uid;
1501         con->gid = gid;
1502
1503         return result;
1504 }
1505
1506 static void *netconsole(void *vconsole)
1507 {
1508         struct console *con = vconsole;
1509         char hostname[MAXHOSTNAMELEN] = "";
1510         char inbuf[512];
1511         char outbuf[512];
1512         const char * const end_buf = inbuf + sizeof(inbuf);
1513         char *start_read = inbuf;
1514         int res;
1515         struct pollfd fds[2];
1516
1517         if (gethostname(hostname, sizeof(hostname)-1))
1518                 ast_copy_string(hostname, "<Unknown>", sizeof(hostname));
1519         snprintf(outbuf, sizeof(outbuf), "%s/%ld/%s\n", hostname, (long)ast_mainpid, ast_get_version());
1520         fdprint(con->fd, outbuf);
1521         for (;;) {
1522                 fds[0].fd = con->fd;
1523                 fds[0].events = POLLIN;
1524                 fds[0].revents = 0;
1525                 fds[1].fd = con->p[0];
1526                 fds[1].events = POLLIN;
1527                 fds[1].revents = 0;
1528
1529                 res = ast_poll(fds, 2, -1);
1530                 if (res < 0) {
1531                         if (errno != EINTR)
1532                                 ast_log(LOG_WARNING, "poll returned < 0: %s\n", strerror(errno));
1533                         continue;
1534                 }
1535                 if (fds[0].revents) {
1536                         int cmds_read, bytes_read;
1537                         if ((bytes_read = read_credentials(con->fd, start_read, end_buf - start_read, con)) < 1) {
1538                                 break;
1539                         }
1540                         /* XXX This will only work if it is the first command, and I'm not sure fixing it is worth the effort. */
1541                         if (strncmp(inbuf, "cli quit after ", 15) == 0) {
1542                                 ast_cli_command_multiple_full(con->uid, con->gid, con->fd, bytes_read - 15, inbuf + 15);
1543                                 break;
1544                         }
1545                         /* ast_cli_command_multiple_full will only process individual commands terminated by a
1546                          * NULL and not trailing partial commands. */
1547                         if (!(cmds_read = ast_cli_command_multiple_full(con->uid, con->gid, con->fd, bytes_read + start_read - inbuf, inbuf))) {
1548                                 /* No commands were read. We either have a short read on the first command
1549                                  * with space left, or a command that is too long */
1550                                 if (start_read + bytes_read < end_buf) {
1551                                         start_read += bytes_read;
1552                                 } else {
1553                                         ast_log(LOG_ERROR, "Command too long! Skipping\n");
1554                                         start_read = inbuf;
1555                                 }
1556                                 continue;
1557                         }
1558                         if (start_read[bytes_read - 1] == '\0') {
1559                                 /* The read ended on a command boundary, start reading again at the head of inbuf */
1560                                 start_read = inbuf;
1561                                 continue;
1562                         }
1563                         /* If we get this far, we have left over characters that have not been processed.
1564                          * Advance to the character after the last command read by ast_cli_command_multiple_full.
1565                          * We are guaranteed to have at least cmds_read NULLs */
1566                         while (cmds_read-- && (start_read = strchr(start_read, '\0'))) {
1567                                 start_read++;
1568                         }
1569                         memmove(inbuf, start_read, end_buf - start_read);
1570                         start_read = end_buf - start_read + inbuf;
1571                 }
1572                 if (fds[1].revents) {
1573                         res = read_credentials(con->p[0], outbuf, sizeof(outbuf), con);
1574                         if (res < 1) {
1575                                 ast_log(LOG_ERROR, "read returned %d\n", res);
1576                                 break;
1577                         }
1578                         res = write(con->fd, outbuf, res);
1579                         if (res < 1)
1580                                 break;
1581                 }
1582         }
1583         if (!ast_opt_hide_connect) {
1584                 ast_verb(3, "Remote UNIX connection disconnected\n");
1585         }
1586         close(con->fd);
1587         close(con->p[0]);
1588         close(con->p[1]);
1589         con->fd = -1;
1590
1591         return NULL;
1592 }
1593
1594 static void *listener(void *unused)
1595 {
1596         struct sockaddr_un sunaddr;
1597         int s;
1598         socklen_t len;
1599         int x;
1600         int flags;
1601         struct pollfd fds[1];
1602         for (;;) {
1603                 if (ast_socket < 0)
1604                         return NULL;
1605                 fds[0].fd = ast_socket;
1606                 fds[0].events = POLLIN;
1607                 s = ast_poll(fds, 1, -1);
1608                 pthread_testcancel();
1609                 if (s < 0) {
1610                         if (errno != EINTR)
1611                                 ast_log(LOG_WARNING, "poll returned error: %s\n", strerror(errno));
1612                         continue;
1613                 }
1614                 len = sizeof(sunaddr);
1615                 s = accept(ast_socket, (struct sockaddr *)&sunaddr, &len);
1616                 if (s < 0) {
1617                         if (errno != EINTR)
1618                                 ast_log(LOG_WARNING, "Accept returned %d: %s\n", s, strerror(errno));
1619                 } else {
1620 #if !defined(SO_PASSCRED)
1621                         {
1622 #else
1623                         int sckopt = 1;
1624                         /* turn on socket credentials passing. */
1625                         if (setsockopt(s, SOL_SOCKET, SO_PASSCRED, &sckopt, sizeof(sckopt)) < 0) {
1626                                 ast_log(LOG_WARNING, "Unable to turn on socket credentials passing\n");
1627                         } else {
1628 #endif
1629                                 for (x = 0; x < AST_MAX_CONNECTS; x++) {
1630                                         if (consoles[x].fd >= 0) {
1631                                                 continue;
1632                                         }
1633                                         if (socketpair(AF_LOCAL, SOCK_STREAM, 0, consoles[x].p)) {
1634                                                 ast_log(LOG_ERROR, "Unable to create pipe: %s\n", strerror(errno));
1635                                                 consoles[x].fd = -1;
1636                                                 fdprint(s, "Server failed to create pipe\n");
1637                                                 close(s);
1638                                                 break;
1639                                         }
1640                                         flags = fcntl(consoles[x].p[1], F_GETFL);
1641                                         fcntl(consoles[x].p[1], F_SETFL, flags | O_NONBLOCK);
1642                                         consoles[x].fd = s;
1643                                         consoles[x].mute = 1; /* Default is muted, we will un-mute if necessary */
1644                                         /* Default uid and gid to -2, so then in cli.c/cli_has_permissions() we will be able
1645                                            to know if the user didn't send the credentials. */
1646                                         consoles[x].uid = -2;
1647                                         consoles[x].gid = -2;
1648                                         if (ast_pthread_create_detached_background(&consoles[x].t, NULL, netconsole, &consoles[x])) {
1649                                                 ast_log(LOG_ERROR, "Unable to spawn thread to handle connection: %s\n", strerror(errno));
1650                                                 close(consoles[x].p[0]);
1651                                                 close(consoles[x].p[1]);
1652                                                 consoles[x].fd = -1;
1653                                                 fdprint(s, "Server failed to spawn thread\n");
1654                                                 close(s);
1655                                         }
1656                                         break;
1657                                 }
1658                                 if (x >= AST_MAX_CONNECTS) {
1659                                         fdprint(s, "No more connections allowed\n");
1660                                         ast_log(LOG_WARNING, "No more connections allowed\n");
1661                                         close(s);
1662                                 } else if ((consoles[x].fd > -1) && (!ast_opt_hide_connect)) {
1663                                         ast_verb(3, "Remote UNIX connection\n");
1664                                 }
1665                         }
1666                 }
1667         }
1668         return NULL;
1669 }
1670
1671 static int ast_makesocket(void)
1672 {
1673         struct sockaddr_un sunaddr;
1674         int res;
1675         int x;
1676         uid_t uid = -1;
1677         gid_t gid = -1;
1678
1679         for (x = 0; x < AST_MAX_CONNECTS; x++)
1680                 consoles[x].fd = -1;
1681         unlink(ast_config_AST_SOCKET);
1682         ast_socket = socket(PF_LOCAL, SOCK_STREAM, 0);
1683         if (ast_socket < 0) {
1684                 ast_log(LOG_WARNING, "Unable to create control socket: %s\n", strerror(errno));
1685                 return -1;
1686         }
1687         memset(&sunaddr, 0, sizeof(sunaddr));
1688         sunaddr.sun_family = AF_LOCAL;
1689         ast_copy_string(sunaddr.sun_path, ast_config_AST_SOCKET, sizeof(sunaddr.sun_path));
1690         res = bind(ast_socket, (struct sockaddr *)&sunaddr, sizeof(sunaddr));
1691         if (res) {
1692                 ast_log(LOG_WARNING, "Unable to bind socket to %s: %s\n", ast_config_AST_SOCKET, strerror(errno));
1693                 close(ast_socket);
1694                 ast_socket = -1;
1695                 return -1;
1696         }
1697         res = listen(ast_socket, 2);
1698         if (res < 0) {
1699                 ast_log(LOG_WARNING, "Unable to listen on socket %s: %s\n", ast_config_AST_SOCKET, strerror(errno));
1700                 close(ast_socket);
1701                 ast_socket = -1;
1702                 return -1;
1703         }
1704         if (ast_register_verbose(network_verboser)) {
1705                 ast_log(LOG_WARNING, "Unable to register network verboser?\n");
1706         }
1707
1708         if (ast_pthread_create_background(&lthread, NULL, listener, NULL)) {
1709                 ast_log(LOG_WARNING, "Unable to create listener thread.\n");
1710                 close(ast_socket);
1711                 return -1;
1712         }
1713
1714         if (!ast_strlen_zero(ast_config_AST_CTL_OWNER)) {
1715                 struct passwd *pw;
1716                 if ((pw = getpwnam(ast_config_AST_CTL_OWNER)) == NULL)
1717                         ast_log(LOG_WARNING, "Unable to find uid of user %s\n", ast_config_AST_CTL_OWNER);
1718                 else
1719                         uid = pw->pw_uid;
1720         }
1721
1722         if (!ast_strlen_zero(ast_config_AST_CTL_GROUP)) {
1723                 struct group *grp;
1724                 if ((grp = getgrnam(ast_config_AST_CTL_GROUP)) == NULL)
1725                         ast_log(LOG_WARNING, "Unable to find gid of group %s\n", ast_config_AST_CTL_GROUP);
1726                 else
1727                         gid = grp->gr_gid;
1728         }
1729
1730         if (chown(ast_config_AST_SOCKET, uid, gid) < 0)
1731                 ast_log(LOG_WARNING, "Unable to change ownership of %s: %s\n", ast_config_AST_SOCKET, strerror(errno));
1732
1733         if (!ast_strlen_zero(ast_config_AST_CTL_PERMISSIONS)) {
1734                 int p1;
1735                 mode_t p;
1736                 sscanf(ast_config_AST_CTL_PERMISSIONS, "%30o", &p1);
1737                 p = p1;
1738                 if ((chmod(ast_config_AST_SOCKET, p)) < 0)
1739                         ast_log(LOG_WARNING, "Unable to change file permissions of %s: %s\n", ast_config_AST_SOCKET, strerror(errno));
1740         }
1741
1742         return 0;
1743 }
1744
1745 static int ast_tryconnect(void)
1746 {
1747         struct sockaddr_un sunaddr;
1748         int res;
1749         ast_consock = socket(PF_LOCAL, SOCK_STREAM, 0);
1750         if (ast_consock < 0) {
1751                 fprintf(stderr, "Unable to create socket: %s\n", strerror(errno));
1752                 return 0;
1753         }
1754         memset(&sunaddr, 0, sizeof(sunaddr));
1755         sunaddr.sun_family = AF_LOCAL;
1756         ast_copy_string(sunaddr.sun_path, ast_config_AST_SOCKET, sizeof(sunaddr.sun_path));
1757         res = connect(ast_consock, (struct sockaddr *)&sunaddr, sizeof(sunaddr));
1758         if (res) {
1759                 close(ast_consock);
1760                 ast_consock = -1;
1761                 return 0;
1762         } else
1763                 return 1;
1764 }
1765
1766 /*! \brief Urgent handler
1767  *
1768  * Called by soft_hangup to interrupt the poll, read, or other
1769  * system call.  We don't actually need to do anything though.
1770  * Remember: Cannot EVER ast_log from within a signal handler
1771  */
1772 static void _urg_handler(int num)
1773 {
1774         return;
1775 }
1776
1777 static struct sigaction urg_handler = {
1778         .sa_handler = _urg_handler,
1779         .sa_flags = SA_RESTART,
1780 };
1781
1782 static void _hup_handler(int num)
1783 {
1784         int a = 0, save_errno = errno;
1785         printf("Received HUP signal -- Reloading configs\n");
1786         if (restartnow)
1787                 execvp(_argv[0], _argv);
1788         sig_flags.need_reload = 1;
1789         if (sig_alert_pipe[1] != -1) {
1790                 if (write(sig_alert_pipe[1], &a, sizeof(a)) < 0) {
1791                         fprintf(stderr, "hup_handler: write() failed: %s\n", strerror(errno));
1792                 }
1793         }
1794         errno = save_errno;
1795 }
1796
1797 static struct sigaction hup_handler = {
1798         .sa_handler = _hup_handler,
1799         .sa_flags = SA_RESTART,
1800 };
1801
1802 static void _child_handler(int sig)
1803 {
1804         /* Must not ever ast_log or ast_verbose within signal handler */
1805         int n, status, save_errno = errno;
1806
1807         /*
1808          * Reap all dead children -- not just one
1809          */
1810         for (n = 0; wait4(-1, &status, WNOHANG, NULL) > 0; n++)
1811                 ;
1812         if (n == 0 && option_debug)
1813                 printf("Huh?  Child handler, but nobody there?\n");
1814         errno = save_errno;
1815 }
1816
1817 static struct sigaction child_handler = {
1818         .sa_handler = _child_handler,
1819         .sa_flags = SA_RESTART,
1820 };
1821
1822 /*! \brief Set maximum open files */
1823 static void set_ulimit(int value)
1824 {
1825         struct rlimit l = {0, 0};
1826
1827         if (value <= 0) {
1828                 ast_log(LOG_WARNING, "Unable to change max files open to invalid value %i\n",value);
1829                 return;
1830         }
1831
1832         l.rlim_cur = value;
1833         l.rlim_max = value;
1834
1835         if (setrlimit(RLIMIT_NOFILE, &l)) {
1836                 ast_log(LOG_WARNING, "Unable to disable core size resource limit: %s\n",strerror(errno));
1837                 return;
1838         }
1839
1840         ast_log(LOG_NOTICE, "Setting max files open to %d\n",value);
1841
1842         return;
1843 }
1844
1845 /*! \brief Set an X-term or screen title */
1846 static void set_title(char *text)
1847 {
1848         if (getenv("TERM") && strstr(getenv("TERM"), "xterm"))
1849                 fprintf(stdout, "\033]2;%s\007", text);
1850 }
1851
1852 static void set_icon(char *text)
1853 {
1854         if (getenv("TERM") && strstr(getenv("TERM"), "xterm"))
1855                 fprintf(stdout, "\033]1;%s\007", text);
1856 }
1857
1858 /*! \brief We set ourselves to a high priority, that we might pre-empt
1859  * everything else.  If your PBX has heavy activity on it, this is a
1860  * good thing.
1861  */
1862 int ast_set_priority(int pri)
1863 {
1864         struct sched_param sched;
1865         memset(&sched, 0, sizeof(sched));
1866 #ifdef __linux__
1867         if (pri) {
1868                 sched.sched_priority = 10;
1869                 if (sched_setscheduler(0, SCHED_RR, &sched)) {
1870                         ast_log(LOG_WARNING, "Unable to set high priority\n");
1871                         return -1;
1872                 } else
1873                         ast_verb(1, "Set to realtime thread\n");
1874         } else {
1875                 sched.sched_priority = 0;
1876                 /* According to the manpage, these parameters can never fail. */
1877                 sched_setscheduler(0, SCHED_OTHER, &sched);
1878         }
1879 #else
1880         if (pri) {
1881                 if (setpriority(PRIO_PROCESS, 0, -10) == -1) {
1882                         ast_log(LOG_WARNING, "Unable to set high priority\n");
1883                         return -1;
1884                 } else
1885                         ast_verb(1, "Set to high priority\n");
1886         } else {
1887                 /* According to the manpage, these parameters can never fail. */
1888                 setpriority(PRIO_PROCESS, 0, 0);
1889         }
1890 #endif
1891         return 0;
1892 }
1893
1894 static int can_safely_quit(shutdown_nice_t niceness, int restart);
1895 static void really_quit(int num, shutdown_nice_t niceness, int restart);
1896
1897 static void quit_handler(int num, shutdown_nice_t niceness, int restart)
1898 {
1899         if (can_safely_quit(niceness, restart)) {
1900                 really_quit(num, niceness, restart);
1901                 /* No one gets here. */
1902         }
1903         /* It wasn't our time. */
1904 }
1905
1906 static int can_safely_quit(shutdown_nice_t niceness, int restart)
1907 {
1908         /* Check if someone else isn't already doing this. */
1909         ast_mutex_lock(&safe_system_lock);
1910         if (shuttingdown != NOT_SHUTTING_DOWN && niceness >= shuttingdown) {
1911                 /* Already in progress and other request was less nice. */
1912                 ast_mutex_unlock(&safe_system_lock);
1913                 ast_verbose("Ignoring asterisk %s request, already in progress.\n", restart ? "restart" : "shutdown");
1914                 return 0;
1915         }
1916         shuttingdown = niceness;
1917         ast_mutex_unlock(&safe_system_lock);
1918
1919         /* Try to get as many CDRs as possible submitted to the backend engines
1920          * (if in batch mode). really_quit happens to call it again when running
1921          * the atexit handlers, otherwise this would be a bit early. */
1922         ast_cdr_engine_term();
1923
1924         /* Shutdown the message queue for the technology agnostic message channel.
1925          * This has to occur before we pause shutdown pending ast_undestroyed_channels. */
1926         ast_msg_shutdown();
1927
1928         if (niceness == SHUTDOWN_NORMAL) {
1929                 time_t s, e;
1930                 /* Begin shutdown routine, hanging up active channels */
1931                 ast_begin_shutdown(1);
1932                 if (option_verbose && ast_opt_console) {
1933                         ast_verbose("Beginning asterisk %s....\n", restart ? "restart" : "shutdown");
1934                 }
1935                 time(&s);
1936                 for (;;) {
1937                         time(&e);
1938                         /* Wait up to 15 seconds for all channels to go away */
1939                         if ((e - s) > 15 || !ast_undestroyed_channels() || shuttingdown != niceness) {
1940                                 break;
1941                         }
1942                         /* Sleep 1/10 of a second */
1943                         usleep(100000);
1944                 }
1945         } else if (niceness >= SHUTDOWN_NICE) {
1946                 if (niceness != SHUTDOWN_REALLY_NICE) {
1947                         ast_begin_shutdown(0);
1948                 }
1949                 if (option_verbose && ast_opt_console) {
1950                         ast_verb(0, "Waiting for inactivity to perform %s...\n", restart ? "restart" : "halt");
1951                 }
1952                 for (;;) {
1953                         if (!ast_undestroyed_channels() || shuttingdown != niceness) {
1954                                 break;
1955                         }
1956                         sleep(1);
1957                 }
1958         }
1959
1960         /* Re-acquire lock and check if someone changed the niceness, in which
1961          * case someone else has taken over the shutdown.
1962          */
1963         ast_mutex_lock(&safe_system_lock);
1964         if (shuttingdown != niceness) {
1965                 if (shuttingdown == NOT_SHUTTING_DOWN && option_verbose && ast_opt_console) {
1966                         ast_verb(0, "Asterisk %s cancelled.\n", restart ? "restart" : "shutdown");
1967                 }
1968                 ast_mutex_unlock(&safe_system_lock);
1969                 return 0;
1970         }
1971         shuttingdown = SHUTTING_DOWN;
1972         ast_mutex_unlock(&safe_system_lock);
1973
1974         return 1;
1975 }
1976
1977 /*! Called when exiting is certain. */
1978 static void really_quit(int num, shutdown_nice_t niceness, int restart)
1979 {
1980         int active_channels;
1981         RAII_VAR(struct ast_json *, json_object, NULL, ast_json_unref);
1982
1983         if (niceness >= SHUTDOWN_NICE) {
1984                 ast_module_shutdown();
1985         }
1986
1987         if (ast_opt_console || (ast_opt_remote && !ast_opt_exec)) {
1988                 char filename[80] = "";
1989                 if (getenv("HOME")) {
1990                         snprintf(filename, sizeof(filename), "%s/.asterisk_history", getenv("HOME"));
1991                 }
1992                 if (!ast_strlen_zero(filename)) {
1993                         ast_el_write_history(filename);
1994                 }
1995                 if (consolethread == AST_PTHREADT_NULL || consolethread == pthread_self()) {
1996                         /* Only end if we are the consolethread, otherwise there's a race with that thread. */
1997                         if (el != NULL) {
1998                                 el_end(el);
1999                         }
2000                         if (el_hist != NULL) {
2001                                 history_end(el_hist);
2002                         }
2003                 } else if (mon_sig_flags == pthread_self()) {
2004                         if (consolethread != AST_PTHREADT_NULL) {
2005                                 pthread_kill(consolethread, SIGURG);
2006                         }
2007                 }
2008         }
2009         active_channels = ast_active_channels();
2010         json_object = ast_json_pack("{s: s, s: s}",
2011                         "Shutdown", active_channels ? "Uncleanly" : "Cleanly",
2012                         "Restart", restart ? "True" : "False");
2013         publish_system_message("Shutdown", json_object);
2014         ast_verb(0, "Asterisk %s ending (%d).\n",
2015                 active_channels ? "uncleanly" : "cleanly", num);
2016
2017         ast_verb(0, "Executing last minute cleanups\n");
2018         ast_run_atexits();
2019
2020         ast_debug(1, "Asterisk ending (%d).\n", num);
2021         if (ast_socket > -1) {
2022                 pthread_cancel(lthread);
2023                 close(ast_socket);
2024                 ast_socket = -1;
2025                 unlink(ast_config_AST_SOCKET);
2026         }
2027         if (ast_consock > -1)
2028                 close(ast_consock);
2029         if (!ast_opt_remote)
2030                 unlink(ast_config_AST_PID);
2031         printf("%s", term_quit());
2032         if (restart) {
2033                 int i;
2034                 ast_verb(0, "Preparing for Asterisk restart...\n");
2035                 /* Mark all FD's for closing on exec */
2036                 for (i = 3; i < 32768; i++) {
2037                         fcntl(i, F_SETFD, FD_CLOEXEC);
2038                 }
2039                 ast_verb(0, "Asterisk is now restarting...\n");
2040                 restartnow = 1;
2041
2042                 /* close logger */
2043                 close_logger();
2044                 clean_time_zones();
2045
2046                 /* If there is a consolethread running send it a SIGHUP
2047                    so it can execvp, otherwise we can do it ourselves */
2048                 if ((consolethread != AST_PTHREADT_NULL) && (consolethread != pthread_self())) {
2049                         pthread_kill(consolethread, SIGHUP);
2050                         /* Give the signal handler some time to complete */
2051                         sleep(2);
2052                 } else
2053                         execvp(_argv[0], _argv);
2054
2055         } else {
2056                 /* close logger */
2057                 close_logger();
2058                 clean_time_zones();
2059         }
2060
2061         exit(0);
2062 }
2063
2064 static void __quit_handler(int num)
2065 {
2066         int a = 0;
2067         sig_flags.need_quit = 1;
2068         if (sig_alert_pipe[1] != -1) {
2069                 if (write(sig_alert_pipe[1], &a, sizeof(a)) < 0) {
2070                         fprintf(stderr, "quit_handler: write() failed: %s\n", strerror(errno));
2071                 }
2072         }
2073         /* There is no need to restore the signal handler here, since the app
2074          * is going to exit */
2075 }
2076
2077 static void __remote_quit_handler(int num)
2078 {
2079         sig_flags.need_quit = 1;
2080 }
2081
2082 static const char *fix_header(char *outbuf, int maxout, const char *s, char *cmp)
2083 {
2084         const char *c;
2085
2086         if (!strncmp(s, cmp, strlen(cmp))) {
2087                 c = s + strlen(cmp);
2088                 term_color(outbuf, cmp, COLOR_GRAY, 0, maxout);
2089                 return c;
2090         }
2091         return NULL;
2092 }
2093
2094 /* These gymnastics are due to platforms which designate char as unsigned by
2095  * default. Level is the negative character -- offset by 1, because \0 is the
2096  * EOS delimiter. */
2097 #define VERBOSE_MAGIC2LEVEL(x) (((char) -*(signed char *) (x)) - 1)
2098 #define VERBOSE_HASMAGIC(x)     (*(signed char *) (x) < 0)
2099
2100 static void console_verboser(const char *s)
2101 {
2102         char tmp[80];
2103         const char *c = NULL;
2104         char level = 0;
2105
2106         if (VERBOSE_HASMAGIC(s)) {
2107                 level = VERBOSE_MAGIC2LEVEL(s);
2108                 s++;
2109                 if (level > option_verbose) {
2110                         return;
2111                 }
2112         }
2113
2114         if ((c = fix_header(tmp, sizeof(tmp), s, VERBOSE_PREFIX_4)) ||
2115             (c = fix_header(tmp, sizeof(tmp), s, VERBOSE_PREFIX_3)) ||
2116             (c = fix_header(tmp, sizeof(tmp), s, VERBOSE_PREFIX_2)) ||
2117             (c = fix_header(tmp, sizeof(tmp), s, VERBOSE_PREFIX_1))) {
2118                 fputs(tmp, stdout);
2119                 fputs(c, stdout);
2120         } else {
2121                 fputs(s, stdout);
2122         }
2123
2124         fflush(stdout);
2125
2126         /* Wake up a poll()ing console */
2127         if (ast_opt_console && consolethread != AST_PTHREADT_NULL) {
2128                 pthread_kill(consolethread, SIGURG);
2129         }
2130 }
2131
2132 static int ast_all_zeros(char *s)
2133 {
2134         while (*s) {
2135                 if (*s > 32)
2136                         return 0;
2137                 s++;
2138         }
2139         return 1;
2140 }
2141
2142 static void consolehandler(char *s)
2143 {
2144         printf("%s", term_end());
2145         fflush(stdout);
2146
2147         /* Called when readline data is available */
2148         if (!ast_all_zeros(s))
2149                 ast_el_add_history(s);
2150         /* The real handler for bang */
2151         if (s[0] == '!') {
2152                 if (s[1])
2153                         ast_safe_system(s+1);
2154                 else
2155                         ast_safe_system(getenv("SHELL") ? getenv("SHELL") : "/bin/sh");
2156         } else
2157                 ast_cli_command(STDOUT_FILENO, s);
2158 }
2159
2160 static int remoteconsolehandler(char *s)
2161 {
2162         int ret = 0;
2163
2164         /* Called when readline data is available */
2165         if (!ast_all_zeros(s))
2166                 ast_el_add_history(s);
2167         /* The real handler for bang */
2168         if (s[0] == '!') {
2169                 if (s[1])
2170                         ast_safe_system(s+1);
2171                 else
2172                         ast_safe_system(getenv("SHELL") ? getenv("SHELL") : "/bin/sh");
2173                 ret = 1;
2174         } else if (strncasecmp(s, "core set verbose ", 17) == 0) {
2175                 int old_verbose = option_verbose;
2176                 if (strncasecmp(s + 17, "atleast ", 8) == 0) {
2177                         int tmp;
2178                         if (sscanf(s + 25, "%d", &tmp) != 1) {
2179                                 fprintf(stderr, "Usage: core set verbose [atleast] <level>\n");
2180                         } else {
2181                                 if (tmp > option_verbose) {
2182                                         option_verbose = tmp;
2183                                 }
2184                                 if (old_verbose != option_verbose) {
2185                                         fprintf(stdout, "Set remote console verbosity from %d to %d\n", old_verbose, option_verbose);
2186                                 } else {
2187                                         fprintf(stdout, "Verbosity level unchanged.\n");
2188                                 }
2189                         }
2190                 } else {
2191                         if (sscanf(s + 17, "%d", &option_verbose) != 1) {
2192                                 fprintf(stderr, "Usage: core set verbose [atleast] <level>\n");
2193                         } else {
2194                                 if (old_verbose != option_verbose) {
2195                                         fprintf(stdout, "Set remote console verbosity to %d\n", option_verbose);
2196                                 } else {
2197                                         fprintf(stdout, "Verbosity level unchanged.\n");
2198                                 }
2199                         }
2200                 }
2201                 ret = 1;
2202         } else if ((strncasecmp(s, "quit", 4) == 0 || strncasecmp(s, "exit", 4) == 0) &&
2203             (s[4] == '\0' || isspace(s[4]))) {
2204                 quit_handler(0, SHUTDOWN_FAST, 0);
2205                 ret = 1;
2206         }
2207
2208         return ret;
2209 }
2210
2211 static char *handle_version(struct ast_cli_entry *e, int cmd, struct ast_cli_args *a)
2212 {
2213         switch (cmd) {
2214         case CLI_INIT:
2215                 e->command = "core show version";
2216                 e->usage =
2217                         "Usage: core show version\n"
2218                         "       Shows Asterisk version information.\n";
2219                 return NULL;
2220         case CLI_GENERATE:
2221                 return NULL;
2222         }
2223
2224         if (a->argc != 3)
2225                 return CLI_SHOWUSAGE;
2226         ast_cli(a->fd, "Asterisk %s built by %s @ %s on a %s running %s on %s\n",
2227                 ast_get_version(), ast_build_user, ast_build_hostname,
2228                 ast_build_machine, ast_build_os, ast_build_date);
2229         return CLI_SUCCESS;
2230 }
2231
2232 #if 0
2233 static int handle_quit(int fd, int argc, char *argv[])
2234 {
2235         if (argc != 1)
2236                 return RESULT_SHOWUSAGE;
2237         quit_handler(0, SHUTDOWN_NORMAL, 0);
2238         return RESULT_SUCCESS;
2239 }
2240 #endif
2241
2242 static char *handle_stop_now(struct ast_cli_entry *e, int cmd, struct ast_cli_args *a)
2243 {
2244         switch (cmd) {
2245         case CLI_INIT:
2246                 e->command = "core stop now";
2247                 e->usage =
2248                         "Usage: core stop now\n"
2249                         "       Shuts down a running Asterisk immediately, hanging up all active calls .\n";
2250                 return NULL;
2251         case CLI_GENERATE:
2252                 return NULL;
2253         }
2254
2255         if (a->argc != e->args)
2256                 return CLI_SHOWUSAGE;
2257         quit_handler(0, SHUTDOWN_NORMAL, 0 /* not restart */);
2258         return CLI_SUCCESS;
2259 }
2260
2261 static char *handle_stop_gracefully(struct ast_cli_entry *e, int cmd, struct ast_cli_args *a)
2262 {
2263         switch (cmd) {
2264         case CLI_INIT:
2265                 e->command = "core stop gracefully";
2266                 e->usage =
2267                         "Usage: core stop gracefully\n"
2268                         "       Causes Asterisk to not accept new calls, and exit when all\n"
2269                         "       active calls have terminated normally.\n";
2270                 return NULL;
2271         case CLI_GENERATE:
2272                 return NULL;
2273         }
2274
2275         if (a->argc != e->args)
2276                 return CLI_SHOWUSAGE;
2277         quit_handler(0, SHUTDOWN_NICE, 0 /* no restart */);
2278         return CLI_SUCCESS;
2279 }
2280
2281 static char *handle_stop_when_convenient(struct ast_cli_entry *e, int cmd, struct ast_cli_args *a)
2282 {
2283         switch (cmd) {
2284         case CLI_INIT:
2285                 e->command = "core stop when convenient";
2286                 e->usage =
2287                         "Usage: core stop when convenient\n"
2288                         "       Causes Asterisk to perform a shutdown when all active calls have ended.\n";
2289                 return NULL;
2290         case CLI_GENERATE:
2291                 return NULL;
2292         }
2293
2294         if (a->argc != e->args)
2295                 return CLI_SHOWUSAGE;
2296         ast_cli(a->fd, "Waiting for inactivity to perform halt\n");
2297         quit_handler(0, SHUTDOWN_REALLY_NICE, 0 /* don't restart */);
2298         return CLI_SUCCESS;
2299 }
2300
2301 static char *handle_restart_now(struct ast_cli_entry *e, int cmd, struct ast_cli_args *a)
2302 {
2303         switch (cmd) {
2304         case CLI_INIT:
2305                 e->command = "core restart now";
2306                 e->usage =
2307                         "Usage: core restart now\n"
2308                         "       Causes Asterisk to hangup all calls and exec() itself performing a cold\n"
2309                         "       restart.\n";
2310                 return NULL;
2311         case CLI_GENERATE:
2312                 return NULL;
2313         }
2314
2315         if (a->argc != e->args)
2316                 return CLI_SHOWUSAGE;
2317         quit_handler(0, SHUTDOWN_NORMAL, 1 /* restart */);
2318         return CLI_SUCCESS;
2319 }
2320
2321 static char *handle_restart_gracefully(struct ast_cli_entry *e, int cmd, struct ast_cli_args *a)
2322 {
2323         switch (cmd) {
2324         case CLI_INIT:
2325                 e->command = "core restart gracefully";
2326                 e->usage =
2327                         "Usage: core restart gracefully\n"
2328                         "       Causes Asterisk to stop accepting new calls and exec() itself performing a cold\n"
2329                         "       restart when all active calls have ended.\n";
2330                 return NULL;
2331         case CLI_GENERATE:
2332                 return NULL;
2333         }
2334
2335         if (a->argc != e->args)
2336                 return CLI_SHOWUSAGE;
2337         quit_handler(0, SHUTDOWN_NICE, 1 /* restart */);
2338         return CLI_SUCCESS;
2339 }
2340
2341 static char *handle_restart_when_convenient(struct ast_cli_entry *e, int cmd, struct ast_cli_args *a)
2342 {
2343         switch (cmd) {
2344         case CLI_INIT:
2345                 e->command = "core restart when convenient";
2346                 e->usage =
2347                         "Usage: core restart when convenient\n"
2348                         "       Causes Asterisk to perform a cold restart when all active calls have ended.\n";
2349                 return NULL;
2350         case CLI_GENERATE:
2351                 return NULL;
2352         }
2353
2354         if (a->argc != e->args)
2355                 return CLI_SHOWUSAGE;
2356         ast_cli(a->fd, "Waiting for inactivity to perform restart\n");
2357         quit_handler(0, SHUTDOWN_REALLY_NICE, 1 /* restart */);
2358         return CLI_SUCCESS;
2359 }
2360
2361 static char *handle_abort_shutdown(struct ast_cli_entry *e, int cmd, struct ast_cli_args *a)
2362 {
2363         int aborting_shutdown = 0;
2364
2365         switch (cmd) {
2366         case CLI_INIT:
2367                 e->command = "core abort shutdown";
2368                 e->usage =
2369                         "Usage: core abort shutdown\n"
2370                         "       Causes Asterisk to abort an executing shutdown or restart, and resume normal\n"
2371                         "       call operations.\n";
2372                 return NULL;
2373         case CLI_GENERATE:
2374                 return NULL;
2375         }
2376
2377         if (a->argc != e->args)
2378                 return CLI_SHOWUSAGE;
2379
2380         ast_mutex_lock(&safe_system_lock);
2381         if (shuttingdown >= SHUTDOWN_FAST) {
2382                 aborting_shutdown = 1;
2383                 shuttingdown = NOT_SHUTTING_DOWN;
2384         }
2385         ast_mutex_unlock(&safe_system_lock);
2386
2387         if (aborting_shutdown) {
2388                 ast_cancel_shutdown();
2389         }
2390         return CLI_SUCCESS;
2391 }
2392
2393 static char *handle_bang(struct ast_cli_entry *e, int cmd, struct ast_cli_args *a)
2394 {
2395         switch (cmd) {
2396         case CLI_INIT:
2397                 e->command = "!";
2398                 e->usage =
2399                         "Usage: !<command>\n"
2400                         "       Executes a given shell command\n";
2401                 return NULL;
2402         case CLI_GENERATE:
2403                 return NULL;
2404         }
2405
2406         return CLI_SUCCESS;
2407 }
2408 static const char warranty_lines[] = {
2409         "\n"
2410         "                           NO WARRANTY\n"
2411         "\n"
2412         "BECAUSE THE PROGRAM IS LICENSED FREE OF CHARGE, THERE IS NO WARRANTY\n"
2413         "FOR THE PROGRAM, TO THE EXTENT PERMITTED BY APPLICABLE LAW.  EXCEPT WHEN\n"
2414         "OTHERWISE STATED IN WRITING THE COPYRIGHT HOLDERS AND/OR OTHER PARTIES\n"
2415         "PROVIDE THE PROGRAM \"AS IS\" WITHOUT WARRANTY OF ANY KIND, EITHER EXPRESSED\n"
2416         "OR IMPLIED, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF\n"
2417         "MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE.  THE ENTIRE RISK AS\n"
2418         "TO THE QUALITY AND PERFORMANCE OF THE PROGRAM IS WITH YOU.  SHOULD THE\n"
2419         "PROGRAM PROVE DEFECTIVE, YOU ASSUME THE COST OF ALL NECESSARY SERVICING,\n"
2420         "REPAIR OR CORRECTION.\n"
2421         "\n"
2422         "IN NO EVENT UNLESS REQUIRED BY APPLICABLE LAW OR AGREED TO IN WRITING\n"
2423         "WILL ANY COPYRIGHT HOLDER, OR ANY OTHER PARTY WHO MAY MODIFY AND/OR\n"
2424         "REDISTRIBUTE THE PROGRAM AS PERMITTED ABOVE, BE LIABLE TO YOU FOR DAMAGES,\n"
2425         "INCLUDING ANY GENERAL, SPECIAL, INCIDENTAL OR CONSEQUENTIAL DAMAGES ARISING\n"
2426         "OUT OF THE USE OR INABILITY TO USE THE PROGRAM (INCLUDING BUT NOT LIMITED\n"
2427         "TO LOSS OF DATA OR DATA BEING RENDERED INACCURATE OR LOSSES SUSTAINED BY\n"
2428         "YOU OR THIRD PARTIES OR A FAILURE OF THE PROGRAM TO OPERATE WITH ANY OTHER\n"
2429         "PROGRAMS), EVEN IF SUCH HOLDER OR OTHER PARTY HAS BEEN ADVISED OF THE\n"
2430         "POSSIBILITY OF SUCH DAMAGES.\n"
2431 };
2432
2433 static char *show_warranty(struct ast_cli_entry *e, int cmd, struct ast_cli_args *a)
2434 {
2435         switch (cmd) {
2436         case CLI_INIT:
2437                 e->command = "core show warranty";
2438                 e->usage =
2439                         "Usage: core show warranty\n"
2440                         "       Shows the warranty (if any) for this copy of Asterisk.\n";
2441                 return NULL;
2442         case CLI_GENERATE:
2443                 return NULL;
2444         }
2445
2446         ast_cli(a->fd, "%s", warranty_lines);
2447
2448         return CLI_SUCCESS;
2449 }
2450
2451 static const char license_lines[] = {
2452         "\n"
2453         "This program is free software; you can redistribute it and/or modify\n"
2454         "it under the terms of the GNU General Public License version 2 as\n"
2455         "published by the Free Software Foundation.\n"
2456         "\n"
2457         "This program also contains components licensed under other licenses.\n"
2458         "They include:\n"
2459         "\n"
2460         "This program is distributed in the hope that it will be useful,\n"
2461         "but WITHOUT ANY WARRANTY; without even the implied warranty of\n"
2462         "MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the\n"
2463         "GNU General Public License for more details.\n"
2464         "\n"
2465         "You should have received a copy of the GNU General Public License\n"
2466         "along with this program; if not, write to the Free Software\n"
2467         "Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA\n"
2468 };
2469
2470 static char *show_license(struct ast_cli_entry *e, int cmd, struct ast_cli_args *a)
2471 {
2472         switch (cmd) {
2473         case CLI_INIT:
2474                 e->command = "core show license";
2475                 e->usage =
2476                         "Usage: core show license\n"
2477                         "       Shows the license(s) for this copy of Asterisk.\n";
2478                 return NULL;
2479         case CLI_GENERATE:
2480                 return NULL;
2481         }
2482
2483         ast_cli(a->fd, "%s", license_lines);
2484
2485         return CLI_SUCCESS;
2486 }
2487
2488 #define ASTERISK_PROMPT "*CLI> "
2489
2490 #define ASTERISK_PROMPT2 "%s*CLI> "
2491
2492 /*!
2493  * \brief Shutdown Asterisk CLI commands.
2494  *
2495  * \note These CLI commands cannot be unregistered at shutdown
2496  * because one of them is likely the reason for the shutdown.
2497  * The CLI generates a warning if a command is in-use when it is
2498  * unregistered.
2499  */
2500 static struct ast_cli_entry cli_asterisk_shutdown[] = {
2501         AST_CLI_DEFINE(handle_stop_now, "Shut down Asterisk immediately"),
2502         AST_CLI_DEFINE(handle_stop_gracefully, "Gracefully shut down Asterisk"),
2503         AST_CLI_DEFINE(handle_stop_when_convenient, "Shut down Asterisk at empty call volume"),
2504         AST_CLI_DEFINE(handle_restart_now, "Restart Asterisk immediately"),
2505         AST_CLI_DEFINE(handle_restart_gracefully, "Restart Asterisk gracefully"),
2506         AST_CLI_DEFINE(handle_restart_when_convenient, "Restart Asterisk at empty call volume"),
2507 };
2508
2509 static struct ast_cli_entry cli_asterisk[] = {
2510         AST_CLI_DEFINE(handle_abort_shutdown, "Cancel a running shutdown"),
2511         AST_CLI_DEFINE(show_warranty, "Show the warranty (if any) for this copy of Asterisk"),
2512         AST_CLI_DEFINE(show_license, "Show the license(s) for this copy of Asterisk"),
2513         AST_CLI_DEFINE(handle_version, "Display version info"),
2514         AST_CLI_DEFINE(handle_bang, "Execute a shell command"),
2515 #if !defined(LOW_MEMORY)
2516         AST_CLI_DEFINE(handle_show_version_files, "List versions of files used to build Asterisk"),
2517         AST_CLI_DEFINE(handle_show_threads, "Show running threads"),
2518 #if defined(HAVE_SYSINFO) || defined(HAVE_SYSCTL)
2519         AST_CLI_DEFINE(handle_show_sysinfo, "Show System Information"),
2520 #endif
2521         AST_CLI_DEFINE(handle_show_profile, "Display profiling info"),
2522         AST_CLI_DEFINE(handle_show_settings, "Show some core settings"),
2523         AST_CLI_DEFINE(handle_clear_profile, "Clear profiling info"),
2524 #endif /* ! LOW_MEMORY */
2525 };
2526
2527 struct el_read_char_state_struct {
2528         unsigned int line_full:1;
2529         unsigned int prev_line_full:1;
2530         char prev_line_verbosity;
2531 };
2532
2533 static int el_read_char_state_init(void *ptr)
2534 {
2535         struct el_read_char_state_struct *state = ptr;
2536         state->line_full = 1;
2537         state->prev_line_full = 1;
2538         state->prev_line_verbosity = 0;
2539         return 0;
2540 }
2541
2542 AST_THREADSTORAGE_CUSTOM(el_read_char_state, el_read_char_state_init, ast_free_ptr);
2543
2544 static int ast_el_read_char(EditLine *editline, char *cp)
2545 {
2546         int num_read = 0;
2547         int lastpos = 0;
2548         struct pollfd fds[2];
2549         int res;
2550         int max;
2551 #define EL_BUF_SIZE 512
2552         char buf[EL_BUF_SIZE];
2553         struct el_read_char_state_struct *state = ast_threadstorage_get(&el_read_char_state, sizeof(*state));
2554
2555         for (;;) {
2556                 max = 1;
2557                 fds[0].fd = ast_consock;
2558                 fds[0].events = POLLIN;
2559                 if (!ast_opt_exec) {
2560                         fds[1].fd = STDIN_FILENO;
2561                         fds[1].events = POLLIN;
2562                         max++;
2563                 }
2564                 res = ast_poll(fds, max, -1);
2565                 if (res < 0) {
2566                         if (sig_flags.need_quit || sig_flags.need_quit_handler)
2567                                 break;
2568                         if (errno == EINTR)
2569                                 continue;
2570                         fprintf(stderr, "poll failed: %s\n", strerror(errno));
2571                         break;
2572                 }
2573
2574                 if (!ast_opt_exec && fds[1].revents) {
2575                         num_read = read(STDIN_FILENO, cp, 1);
2576                         if (num_read < 1) {
2577                                 break;
2578                         } else {
2579                                 return (num_read);
2580                         }
2581                 }
2582                 if (fds[0].revents) {
2583                         char level = 0;
2584                         char *curline = buf, *nextline;
2585                         res = read(ast_consock, buf, sizeof(buf) - 1);
2586                         /* if the remote side disappears exit */
2587                         if (res < 1) {
2588                                 fprintf(stderr, "\nDisconnected from Asterisk server\n");
2589                                 if (!ast_opt_reconnect) {
2590                                         quit_handler(0, SHUTDOWN_FAST, 0);
2591                                 } else {
2592                                         int tries;
2593                                         int reconnects_per_second = 20;
2594                                         fprintf(stderr, "Attempting to reconnect for 30 seconds\n");
2595                                         for (tries = 0; tries < 30 * reconnects_per_second; tries++) {
2596                                                 if (ast_tryconnect()) {
2597                                                         fprintf(stderr, "Reconnect succeeded after %.3f seconds\n", 1.0 / reconnects_per_second * tries);
2598                                                         printf("%s", term_quit());
2599                                                         WELCOME_MESSAGE;
2600                                                         if (!ast_opt_mute)
2601                                                                 fdsend(ast_consock, "logger mute silent");
2602                                                         else
2603                                                                 printf("log and verbose output currently muted ('logger mute' to unmute)\n");
2604                                                         break;
2605                                                 } else
2606                                                         usleep(1000000 / reconnects_per_second);
2607                                         }
2608                                         if (tries >= 30 * reconnects_per_second) {
2609                                                 fprintf(stderr, "Failed to reconnect for 30 seconds.  Quitting.\n");
2610                                                 quit_handler(0, SHUTDOWN_FAST, 0);
2611                                         }
2612                                 }
2613                                 continue;
2614                         }
2615
2616                         buf[res] = '\0';
2617
2618                         /* Write over the CLI prompt */
2619                         if (!ast_opt_exec && !lastpos) {
2620                                 if (write(STDOUT_FILENO, "\r\e[0K", 5) < 0) {
2621                                 }
2622                         }
2623
2624                         do {
2625                                 state->prev_line_full = state->line_full;
2626                                 if ((nextline = strchr(curline, '\n'))) {
2627                                         state->line_full = 1;
2628                                         nextline++;
2629                                 } else {
2630                                         state->line_full = 0;
2631                                         nextline = strchr(curline, '\0');
2632                                 }
2633
2634                                 if (state->prev_line_full && VERBOSE_HASMAGIC(curline)) {
2635                                         level = VERBOSE_MAGIC2LEVEL(curline);
2636                                         curline++;
2637                                 } else if (state->prev_line_full && !VERBOSE_HASMAGIC(curline)) {
2638                                         /* Non-verbose output */
2639                                         level = 0;
2640                                 } else {
2641                                         level = state->prev_line_verbosity;
2642                                 }
2643                                 if ((!state->prev_line_full && state->prev_line_verbosity <= option_verbose) || (state->prev_line_full && level <= option_verbose)) {
2644                                         if (write(STDOUT_FILENO, curline, nextline - curline) < 0) {
2645                                         }
2646                                 }
2647
2648                                 state->prev_line_verbosity = level;
2649                                 curline = nextline;
2650                         } while (!ast_strlen_zero(curline));
2651
2652                         if ((res < EL_BUF_SIZE - 1) && ((buf[res-1] == '\n') || (buf[res-2] == '\n'))) {
2653                                 *cp = CC_REFRESH;
2654                                 return(1);
2655                         } else
2656                                 lastpos = 1;
2657                 }
2658         }
2659
2660         *cp = '\0';
2661         return (0);
2662 }
2663
2664 static struct ast_str *prompt = NULL;
2665
2666 static char *cli_prompt(EditLine *editline)
2667 {
2668         char tmp[100];
2669         char *pfmt;
2670         int color_used = 0;
2671         static int cli_prompt_changes = 0;
2672         struct passwd *pw;
2673         struct group *gr;
2674
2675         if (prompt == NULL) {
2676                 prompt = ast_str_create(100);
2677         } else if (!cli_prompt_changes) {
2678                 return ast_str_buffer(prompt);
2679         } else {
2680                 ast_str_reset(prompt);
2681         }
2682
2683         if ((pfmt = getenv("ASTERISK_PROMPT"))) {
2684                 char *t = pfmt;
2685                 struct timeval ts = ast_tvnow();
2686                 while (*t != '\0') {
2687                         if (*t == '%') {
2688                                 char hostname[MAXHOSTNAMELEN] = "";
2689                                 int i, which;
2690                                 struct ast_tm tm = { 0, };
2691                                 int fgcolor = COLOR_WHITE, bgcolor = COLOR_BLACK;
2692
2693                                 t++;
2694                                 switch (*t) {
2695                                 case 'C': /* color */
2696                                         t++;
2697                                         if (sscanf(t, "%30d;%30d%n", &fgcolor, &bgcolor, &i) == 2) {
2698                                                 ast_term_color_code(&prompt, fgcolor, bgcolor);
2699                                                 t += i - 1;
2700                                         } else if (sscanf(t, "%30d%n", &fgcolor, &i) == 1) {
2701                                                 ast_term_color_code(&prompt, fgcolor, 0);
2702                                                 t += i - 1;
2703                                         }
2704
2705                                         /* If the color has been reset correctly, then there's no need to reset it later */
2706                                         color_used = ((fgcolor == COLOR_WHITE) && (bgcolor == COLOR_BLACK)) ? 0 : 1;
2707                                         break;
2708                                 case 'd': /* date */
2709                                         if (ast_localtime(&ts, &tm, NULL)) {
2710                                                 ast_strftime(tmp, sizeof(tmp), "%Y-%m-%d", &tm);
2711                                                 ast_str_append(&prompt, 0, "%s", tmp);
2712                                                 cli_prompt_changes++;
2713                                         }
2714                                         break;
2715                                 case 'g': /* group */
2716                                         if ((gr = getgrgid(getgid()))) {
2717                                                 ast_str_append(&prompt, 0, "%s", gr->gr_name);
2718                                         }
2719                                         break;
2720                                 case 'h': /* hostname */
2721                                         if (!gethostname(hostname, sizeof(hostname) - 1)) {
2722                                                 ast_str_append(&prompt, 0, "%s", hostname);
2723                                         } else {
2724                                                 ast_str_append(&prompt, 0, "%s", "localhost");
2725                                         }
2726                                         break;
2727                                 case 'H': /* short hostname */
2728                                         if (!gethostname(hostname, sizeof(hostname) - 1)) {
2729                                                 char *dotptr;
2730                                                 if ((dotptr = strchr(hostname, '.'))) {
2731                                                         *dotptr = '\0';
2732                                                 }
2733                                                 ast_str_append(&prompt, 0, "%s", hostname);
2734                                         } else {
2735                                                 ast_str_append(&prompt, 0, "%s", "localhost");
2736                                         }
2737                                         break;
2738 #ifdef HAVE_GETLOADAVG
2739                                 case 'l': /* load avg */
2740                                         t++;
2741                                         if (sscanf(t, "%30d", &which) == 1 && which > 0 && which <= 3) {
2742                                                 double list[3];
2743                                                 getloadavg(list, 3);
2744                                                 ast_str_append(&prompt, 0, "%.2f", list[which - 1]);
2745                                                 cli_prompt_changes++;
2746                                         }
2747                                         break;
2748 #endif
2749                                 case 's': /* Asterisk system name (from asterisk.conf) */
2750                                         ast_str_append(&prompt, 0, "%s", ast_config_AST_SYSTEM_NAME);
2751                                         break;
2752                                 case 't': /* time */
2753                                         if (ast_localtime(&ts, &tm, NULL)) {
2754                                                 ast_strftime(tmp, sizeof(tmp), "%H:%M:%S", &tm);
2755                                                 ast_str_append(&prompt, 0, "%s", tmp);
2756                                                 cli_prompt_changes++;
2757                                         }
2758                                         break;
2759                                 case 'u': /* username */
2760                                         if ((pw = getpwuid(getuid()))) {
2761                                                 ast_str_append(&prompt, 0, "%s", pw->pw_name);
2762                                         }
2763                                         break;
2764                                 case '#': /* process console or remote? */
2765                                         ast_str_append(&prompt, 0, "%c", ast_opt_remote ? '>' : '#');
2766                                         break;
2767                                 case '%': /* literal % */
2768                                         ast_str_append(&prompt, 0, "%c", '%');
2769                                         break;
2770                                 case '\0': /* % is last character - prevent bug */
2771                                         t--;
2772                                         break;
2773                                 }
2774                         } else {
2775                                 ast_str_append(&prompt, 0, "%c", *t);
2776                         }
2777                         t++;
2778                 }
2779                 if (color_used) {
2780                         /* Force colors back to normal at end */
2781                         ast_term_color_code(&prompt, 0, 0);
2782                 }
2783         } else if (remotehostname) {
2784                 ast_str_set(&prompt, 0, ASTERISK_PROMPT2, remotehostname);
2785         } else {
2786                 ast_str_set(&prompt, 0, "%s", ASTERISK_PROMPT);
2787         }
2788
2789         return ast_str_buffer(prompt);
2790 }
2791
2792 static char **ast_el_strtoarr(char *buf)
2793 {
2794         char **match_list = NULL, **match_list_tmp, *retstr;
2795         size_t match_list_len;
2796         int matches = 0;
2797
2798         match_list_len = 1;
2799         while ( (retstr = strsep(&buf, " ")) != NULL) {
2800
2801                 if (!strcmp(retstr, AST_CLI_COMPLETE_EOF))
2802                         break;
2803                 if (matches + 1 >= match_list_len) {
2804                         match_list_len <<= 1;
2805                         if ((match_list_tmp = ast_realloc(match_list, match_list_len * sizeof(char *)))) {
2806                                 match_list = match_list_tmp;
2807                         } else {
2808                                 if (match_list)
2809                                         ast_free(match_list);
2810                                 return (char **) NULL;
2811                         }
2812                 }
2813
2814                 match_list[matches++] = ast_strdup(retstr);
2815         }
2816
2817         if (!match_list)
2818                 return (char **) NULL;
2819
2820         if (matches >= match_list_len) {
2821                 if ((match_list_tmp = ast_realloc(match_list, (match_list_len + 1) * sizeof(char *)))) {
2822                         match_list = match_list_tmp;
2823                 } else {
2824                         if (match_list)
2825                                 ast_free(match_list);
2826                         return (char **) NULL;
2827                 }
2828         }
2829
2830         match_list[matches] = (char *) NULL;
2831
2832         return match_list;
2833 }
2834
2835 static int ast_el_sort_compare(const void *i1, const void *i2)
2836 {
2837         char *s1, *s2;
2838
2839         s1 = ((char **)i1)[0];
2840         s2 = ((char **)i2)[0];
2841
2842         return strcasecmp(s1, s2);
2843 }
2844
2845 static int ast_cli_display_match_list(char **matches, int len, int max)
2846 {
2847         int i, idx, limit, count;
2848         int screenwidth = 0;
2849         int numoutput = 0, numoutputline = 0;
2850
2851         screenwidth = ast_get_termcols(STDOUT_FILENO);
2852
2853         /* find out how many entries can be put on one line, with two spaces between strings */
2854         limit = screenwidth / (max + 2);
2855         if (limit == 0)
2856                 limit = 1;
2857
2858         /* how many lines of output */
2859         count = len / limit;
2860         if (count * limit < len)
2861                 count++;
2862
2863         idx = 1;
2864
2865         qsort(&matches[0], (size_t)(len), sizeof(char *), ast_el_sort_compare);
2866
2867         for (; count > 0; count--) {
2868                 numoutputline = 0;
2869                 for (i = 0; i < limit && matches[idx]; i++, idx++) {
2870
2871                         /* Don't print dupes */
2872                         if ( (matches[idx+1] != NULL && strcmp(matches[idx], matches[idx+1]) == 0 ) ) {
2873                                 i--;
2874                                 ast_free(matches[idx]);
2875                                 matches[idx] = NULL;
2876                                 continue;
2877                         }
2878
2879                         numoutput++;
2880                         numoutputline++;
2881                         fprintf(stdout, "%-*s  ", max, matches[idx]);
2882                         ast_free(matches[idx]);
2883                         matches[idx] = NULL;
2884                 }
2885                 if (numoutputline > 0)
2886                         fprintf(stdout, "\n");
2887         }
2888
2889         return numoutput;
2890 }
2891
2892
2893 static char *cli_complete(EditLine *editline, int ch)
2894 {
2895         int len = 0;
2896         char *ptr;
2897         int nummatches = 0;
2898         char **matches;
2899         int retval = CC_ERROR;
2900         char buf[2048], savechr;
2901         int res;
2902
2903         LineInfo *lf = (LineInfo *)el_line(editline);
2904
2905         savechr = *(char *)lf->cursor;
2906         *(char *)lf->cursor = '\0';
2907         ptr = (char *)lf->cursor;
2908         if (ptr) {
2909                 while (ptr > lf->buffer) {
2910                         if (isspace(*ptr)) {
2911                                 ptr++;
2912                                 break;
2913                         }
2914                         ptr--;
2915                 }
2916         }
2917
2918         len = lf->cursor - ptr;
2919
2920         if (ast_opt_remote) {
2921                 snprintf(buf, sizeof(buf), "_COMMAND NUMMATCHES \"%s\" \"%s\"", lf->buffer, ptr);
2922                 fdsend(ast_consock, buf);
2923                 if ((res = read(ast_consock, buf, sizeof(buf) - 1)) < 0) {
2924                         return (char*)(CC_ERROR);
2925                 }
2926                 buf[res] = '\0';
2927                 nummatches = atoi(buf);
2928
2929                 if (nummatches > 0) {
2930                         char *mbuf;
2931                         int mlen = 0, maxmbuf = 2048;
2932                         /* Start with a 2048 byte buffer */
2933                         if (!(mbuf = ast_malloc(maxmbuf))) {
2934                                 *((char *) lf->cursor) = savechr;
2935                                 return (char *)(CC_ERROR);
2936                         }
2937                         snprintf(buf, sizeof(buf), "_COMMAND MATCHESARRAY \"%s\" \"%s\"", lf->buffer, ptr);
2938                         fdsend(ast_consock, buf);
2939                         res = 0;
2940                         mbuf[0] = '\0';
2941                         while (!strstr(mbuf, AST_CLI_COMPLETE_EOF) && res != -1) {
2942                                 if (mlen + 1024 > maxmbuf) {
2943                                         /* Every step increment buffer 1024 bytes */
2944                                         maxmbuf += 1024;
2945                                         if (!(mbuf = ast_realloc(mbuf, maxmbuf))) {
2946                                                 *((char *) lf->cursor) = savechr;
2947                                                 return (char *)(CC_ERROR);
2948                                         }
2949                                 }
2950                                 /* Only read 1024 bytes at a time */
2951                                 res = read(ast_consock, mbuf + mlen, 1024);
2952                                 if (res > 0)
2953                                         mlen += res;
2954                         }
2955                         mbuf[mlen] = '\0';
2956
2957                         matches = ast_el_strtoarr(mbuf);
2958                         ast_free(mbuf);
2959                 } else
2960                         matches = (char **) NULL;
2961         } else {
2962                 char **p, *oldbuf=NULL;
2963                 nummatches = 0;
2964                 matches = ast_cli_completion_matches((char *)lf->buffer,ptr);
2965                 for (p = matches; p && *p; p++) {
2966                         if (!oldbuf || strcmp(*p,oldbuf))
2967                                 nummatches++;
2968                         oldbuf = *p;
2969                 }
2970         }
2971
2972         if (matches) {
2973                 int i;
2974                 int matches_num, maxlen, match_len;
2975
2976                 if (matches[0][0] != '\0') {
2977                         el_deletestr(editline, (int) len);
2978                         el_insertstr(editline, matches[0]);
2979                         retval = CC_REFRESH;
2980                 }
2981
2982                 if (nummatches == 1) {
2983                         /* Found an exact match */
2984                         el_insertstr(editline, " ");
2985                         retval = CC_REFRESH;
2986                 } else {
2987                         /* Must be more than one match */
2988                         for (i = 1, maxlen = 0; matches[i]; i++) {
2989                                 match_len = strlen(matches[i]);
2990                                 if (match_len > maxlen)
2991                                         maxlen = match_len;
2992                         }
2993                         matches_num = i - 1;
2994                         if (matches_num >1) {
2995                                 fprintf(stdout, "\n");
2996                                 ast_cli_display_match_list(matches, nummatches, maxlen);
2997                                 retval = CC_REDISPLAY;
2998                         } else {
2999                                 el_insertstr(editline," ");
3000                                 retval = CC_REFRESH;
3001                         }
3002                 }
3003                 for (i = 0; matches[i]; i++)
3004                         ast_free(matches[i]);
3005                 ast_free(matches);
3006         }
3007
3008         *((char *) lf->cursor) = savechr;
3009
3010         return (char *)(long)retval;
3011 }
3012
3013 static int ast_el_initialize(void)
3014 {
3015         HistEvent ev;
3016         char *editor, *editrc = getenv("EDITRC");
3017
3018         if (!(editor = getenv("AST_EDITMODE"))) {
3019                 if (!(editor = getenv("AST_EDITOR"))) {
3020                         editor = "emacs";
3021                 }
3022         }
3023
3024         if (el != NULL)
3025                 el_end(el);
3026         if (el_hist != NULL)
3027                 history_end(el_hist);
3028
3029         el = el_init("asterisk", stdin, stdout, stderr);
3030         el_set(el, EL_PROMPT, cli_prompt);
3031
3032         el_set(el, EL_EDITMODE, 1);
3033         el_set(el, EL_EDITOR, editor);
3034         el_hist = history_init();
3035         if (!el || !el_hist)
3036                 return -1;
3037
3038         /* setup history with 100 entries */
3039         history(el_hist, &ev, H_SETSIZE, 100);
3040
3041         el_set(el, EL_HIST, history, el_hist);
3042
3043         el_set(el, EL_ADDFN, "ed-complete", "Complete argument", cli_complete);
3044         /* Bind <tab> to command completion */
3045         el_set(el, EL_BIND, "^I", "ed-complete", NULL);
3046         /* Bind ? to command completion */
3047         el_set(el, EL_BIND, "?", "ed-complete", NULL);
3048         /* Bind ^D to redisplay */
3049         el_set(el, EL_BIND, "^D", "ed-redisplay", NULL);
3050         /* Bind Delete to delete char left */
3051         el_set(el, EL_BIND, "\\e[3~", "ed-delete-next-char", NULL);
3052         /* Bind Home and End to move to line start and end */
3053         el_set(el, EL_BIND, "\\e[1~", "ed-move-to-beg", NULL);
3054         el_set(el, EL_BIND, "\\e[4~", "ed-move-to-end", NULL);
3055         /* Bind C-left and C-right to move by word (not all terminals) */
3056         el_set(el, EL_BIND, "\\eOC", "vi-next-word", NULL);
3057         el_set(el, EL_BIND, "\\eOD", "vi-prev-word", NULL);
3058
3059         if (editrc) {
3060                 el_source(el, editrc);
3061         }
3062
3063         return 0;
3064 }
3065
3066 #define MAX_HISTORY_COMMAND_LENGTH 256
3067
3068 static int ast_el_add_history(char *buf)
3069 {
3070         HistEvent ev;
3071
3072         if (el_hist == NULL || el == NULL)
3073                 ast_el_initialize();
3074         if (strlen(buf) > (MAX_HISTORY_COMMAND_LENGTH - 1))
3075                 return 0;
3076         return (history(el_hist, &ev, H_ENTER, ast_strip(ast_strdupa(buf))));
3077 }
3078
3079 static int ast_el_write_history(char *filename)
3080 {
3081         HistEvent ev;
3082
3083         if (el_hist == NULL || el == NULL)
3084                 ast_el_initialize();
3085
3086         return (history(el_hist, &ev, H_SAVE, filename));
3087 }
3088
3089 static int ast_el_read_history(char *filename)
3090 {
3091         HistEvent ev;
3092
3093         if (el_hist == NULL || el == NULL) {
3094                 ast_el_initialize();
3095         }
3096
3097         return history(el_hist, &ev, H_LOAD, filename);
3098 }
3099
3100 static void ast_remotecontrol(char *data)
3101 {
3102         char buf[80];
3103         int res;
3104         char filename[80] = "";
3105         char *hostname;
3106         char *cpid;
3107         char *version;
3108         int pid;
3109         char *stringp = NULL;
3110
3111         char *ebuf;
3112         int num = 0;
3113
3114         memset(&sig_flags, 0, sizeof(sig_flags));
3115         signal(SIGINT, __remote_quit_handler);
3116         signal(SIGTERM, __remote_quit_handler);
3117         signal(SIGHUP, __remote_quit_handler);
3118
3119         if (read(ast_consock, buf, sizeof(buf)) < 0) {
3120                 ast_log(LOG_ERROR, "read() failed: %s\n", strerror(errno));
3121                 return;
3122         }
3123         if (data) {
3124                 char prefix[] = "cli quit after ";
3125                 char *tmp = ast_alloca(strlen(data) + strlen(prefix) + 1);
3126                 sprintf(tmp, "%s%s", prefix, data);
3127                 if (write(ast_consock, tmp, strlen(tmp) + 1) < 0) {
3128                         ast_log(LOG_ERROR, "write() failed: %s\n", strerror(errno));
3129                         if (sig_flags.need_quit || sig_flags.need_quit_handler) {
3130                                 return;
3131                         }
3132                 }
3133         }
3134         stringp = buf;
3135         hostname = strsep(&stringp, "/");
3136         cpid = strsep(&stringp, "/");
3137         version = strsep(&stringp, "\n");
3138         if (!version)
3139                 version = "<Version Unknown>";
3140         stringp = hostname;
3141         strsep(&stringp, ".");
3142         if (cpid)
3143                 pid = atoi(cpid);
3144         else
3145                 pid = -1;
3146         if (!data) {
3147                 if (!ast_opt_mute) {
3148                         fdsend(ast_consock, "logger mute silent");
3149                 } else {
3150                         printf("log and verbose output currently muted ('logger mute' to unmute)\n");
3151                 }
3152         }
3153
3154         if (ast_opt_exec && data) {  /* hack to print output then exit if asterisk -rx is used */
3155                 int linefull = 1, prev_linefull = 1, prev_line_verbose = 0;
3156                 struct pollfd fds;
3157                 fds.fd = ast_consock;
3158                 fds.events = POLLIN;
3159                 fds.revents = 0;
3160
3161                 while (ast_poll(&fds, 1, 60000) > 0) {
3162                         char buffer[512] = "", *curline = buffer, *nextline;
3163                         int not_written = 1;
3164
3165                         if (sig_flags.need_quit || sig_flags.need_quit_handler) {
3166                                 break;
3167                         }
3168
3169                         if (read(ast_consock, buffer, sizeof(buffer) - 1) <= 0) {
3170                                 break;
3171                         }
3172
3173                         do {
3174                                 prev_linefull = linefull;
3175                                 if ((nextline = strchr(curline, '\n'))) {
3176                                         linefull = 1;
3177                                         nextline++;
3178                                 } else {
3179                                         linefull = 0;
3180                                         nextline = strchr(curline, '\0');
3181                                 }
3182
3183                                 /* Skip verbose lines */
3184                                 /* Prev line full? | Line is verbose | Last line verbose? | Print
3185                                  * TRUE            | TRUE*           | TRUE               | FALSE
3186                                  * TRUE            | TRUE*           | FALSE              | FALSE
3187                                  * TRUE            | FALSE*          | TRUE               | TRUE
3188                                  * TRUE            | FALSE*          | FALSE              | TRUE
3189                                  * FALSE           | TRUE            | TRUE*              | FALSE
3190                                  * FALSE           | TRUE            | FALSE*             | TRUE
3191                                  * FALSE           | FALSE           | TRUE*              | FALSE
3192                                  * FALSE           | FALSE           | FALSE*             | TRUE
3193                                  */
3194                                 if ((!prev_linefull && !prev_line_verbose) || (prev_linefull && *curline > 0)) {
3195                                         prev_line_verbose = 0;
3196                                         not_written = 0;
3197                                         if (write(STDOUT_FILENO, curline, nextline - curline) < 0) {
3198                                                 ast_log(LOG_WARNING, "write() failed: %s\n", strerror(errno));
3199                                         }
3200                                 } else {
3201                                         prev_line_verbose = 1;
3202                                 }
3203                                 curline = nextline;
3204                         } while (!ast_strlen_zero(curline));
3205
3206                         /* No non-verbose output in 60 seconds. */
3207                         if (not_written) {
3208                                 break;
3209                         }
3210                 }
3211                 return;
3212         }
3213
3214         ast_verbose("Connected to Asterisk %s currently running on %s (pid = %d)\n", version, hostname, pid);
3215         remotehostname = hostname;
3216         if (getenv("HOME"))
3217                 snprintf(filename, sizeof(filename), "%s/.asterisk_history", getenv("HOME"));
3218         if (el_hist == NULL || el == NULL)
3219                 ast_el_initialize();
3220
3221         el_set(el, EL_GETCFN, ast_el_read_char);
3222
3223         if (!ast_strlen_zero(filename))
3224                 ast_el_read_history(filename);
3225
3226         for (;;) {
3227                 ebuf = (char *)el_gets(el, &num);
3228
3229                 if (sig_flags.need_quit || sig_flags.need_quit_handler) {
3230                         break;
3231                 }
3232
3233                 if (!ebuf && write(1, "", 1) < 0)
3234                         break;
3235
3236                 if (!ast_strlen_zero(ebuf)) {
3237                         if (ebuf[strlen(ebuf)-1] == '\n')
3238                                 ebuf[strlen(ebuf)-1] = '\0';
3239                         if (!remoteconsolehandler(ebuf)) {
3240                                 res = write(ast_consock, ebuf, strlen(ebuf) + 1);
3241                                 if (res < 1) {
3242                                         ast_log(LOG_WARNING, "Unable to write: %s\n", strerror(errno));
3243                                         break;
3244                                 }
3245                         }
3246                 }
3247         }
3248         printf("\nDisconnected from Asterisk server\n");
3249 }
3250
3251 static int show_version(void)
3252 {
3253         printf("Asterisk %s\n", ast_get_version());
3254         return 0;
3255 }
3256
3257 static int show_cli_help(void)
3258 {
3259         printf("Asterisk %s, Copyright (C) 1999 - 2012, Digium, Inc. and others.\n", ast_get_version());
3260         printf("Usage: asterisk [OPTIONS]\n");
3261         printf("Valid Options:\n");
3262         printf("   -V              Display version number and exit\n");
3263         printf("   -C <configfile> Use an alternate configuration file\n");
3264         printf("   -G <group>      Run as a group other than the caller\n");
3265         printf("   -U <user>       Run as a user other than the caller\n");
3266         printf("   -c              Provide console CLI\n");
3267         printf("   -d              Enable extra debugging\n");
3268 #if HAVE_WORKING_FORK
3269         printf("   -f              Do not fork\n");
3270         printf("   -F              Always fork\n");
3271 #endif
3272         printf("   -g              Dump core in case of a crash\n");
3273         printf("   -h              This help screen\n");
3274         printf("   -i              Initialize crypto keys at startup\n");
3275         printf("   -I              Enable internal timing if DAHDI timer is available\n");
3276         printf("   -L <load>       Limit the maximum load average before rejecting new calls\n");
3277         printf("   -M <value>      Limit the maximum number of calls to the specified value\n");
3278         printf("   -m              Mute debugging and console output on the console\n");
3279         printf("   -n              Disable console colorization\n");
3280         printf("   -p              Run as pseudo-realtime thread\n");
3281         printf("   -q              Quiet mode (suppress output)\n");
3282         printf("   -r              Connect to Asterisk on this machine\n");
3283         printf("   -R              Same as -r, except attempt to reconnect if disconnected\n");
3284         printf("   -s <socket>     Connect to Asterisk via socket <socket> (only valid with -r)\n");
3285         printf("   -t              Record soundfiles in /var/tmp and move them where they\n");
3286         printf("                   belong after they are done\n");
3287         printf("   -T              Display the time in [Mmm dd hh:mm:ss] format for each line\n");
3288         printf("                   of output to the CLI\n");
3289         printf("   -v              Increase verbosity (multiple v's = more verbose)\n");
3290         printf("   -x <cmd>        Execute command <cmd> (implies -r)\n");
3291         printf("   -X              Execute includes by default (allows #exec in asterisk.conf)\n");
3292         printf("   -W              Adjust terminal colors to compensate for a light background\n");
3293         printf("\n");
3294         return 0;
3295 }
3296
3297 static void ast_readconfig(void)
3298 {
3299         struct ast_config *cfg;
3300         struct ast_variable *v;
3301         char *config = DEFAULT_CONFIG_FILE;
3302         char hostname[MAXHOSTNAMELEN] = "";
3303         struct ast_flags config_flags = { CONFIG_FLAG_NOREALTIME };
3304         struct {
3305                 unsigned int dbdir:1;
3306                 unsigned int keydir:1;
3307         } found = { 0, 0 };
3308
3309         /* Set default value */
3310         option_dtmfminduration = AST_MIN_DTMF_DURATION;
3311
3312         if (ast_opt_override_config) {
3313                 cfg = ast_config_load2(ast_config_AST_CONFIG_FILE, "" /* core, can't reload */, config_flags);
3314                 if (cfg == CONFIG_STATUS_FILEMISSING || cfg == CONFIG_STATUS_FILEUNCHANGED || cfg == CONFIG_STATUS_FILEINVALID) {
3315                         fprintf(stderr, "Unable to open specified master config file '%s', using built-in defaults\n", ast_config_AST_CONFIG_FILE);
3316                 }
3317         } else {
3318                 cfg = ast_config_load2(config, "" /* core, can't reload */, config_flags);
3319         }
3320
3321         /* init with buildtime config */
3322         ast_copy_string(cfg_paths.config_dir, DEFAULT_CONFIG_DIR, sizeof(cfg_paths.config_dir));
3323         ast_copy_string(cfg_paths.spool_dir, DEFAULT_SPOOL_DIR, sizeof(cfg_paths.spool_dir));
3324         ast_copy_string(cfg_paths.module_dir, DEFAULT_MODULE_DIR, sizeof(cfg_paths.module_dir));
3325         snprintf(cfg_paths.monitor_dir, sizeof(cfg_paths.monitor_dir), "%s/monitor", cfg_paths.spool_dir);
3326         ast_copy_string(cfg_paths.var_dir, DEFAULT_VAR_DIR, sizeof(cfg_paths.var_dir));
3327         ast_copy_string(cfg_paths.data_dir, DEFAULT_DATA_DIR, sizeof(cfg_paths.data_dir));
3328         ast_copy_string(cfg_paths.log_dir, DEFAULT_LOG_DIR, sizeof(cfg_paths.log_dir));
3329         ast_copy_string(cfg_paths.agi_dir, DEFAULT_AGI_DIR, sizeof(cfg_paths.agi_dir));
3330         ast_copy_string(cfg_paths.db_path, DEFAULT_DB, sizeof(cfg_paths.db_path));
3331         ast_copy_string(cfg_paths.sbin_dir, DEFAULT_SBIN_DIR, sizeof(cfg_paths.sbin_dir));
3332         ast_copy_string(cfg_paths.key_dir, DEFAULT_KEY_DIR, sizeof(cfg_paths.key_dir));
3333         ast_copy_string(cfg_paths.pid_path, DEFAULT_PID, sizeof(cfg_paths.pid_path));
3334         ast_copy_string(cfg_paths.socket_path, DEFAULT_SOCKET, sizeof(cfg_paths.socket_path));
3335         ast_copy_string(cfg_paths.run_dir, DEFAULT_RUN_DIR, sizeof(cfg_paths.run_dir));
3336
3337         ast_set_default_eid(&ast_eid_default);
3338
3339         /* no asterisk.conf? no problem, use buildtime config! */
3340         if (cfg == CONFIG_STATUS_FILEMISSING || cfg == CONFIG_STATUS_FILEUNCHANGED || cfg == CONFIG_STATUS_FILEINVALID) {
3341                 return;
3342         }
3343
3344         for (v = ast_variable_browse(cfg, "files"); v; v = v->next) {
3345                 if (!strcasecmp(v->name, "astctlpermissions"))
3346                         ast_copy_string(ast_config_AST_CTL_PERMISSIONS, v->value, sizeof(ast_config_AST_CTL_PERMISSIONS));
3347                 else if (!strcasecmp(v->name, "astctlowner"))
3348                         ast_copy_string(ast_config_AST_CTL_OWNER, v->value, sizeof(ast_config_AST_CTL_OWNER));
3349                 else if (!strcasecmp(v->name, "astctlgroup"))
3350                         ast_copy_string(ast_config_AST_CTL_GROUP, v->value, sizeof(ast_config_AST_CTL_GROUP));
3351                 else if (!strcasecmp(v->name, "astctl"))
3352                         ast_copy_string(ast_config_AST_CTL, v->value, sizeof(ast_config_AST_CTL));
3353         }
3354
3355         for (v = ast_variable_browse(cfg, "directories"); v; v = v->next) {
3356                 if (!strcasecmp(v->name, "astetcdir")) {
3357                         ast_copy_string(cfg_paths.config_dir, v->value, sizeof(cfg_paths.config_dir));
3358                 } else if (!strcasecmp(v->name, "astspooldir")) {
3359                         ast_copy_string(cfg_paths.spool_dir, v->value, sizeof(cfg_paths.spool_dir));
3360                         snprintf(cfg_paths.monitor_dir, sizeof(cfg_paths.monitor_dir), "%s/monitor", v->value);
3361                 } else if (!strcasecmp(v->name, "astvarlibdir")) {
3362                         ast_copy_string(cfg_paths.var_dir, v->value, sizeof(cfg_paths.var_dir));
3363                         if (!found.dbdir)
3364                                 snprintf(cfg_paths.db_path, sizeof(cfg_paths.db_path), "%s/astdb", v->value);
3365                 } else if (!strcasecmp(v->name, "astdbdir")) {
3366                         snprintf(cfg_paths.db_path, sizeof(cfg_paths.db_path), "%s/astdb", v->value);
3367                         found.dbdir = 1;
3368                 } else if (!strcasecmp(v->name, "astdatadir")) {
3369                         ast_copy_string(cfg_paths.data_dir, v->value, sizeof(cfg_paths.data_dir));
3370                         if (!found.keydir)
3371                                 snprintf(cfg_paths.key_dir, sizeof(cfg_paths.key_dir), "%s/keys", v->value);
3372                 } else if (!strcasecmp(v->name, "astkeydir")) {
3373                         snprintf(cfg_paths.key_dir, sizeof(cfg_paths.key_dir), "%s/keys", v->value);
3374                         found.keydir = 1;
3375                 } else if (!strcasecmp(v->name, "astlogdir")) {
3376                         ast_copy_string(cfg_paths.log_dir, v->value, sizeof(cfg_paths.log_dir));
3377                 } else if (!strcasecmp(v->name, "astagidir")) {
3378                         ast_copy_string(cfg_paths.agi_dir, v->value, sizeof(cfg_paths.agi_dir));
3379                 } else if (!strcasecmp(v->name, "astrundir")) {
3380                         snprintf(cfg_paths.pid_path, sizeof(cfg_paths.pid_path), "%s/%s", v->value, "asterisk.pid");
3381                         snprintf(cfg_paths.socket_path, sizeof(cfg_paths.socket_path), "%s/%s", v->value, ast_config_AST_CTL);
3382                         ast_copy_string(cfg_paths.run_dir, v->value, sizeof(cfg_paths.run_dir));
3383                 } else if (!strcasecmp(v->name, "astmoddir")) {
3384                         ast_copy_string(cfg_paths.module_dir, v->value, sizeof(cfg_paths.module_dir));
3385                 } else if (!strcasecmp(v->name, "astsbindir")) {
3386                         ast_copy_string(cfg_paths.sbin_dir, v->value, sizeof(cfg_paths.sbin_dir));
3387                 }
3388         }
3389
3390         for (v = ast_variable_browse(cfg, "options"); v; v = v->next) {
3391                 /* verbose level (-v at startup) */
3392                 if (!strcasecmp(v->name, "verbose")) {
3393                         option_verbose = atoi(v->value);
3394                 /* whether or not to force timestamping in CLI verbose output. (-T at startup) */
3395                 } else if (!strcasecmp(v->name, "timestamp")) {
3396                         ast_set2_flag(&ast_options, ast_true(v->value), AST_OPT_FLAG_TIMESTAMP);
3397                 /* whether or not to support #exec in config files */
3398                 } else if (!strcasecmp(v->name, "execincludes")) {
3399                         ast_set2_flag(&ast_options, ast_true(v->value), AST_OPT_FLAG_EXEC_INCLUDES);
3400                 /* debug level (-d at startup) */
3401                 } else if (!strcasecmp(v->name, "debug")) {
3402                         option_debug = 0;
3403                         if (sscanf(v->value, "%30d", &option_debug) != 1) {
3404                                 option_debug = ast_true(v->value);
3405                         }
3406 #if HAVE_WORKING_FORK
3407                 /* Disable forking (-f at startup) */
3408                 } else if (!strcasecmp(v->name, "nofork")) {
3409                         ast_set2_flag(&ast_options, ast_true(v->value), AST_OPT_FLAG_NO_FORK);
3410                 /* Always fork, even if verbose or debug are enabled (-F at startup) */
3411                 } else if (!strcasecmp(v->name, "alwaysfork")) {
3412                         ast_set2_flag(&ast_options, ast_true(v->value), AST_OPT_FLAG_ALWAYS_FORK);
3413 #endif
3414                 /* Run quietly (-q at startup ) */
3415                 } else if (!strcasecmp(v->name, "quiet")) {
3416                         ast_set2_flag(&ast_options, ast_true(v->value), AST_OPT_FLAG_QUIET);
3417                 /* Run as console (-c at startup, implies nofork) */
3418                 } else if (!strcasecmp(v->name, "console")) {
3419                         ast_set2_flag(&ast_options, ast_true(v->value), AST_OPT_FLAG_NO_FORK | AST_OPT_FLAG_CONSOLE);
3420                 /* Run with high priority if the O/S permits (-p at startup) */
3421                 } else if (!strcasecmp(v->name, "highpriority")) {
3422                         ast_set2_flag(&ast_options, ast_true(v->value), AST_OPT_FLAG_HIGH_PRIORITY);
3423                 /* Initialize RSA auth keys (IAX2) (-i at startup) */
3424                 } else if (!strcasecmp(v->name, "initcrypto")) {
3425                         ast_set2_flag(&ast_options, ast_true(v->value), AST_OPT_FLAG_INIT_KEYS);
3426                 /* Disable ANSI colors for console (-c at startup) */
3427                 } else if (!strcasecmp(v->name, "nocolor")) {
3428                         ast_set2_flag(&ast_options, ast_true(v->value), AST_OPT_FLAG_NO_COLOR);
3429                 /* Disable some usage warnings for picky people :p */
3430                 } else if (!strcasecmp(v->name, "dontwarn")) {
3431                         ast_set2_flag(&ast_options, ast_true(v->value), AST_OPT_FLAG_DONT_WARN);
3432                 /* Dump core in case of crash (-g) */
3433                 } else if (!strcasecmp(v->name, "dumpcore")) {
3434                         ast_set2_flag(&ast_options, ast_true(v->value), AST_OPT_FLAG_DUMP_CORE);
3435                 /* Cache recorded sound files to another directory during recording */
3436                 } else if (!strcasecmp(v->name, "cache_record_files")) {
3437                         ast_set2_flag(&ast_options, ast_true(v->value), AST_OPT_FLAG_CACHE_RECORD_FILES);
3438                 /* Specify cache directory */
3439                 }  else if (!strcasecmp(v->name, "record_cache_dir")) {
3440                         ast_copy_string(record_cache_dir, v->value, AST_CACHE_DIR_LEN);
3441                 /* Build transcode paths via SLINEAR, instead of directly */
3442                 } else if (!strcasecmp(v->name, "transcode_via_sln")) {
3443                         ast_set2_flag(&ast_options, ast_true(v->value), AST_OPT_FLAG_TRANSCODE_VIA_SLIN);
3444                 /* Transmit SLINEAR silence while a channel is being recorded or DTMF is being generated on a channel */
3445                 } else if (!strcasecmp(v->name, "transmit_silence_during_record") || !strcasecmp(v->name, "transmit_silence")) {
3446                         ast_set2_flag(&ast_options, ast_true(v->value), AST_OPT_FLAG_TRANSMIT_SILENCE);
3447                 /* Enable internal timing */
3448                 } else if (!strcasecmp(v->name, "internal_timing")) {
3449                         ast_set2_flag(&ast_options, ast_true(v->value), AST_OPT_FLAG_INTERNAL_TIMING);
3450                 } else if (!strcasecmp(v->name, "mindtmfduration")) {
3451                         if (sscanf(v->value, "%30u", &option_dtmfminduration) != 1) {
3452                                 option_dtmfminduration = AST_MIN_DTMF_DURATION;
3453                         }
3454                 } else if (!strcasecmp(v->name, "maxcalls")) {
3455                         if ((sscanf(v->value, "%30d", &option_maxcalls) != 1) || (option_maxcalls < 0)) {
3456                                 option_maxcalls = 0;
3457                         }
3458                 } else if (!strcasecmp(v->name, "maxload")) {
3459                         double test[1];
3460
3461                         if (getloadavg(test, 1) == -1) {
3462                                 ast_log(LOG_ERROR, "Cannot obtain load average on this system. 'maxload' option disabled.\n");
3463                                 option_maxload = 0.0;
3464                         } else if ((sscanf(v->value, "%30lf", &option_maxload) != 1) || (option_maxload < 0.0)) {
3465                                 option_maxload = 0.0;
3466                         }
3467                 /* Set the maximum amount of open files */
3468                 } else if (!strcasecmp(v->name, "maxfiles")) {
3469                         option_maxfiles = atoi(v->value);
3470                         set_ulimit(option_maxfiles);
3471                 /* What user to run as */
3472                 } else if (!strcasecmp(v->name, "runuser")) {
3473                         ast_copy_string(cfg_paths.run_user, v->value, sizeof(cfg_paths.run_user));
3474                 /* What group to run as */
3475                 } else if (!strcasecmp(v->name, "rungroup")) {
3476                         ast_copy_string(cfg_paths.run_group, v->value, sizeof(cfg_paths.run_group));
3477                 } else if (!strcasecmp(v->name, "systemname")) {
3478                         ast_copy_string(cfg_paths.system_name, v->value, sizeof(cfg_paths.system_name));
3479                 } else if (!strcasecmp(v->name, "autosystemname")) {
3480                         if (ast_true(v->value)) {
3481                                 if (!gethostname(hostname, sizeof(hostname) - 1))
3482                                         ast_copy_string(cfg_paths.system_name, hostname, sizeof(cfg_paths.system_name));
3483                                 else {
3484                                         if (ast_strlen_zero(ast_config_AST_SYSTEM_NAME)){
3485                                                 ast_copy_string(cfg_paths.system_name, "localhost", sizeof(cfg_paths.system_name));
3486                                         }
3487                                         ast_log(LOG_ERROR, "Cannot obtain hostname for this system.  Using '%s' instead.\n", ast_config_AST_SYSTEM_NAME);
3488                                 }
3489                         }
3490                 } else if (!strcasecmp(v->name, "languageprefix")) {
3491                         ast_language_is_prefix = ast_true(v->value);
3492                 } else if (!strcasecmp(v->name, "defaultlanguage")) {
3493                         ast_copy_string(defaultlanguage, v->value, MAX_LANGUAGE);
3494                 } else if (!strcasecmp(v->name, "lockmode")) {
3495                         if (!strcasecmp(v->value, "lockfile")) {
3496                                 ast_set_lock_type(AST_LOCK_TYPE_LOCKFILE);
3497                         } else if (!strcasecmp(v->value, "flock")) {
3498                                 ast_set_lock_type(AST_LOCK_TYPE_FLOCK);
3499                         } else {
3500                                 ast_log(LOG_WARNING, "'%s' is not a valid setting for the lockmode option, "
3501                                         "defaulting to 'lockfile'\n", v->value);
3502                                 ast_set_lock_type(AST_LOCK_TYPE_LOCKFILE);
3503                         }
3504 #if defined(HAVE_SYSINFO)
3505                 } else if (!strcasecmp(v->name, "minmemfree")) {
3506                         /* specify the minimum amount of free memory to retain.  Asterisk should stop accepting new calls
3507                          * if the amount of free memory falls below this watermark */
3508                         if ((sscanf(v->value, "%30ld", &option_minmemfree) != 1) || (option_minmemfree < 0)) {
3509                                 option_minmemfree = 0;
3510                         }
3511 #endif
3512                 } else if (!strcasecmp(v->name, "entityid")) {
3513                         struct ast_eid tmp_eid;
3514                         if (!ast_str_to_eid(&tmp_eid, v->value)) {
3515                                 ast_verbose("Successfully set global EID to '%s'\n", v->value);
3516                                 ast_eid_default = tmp_eid;
3517                         } else
3518                                 ast_verbose("Invalid Entity ID '%s' provided\n", v->value);
3519                 } else if (!strcasecmp(v->name, "lightbackground")) {
3520                         ast_set2_flag(&ast_options, ast_true(v->value), AST_OPT_FLAG_LIGHT_BACKGROUND);
3521                 } else if (!strcasecmp(v->name, "forceblackbackground")) {
3522                         ast_set2_flag(&ast_options, ast_true(v->value), AST_OPT_FLAG_FORCE_BLACK_BACKGROUND);
3523                 } else if (!strcasecmp(v->name, "hideconnect")) {
3524                         ast_set2_flag(&ast_options, ast_true(v->value), AST_OPT_FLAG_HIDE_CONSOLE_CONNECT);
3525                 } else if (!strcasecmp(v->name, "lockconfdir")) {
3526                         ast_set2_flag(&ast_options, ast_true(v->value), AST_OPT_FLAG_LOCK_CONFIG_DIR);
3527                 } else if (!strcasecmp(v->name, "stdexten")) {
3528                         /* Choose how to invoke the extensions.conf stdexten */
3529                         if (!strcasecmp(v->value, "gosub")) {
3530                                 ast_clear_flag(&ast_options, AST_OPT_FLAG_STDEXTEN_MACRO);
3531                         } else if (!strcasecmp(v->value, "macro")) {
3532                                 ast_set_flag(&ast_options, AST_OPT_FLAG_STDEXTEN_MACRO);
3533                         } else {
3534                                 ast_log(LOG_WARNING,
3535                                         "'%s' is not a valid setting for the stdexten option, defaulting to 'gosub'\n",
3536                                         v->value);
3537                                 ast_clear_flag(&ast_options, AST_OPT_FLAG_STDEXTEN_MACRO);
3538                         }
3539                 }
3540         }
3541         for (v = ast_variable_browse(cfg, "compat"); v; v = v->next) {
3542                 float version;
3543                 if (sscanf(v->value, "%30f", &version) != 1) {
3544                         fprintf(stderr, "Compatibility version for option '%s' is not a number: '%s'\n", v->name, v->value);
3545                         continue;
3546                 }
3547                 if (!strcasecmp(v->name, "app_set")) {
3548                         ast_set2_flag(&ast_compat, version < 1.5 ? 1 : 0, AST_COMPAT_APP_SET);
3549                 } else if (!strcasecmp(v->name, "res_agi")) {
3550                         ast_set2_flag(&ast_compat, version < 1.5 ? 1 : 0, AST_COMPAT_DELIM_RES_AGI);
3551                 } else if (!strcasecmp(v->name, "pbx_realtime")) {
3552                         ast_set2_flag(&ast_compat, version < 1.5 ? 1 : 0, AST_COMPAT_DELIM_PBX_REALTIME);
3553                 }
3554         }
3555         ast_config_destroy(cfg);
3556 }
3557
3558 static void *monitor_sig_flags(void *unused)
3559 {
3560         for (;;) {
3561                 struct pollfd p = { sig_alert_pipe[0], POLLIN, 0 };
3562                 int a;
3563                 ast_poll(&p, 1, -1);
3564                 if (sig_flags.need_reload) {
3565                         sig_flags.need_reload = 0;
3566                         ast_module_reload(NULL);
3567                 }
3568                 if (sig_flags.need_quit) {
3569                         sig_flags.need_quit = 0;
3570                         if ((consolethread != AST_PTHREADT_NULL) && (consolethread != pthread_self())) {
3571                                 sig_flags.need_quit_handler = 1;
3572                                 pthread_kill(consolethread, SIGURG);
3573                         } else {
3574                                 quit_handler(0, SHUTDOWN_NORMAL, 0);
3575                         }
3576                 }
3577                 if (read(sig_alert_pipe[0], &a, sizeof(a)) != sizeof(a)) {
3578                 }
3579         }
3580
3581         return NULL;
3582 }
3583
3584 static void *canary_thread(void *unused)
3585 {
3586         struct stat canary_stat;
3587         struct timeval now;
3588
3589         /* Give the canary time to sing */
3590         sleep(120);
3591
3592         for (;;) {
3593                 now = ast_tvnow();
3594                 if (stat(canary_filename, &canary_stat) || now.tv_sec > canary_stat.st_mtime + 60) {
3595                         ast_log(LOG_WARNING,
3596                                 "The canary is no more.  He has ceased to be!  "
3597                                 "He's expired and gone to meet his maker!  "
3598                                 "He's a stiff!  Bereft of life, he rests in peace.  "
3599                                 "His metabolic processes are now history!  He's off the twig!  "
3600                                 "He's kicked the bucket.  He's shuffled off his mortal coil, "
3601                                 "run down the curtain, and joined the bleeding choir invisible!!  "
3602                                 "THIS is an EX-CANARY.  (Reducing priority)\n");
3603                         ast_set_priority(0);
3604 &nb