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