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