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