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