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