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