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