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