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