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