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