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