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