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