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