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