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