fix *BSD breakage from include-order changes (bug #4067)
[asterisk/asterisk.git] / asterisk.c
1 /*
2  * Asterisk -- A telephony toolkit for Linux.
3  *
4  * Top level source file for asterisk
5  * 
6  * Copyright (C) 1999 - 2005, Digium, Inc.
7  *
8  * Mark Spencer <markster@digium.com>
9  *
10  * This program is free software, distributed under the terms of
11  * the GNU General Public License
12  */
13
14 #include <unistd.h>
15 #include <stdlib.h>
16 #include <sys/time.h>
17 #include <fcntl.h>
18 #include <stdio.h>
19 #include <signal.h>
20 #include <sched.h>
21 #include <sys/socket.h>
22 #include <sys/un.h>
23 #include <sys/wait.h>
24 #include <string.h>
25 #include <errno.h>
26 #include <ctype.h>
27 #include <sys/resource.h>
28 #include <grp.h>
29 #include <pwd.h>
30 #include <sys/stat.h>
31
32 #if  defined(__FreeBSD__) || defined( __NetBSD__ ) || defined(SOLARIS)
33 #include <netdb.h>
34 #endif
35
36 #include "asterisk/logger.h"
37 #include "asterisk/options.h"
38 #include "asterisk/cli.h"
39 #include "asterisk/channel.h"
40 #include "asterisk/ulaw.h"
41 #include "asterisk/alaw.h"
42 #include "asterisk/callerid.h"
43 #include "asterisk/module.h"
44 #include "asterisk/image.h"
45 #include "asterisk/tdd.h"
46 #include "asterisk/term.h"
47 #include "asterisk/manager.h"
48 #include "asterisk/pbx.h"
49 #include "asterisk/enum.h"
50 #include "asterisk/rtp.h"
51 #include "asterisk/app.h"
52 #include "asterisk/lock.h"
53 #include "asterisk/utils.h"
54 #include "asterisk/file.h"
55 #include "asterisk/io.h"
56 #include "asterisk/lock.h"
57 #include "editline/histedit.h"
58 #include "asterisk.h"
59 #include "asterisk/config.h"
60
61 #ifndef AF_LOCAL
62 #define AF_LOCAL AF_UNIX
63 #define PF_LOCAL PF_UNIX
64 #endif
65
66 #define AST_MAX_CONNECTS 128
67 #define NUM_MSGS 64
68
69 #define WELCOME_MESSAGE ast_verbose( "Asterisk " ASTERISK_VERSION ", Copyright (C) 1999 - 2005 Digium.\n"); \
70                 ast_verbose( "Written by Mark Spencer <markster@digium.com>\n"); \
71                 ast_verbose( "=========================================================================\n")
72
73 int option_verbose=0;
74 int option_debug=0;
75 int option_exec_includes=0;
76 int option_nofork=0;
77 int option_quiet=0;
78 int option_console=0;
79 int option_highpriority=0;
80 int option_remote=0;
81 int option_exec=0;
82 int option_initcrypto=0;
83 int option_nocolor;
84 int option_dumpcore = 0;
85 int option_cache_record_files = 0;
86 int option_timestamp = 0;
87 int option_overrideconfig = 0;
88 int option_reconnect = 0;
89 int option_transcode_slin = 1;
90 int fully_booted = 0;
91 char record_cache_dir[AST_CACHE_DIR_LEN] = AST_TMP_DIR;
92 char debug_filename[AST_FILENAME_MAX] = "";
93
94 static int ast_socket = -1;             /* UNIX Socket for allowing remote control */
95 static int ast_consock = -1;            /* UNIX Socket for controlling another asterisk */
96 int ast_mainpid;
97 struct console {
98         int fd;                                 /* File descriptor */
99         int p[2];                               /* Pipe */
100         pthread_t t;                    /* Thread of handler */
101 };
102
103 static struct ast_atexit {
104         void (*func)(void);
105         struct ast_atexit *next;
106 } *atexits = NULL;
107 AST_MUTEX_DEFINE_STATIC(atexitslock);
108
109 time_t ast_startuptime;
110 time_t ast_lastreloadtime;
111
112 static History *el_hist = NULL;
113 static EditLine *el = NULL;
114 static char *remotehostname;
115
116 struct console consoles[AST_MAX_CONNECTS];
117
118 char defaultlanguage[MAX_LANGUAGE] = DEFAULT_LANGUAGE;
119
120 static int ast_el_add_history(char *);
121 static int ast_el_read_history(char *);
122 static int ast_el_write_history(char *);
123
124 char ast_config_AST_CONFIG_DIR[AST_CONFIG_MAX_PATH];
125 char ast_config_AST_CONFIG_FILE[AST_CONFIG_MAX_PATH];
126 char ast_config_AST_MODULE_DIR[AST_CONFIG_MAX_PATH];
127 char ast_config_AST_SPOOL_DIR[AST_CONFIG_MAX_PATH];
128 char ast_config_AST_VAR_DIR[AST_CONFIG_MAX_PATH];
129 char ast_config_AST_LOG_DIR[AST_CONFIG_MAX_PATH];
130 char ast_config_AST_AGI_DIR[AST_CONFIG_MAX_PATH];
131 char ast_config_AST_DB[AST_CONFIG_MAX_PATH];
132 char ast_config_AST_KEY_DIR[AST_CONFIG_MAX_PATH];
133 char ast_config_AST_PID[AST_CONFIG_MAX_PATH];
134 char ast_config_AST_SOCKET[AST_CONFIG_MAX_PATH];
135 char ast_config_AST_RUN_DIR[AST_CONFIG_MAX_PATH];
136
137 static char *_argv[256];
138 static int shuttingdown = 0;
139 static int restartnow = 0;
140 static pthread_t consolethread = AST_PTHREADT_NULL;
141
142 int ast_register_atexit(void (*func)(void))
143 {
144         int res = -1;
145         struct ast_atexit *ae;
146         ast_unregister_atexit(func);
147         ae = malloc(sizeof(struct ast_atexit));
148         ast_mutex_lock(&atexitslock);
149         if (ae) {
150                 memset(ae, 0, sizeof(struct ast_atexit));
151                 ae->next = atexits;
152                 ae->func = func;
153                 atexits = ae;
154                 res = 0;
155         }
156         ast_mutex_unlock(&atexitslock);
157         return res;
158 }
159
160 void ast_unregister_atexit(void (*func)(void))
161 {
162         struct ast_atexit *ae, *prev = NULL;
163         ast_mutex_lock(&atexitslock);
164         ae = atexits;
165         while(ae) {
166                 if (ae->func == func) {
167                         if (prev)
168                                 prev->next = ae->next;
169                         else
170                                 atexits = ae->next;
171                         break;
172                 }
173                 prev = ae;
174                 ae = ae->next;
175         }
176         ast_mutex_unlock(&atexitslock);
177 }
178
179 static int fdprint(int fd, const char *s)
180 {
181         return write(fd, s, strlen(s) + 1);
182 }
183
184 /* NULL handler so we can collect the child exit status */
185 static void null_sig_handler(int signal)
186 {
187
188 }
189
190 int ast_safe_system(const char *s)
191 {
192         /* XXX This function needs some optimization work XXX */
193         pid_t pid;
194         int x;
195         int res;
196         struct rusage rusage;
197         int status;
198         void (*prev_handler) = signal(SIGCHLD, null_sig_handler);
199         pid = fork();
200         if (pid == 0) {
201                 /* Close file descriptors and launch system command */
202                 for (x=STDERR_FILENO + 1; x<4096;x++) {
203                         close(x);
204                 }
205                 res = execl("/bin/sh", "/bin/sh", "-c", s, NULL);
206                 exit(1);
207         } else if (pid > 0) {
208                 for(;;) {
209                         res = wait4(pid, &status, 0, &rusage);
210                         if (res > -1) {
211                                 if (WIFEXITED(status))
212                                         res = WEXITSTATUS(status);
213                                 else
214                                         res = -1;
215                                 break;
216                         } else {
217                                 if (errno != EINTR) 
218                                         break;
219                         }
220                 }
221         } else {
222                 ast_log(LOG_WARNING, "Fork failed: %s\n", strerror(errno));
223                 res = -1;
224         }
225         signal(SIGCHLD, prev_handler);
226         return res;
227 }
228
229 /*
230  * write the string to all attached console clients
231  */
232 static void ast_network_puts(const char *string)
233 {
234         int x;
235         for (x=0;x<AST_MAX_CONNECTS; x++) {
236                 if (consoles[x].fd > -1) 
237                         fdprint(consoles[x].p[1], string);
238         }
239 }
240
241 /*
242  * write the string to the console, and all attached
243  * console clients
244  */
245 void ast_console_puts(const char *string)
246 {
247         fputs(string, stdout);
248         fflush(stdout);
249         ast_network_puts(string);
250 }
251
252 static void network_verboser(const char *s, int pos, int replace, int complete)
253         /* ARGUSED */
254 {
255         if (replace) {
256                 char *t = alloca(strlen(s) + 2);
257                 if (t) {
258                         sprintf(t, "\r%s", s);
259                         if (complete)
260                                 ast_network_puts(t);
261                 } else {
262                         ast_log(LOG_ERROR, "Out of memory\n");
263                         ast_network_puts(s);
264                 }
265         } else {
266                 if (complete)
267                         ast_network_puts(s);
268         }
269 }
270
271 static pthread_t lthread;
272
273 static void *netconsole(void *vconsole)
274 {
275         struct console *con = vconsole;
276         char hostname[256];
277         char tmp[512];
278         int res;
279         struct pollfd fds[2];
280         
281         if (gethostname(hostname, sizeof(hostname)))
282                 strncpy(hostname, "<Unknown>", sizeof(hostname)-1);
283         snprintf(tmp, sizeof(tmp), "%s/%d/%s\n", hostname, ast_mainpid, ASTERISK_VERSION);
284         fdprint(con->fd, tmp);
285         for(;;) {
286                 fds[0].fd = con->fd;
287                 fds[0].events = POLLIN;
288                 fds[1].fd = con->p[0];
289                 fds[1].events = POLLIN;
290
291                 res = poll(fds, 2, -1);
292                 if (res < 0) {
293                         if (errno != EINTR)
294                                 ast_log(LOG_WARNING, "poll returned < 0: %s\n", strerror(errno));
295                         continue;
296                 }
297                 if (fds[0].revents) {
298                         res = read(con->fd, tmp, sizeof(tmp));
299                         if (res < 1) {
300                                 break;
301                         }
302                         tmp[res] = 0;
303                         ast_cli_command(con->fd, tmp);
304                 }
305                 if (fds[1].revents) {
306                         res = read(con->p[0], tmp, sizeof(tmp));
307                         if (res < 1) {
308                                 ast_log(LOG_ERROR, "read returned %d\n", res);
309                                 break;
310                         }
311                         res = write(con->fd, tmp, res);
312                         if (res < 1)
313                                 break;
314                 }
315         }
316         if (option_verbose > 2) 
317                 ast_verbose(VERBOSE_PREFIX_3 "Remote UNIX connection disconnected\n");
318         close(con->fd);
319         close(con->p[0]);
320         close(con->p[1]);
321         con->fd = -1;
322         
323         return NULL;
324 }
325
326 static void *listener(void *unused)
327 {
328         struct sockaddr_un sunaddr;
329         int s;
330         int len;
331         int x;
332         int flags;
333         struct pollfd fds[1];
334         pthread_attr_t attr;
335         pthread_attr_init(&attr);
336         pthread_attr_setdetachstate(&attr, PTHREAD_CREATE_DETACHED);
337         for(;;) {
338                 if (ast_socket < 0)
339                         return NULL;
340                 fds[0].fd = ast_socket;
341                 fds[0].events= POLLIN;
342                 s = poll(fds, 1, -1);
343                 if (s < 0) {
344                         if (errno != EINTR)
345                                 ast_log(LOG_WARNING, "poll returned error: %s\n", strerror(errno));
346                         continue;
347                 }
348                 len = sizeof(sunaddr);
349                 s = accept(ast_socket, (struct sockaddr *)&sunaddr, &len);
350                 if (s < 0) {
351                         if (errno != EINTR)
352                                 ast_log(LOG_WARNING, "Accept returned %d: %s\n", s, strerror(errno));
353                 } else {
354                         for (x=0;x<AST_MAX_CONNECTS;x++) {
355                                 if (consoles[x].fd < 0) {
356                                         if (socketpair(AF_LOCAL, SOCK_STREAM, 0, consoles[x].p)) {
357                                                 ast_log(LOG_ERROR, "Unable to create pipe: %s\n", strerror(errno));
358                                                 consoles[x].fd = -1;
359                                                 fdprint(s, "Server failed to create pipe\n");
360                                                 close(s);
361                                                 break;
362                                         }
363                                         flags = fcntl(consoles[x].p[1], F_GETFL);
364                                         fcntl(consoles[x].p[1], F_SETFL, flags | O_NONBLOCK);
365                                         consoles[x].fd = s;
366                                         if (ast_pthread_create(&consoles[x].t, &attr, netconsole, &consoles[x])) {
367                                                 ast_log(LOG_ERROR, "Unable to spawn thread to handle connection: %s\n", strerror(errno));
368                                                 consoles[x].fd = -1;
369                                                 fdprint(s, "Server failed to spawn thread\n");
370                                                 close(s);
371                                         }
372                                         break;
373                                 }
374                         }
375                         if (x >= AST_MAX_CONNECTS) {
376                                 fdprint(s, "No more connections allowed\n");
377                                 ast_log(LOG_WARNING, "No more connections allowed\n");
378                                 close(s);
379                         } else if (consoles[x].fd > -1) {
380                                 if (option_verbose > 2) 
381                                         ast_verbose(VERBOSE_PREFIX_3 "Remote UNIX connection\n");
382                         }
383                 }
384         }
385         return NULL;
386 }
387
388 static int ast_makesocket(void)
389 {
390         struct sockaddr_un sunaddr;
391         int res;
392         int x;
393
394         struct ast_config *cfg;
395         char *config = ASTCONFPATH;
396         char *owner;
397         char *group;
398         char *perms;
399         uid_t uid;
400         gid_t gid;
401
402
403         for (x=0;x<AST_MAX_CONNECTS;x++)        
404                 consoles[x].fd = -1;
405         unlink((char *)ast_config_AST_SOCKET);
406         ast_socket = socket(PF_LOCAL, SOCK_STREAM, 0);
407         if (ast_socket < 0) {
408                 ast_log(LOG_WARNING, "Unable to create control socket: %s\n", strerror(errno));
409                 return -1;
410         }               
411         memset(&sunaddr, 0, sizeof(sunaddr));
412         sunaddr.sun_family = AF_LOCAL;
413         strncpy(sunaddr.sun_path, (char *)ast_config_AST_SOCKET, sizeof(sunaddr.sun_path)-1);
414         res = bind(ast_socket, (struct sockaddr *)&sunaddr, sizeof(sunaddr));
415         if (res) {
416                 ast_log(LOG_WARNING, "Unable to bind socket to %s: %s\n", (char *)ast_config_AST_SOCKET, strerror(errno));
417                 close(ast_socket);
418                 ast_socket = -1;
419                 return -1;
420         }
421         res = listen(ast_socket, 2);
422         if (res < 0) {
423                 ast_log(LOG_WARNING, "Unable to listen on socket %s: %s\n", (char *)ast_config_AST_SOCKET, strerror(errno));
424                 close(ast_socket);
425                 ast_socket = -1;
426                 return -1;
427         }
428         ast_register_verbose(network_verboser);
429         ast_pthread_create(&lthread, NULL, listener, NULL);
430
431         /* Load the options for owner, group and permissions from
432            asterisk.conf. if the file doesn't exist (????) just skip
433            this part.
434         */
435         if (option_overrideconfig == 1) {
436                 cfg = ast_config_load((char *)ast_config_AST_CONFIG_FILE);
437         } else {
438                 cfg = ast_config_load(config);
439         }
440         if (!cfg) return 0;
441
442         gid=-1;
443         uid=-1;
444         group = ast_variable_retrieve(cfg, "files", "astctlgroup");
445         owner = ast_variable_retrieve(cfg, "files", "astctlowner");
446         perms = ast_variable_retrieve(cfg, "files", "astctlpermissions");
447
448         if (owner!=NULL) {
449                 struct passwd *pw;
450                 if ((pw=getpwnam(owner))==NULL)
451                         ast_log(LOG_WARNING, "Unable to find uid of user %s\n", owner);
452                 else
453                         uid=pw->pw_uid;
454         }
455         if (group!=NULL) {
456                 struct group *grp;
457                 if ((grp=getgrnam(group))==NULL)
458                         ast_log(LOG_WARNING, "Unable to find gid of group %s\n", group);
459                 else
460                         gid=grp->gr_gid;
461         }
462         if (chown(ast_config_AST_SOCKET,uid,gid)<0)
463                 ast_log(LOG_WARNING, "Unable to change ownership of %s: %s\n", ast_config_AST_SOCKET,strerror(errno));
464
465         if (perms!=NULL) {
466                 mode_t p;
467                 sscanf(perms,"%o",&p);
468                 if ((chmod(ast_config_AST_SOCKET,p))<0)
469                         ast_log(LOG_WARNING, "Unable to change file permissions of %s: %s\n", ast_config_AST_SOCKET,strerror(errno));
470         }
471
472         return 0;
473 }
474
475 static int ast_tryconnect(void)
476 {
477         struct sockaddr_un sunaddr;
478         int res;
479         ast_consock = socket(PF_LOCAL, SOCK_STREAM, 0);
480         if (ast_consock < 0) {
481                 ast_log(LOG_WARNING, "Unable to create socket: %s\n", strerror(errno));
482                 return 0;
483         }
484         memset(&sunaddr, 0, sizeof(sunaddr));
485         sunaddr.sun_family = AF_LOCAL;
486         strncpy(sunaddr.sun_path, (char *)ast_config_AST_SOCKET, sizeof(sunaddr.sun_path)-1);
487         res = connect(ast_consock, (struct sockaddr *)&sunaddr, sizeof(sunaddr));
488         if (res) {
489                 close(ast_consock);
490                 ast_consock = -1;
491                 return 0;
492         } else
493                 return 1;
494 }
495
496 static void urg_handler(int num)
497 {
498         /* Called by soft_hangup to interrupt the poll, read, or other
499            system call.  We don't actually need to do anything though.  */
500         /* Cannot EVER ast_log from within a signal handler */
501         if (option_debug) 
502                 printf("Urgent handler\n");
503         signal(num, urg_handler);
504         return;
505 }
506
507 static void hup_handler(int num)
508 {
509         if (option_verbose > 1) 
510                 printf("Received HUP signal -- Reloading configs\n");
511         if (restartnow)
512                 execvp(_argv[0], _argv);
513         /* XXX This could deadlock XXX */
514         ast_module_reload(NULL);
515 }
516
517 static void child_handler(int sig)
518 {
519         /* Must not ever ast_log or ast_verbose within signal handler */
520         int n, status;
521
522         /*
523          * Reap all dead children -- not just one
524          */
525         for (n = 0; wait4(-1, &status, WNOHANG, NULL) > 0; n++)
526                 ;
527         if (n == 0 && option_debug)     
528                 printf("Huh?  Child handler, but nobody there?\n");
529 }
530
531 static void set_title(char *text)
532 {
533         /* Set an X-term or screen title */
534         if (getenv("TERM") && strstr(getenv("TERM"), "xterm"))
535                 fprintf(stdout, "\033]2;%s\007", text);
536 }
537
538 static void set_icon(char *text)
539 {
540         if (getenv("TERM") && strstr(getenv("TERM"), "xterm"))
541                 fprintf(stdout, "\033]1;%s\007", text);
542 }
543
544 static int set_priority(int pri)
545 {
546         struct sched_param sched;
547         memset(&sched, 0, sizeof(sched));
548         /* We set ourselves to a high priority, that we might pre-empt everything
549            else.  If your PBX has heavy activity on it, this is a good thing.  */
550 #ifdef __linux__
551         if (pri) {  
552                 sched.sched_priority = 10;
553                 if (sched_setscheduler(0, SCHED_RR, &sched)) {
554                         ast_log(LOG_WARNING, "Unable to set high priority\n");
555                         return -1;
556                 } else
557                         if (option_verbose)
558                                 ast_verbose("Set to realtime thread\n");
559         } else {
560                 sched.sched_priority = 0;
561                 if (sched_setscheduler(0, SCHED_OTHER, &sched)) {
562                         ast_log(LOG_WARNING, "Unable to set normal priority\n");
563                         return -1;
564                 }
565         }
566 #else
567         if (pri) {
568                 if (setpriority(PRIO_PROCESS, 0, -10) == -1) {
569                         ast_log(LOG_WARNING, "Unable to set high priority\n");
570                         return -1;
571                 } else
572                         if (option_verbose)
573                                 ast_verbose("Set to high priority\n");
574         } else {
575                 if (setpriority(PRIO_PROCESS, 0, 0) == -1) {
576                         ast_log(LOG_WARNING, "Unable to set normal priority\n");
577                         return -1;
578                 }
579         }
580 #endif
581         return 0;
582 }
583
584 static void ast_run_atexits(void)
585 {
586         struct ast_atexit *ae;
587         ast_mutex_lock(&atexitslock);
588         ae = atexits;
589         while(ae) {
590                 if (ae->func) 
591                         ae->func();
592                 ae = ae->next;
593         }
594         ast_mutex_unlock(&atexitslock);
595 }
596
597 static void quit_handler(int num, int nice, int safeshutdown, int restart)
598 {
599         char filename[80] = "";
600         time_t s,e;
601         int x;
602         if (safeshutdown) {
603                 shuttingdown = 1;
604                 if (!nice) {
605                         /* Begin shutdown routine, hanging up active channels */
606                         ast_begin_shutdown(1);
607                         if (option_verbose && option_console)
608                                 ast_verbose("Beginning asterisk %s....\n", restart ? "restart" : "shutdown");
609                         time(&s);
610                         for(;;) {
611                                 time(&e);
612                                 /* Wait up to 15 seconds for all channels to go away */
613                                 if ((e - s) > 15)
614                                         break;
615                                 if (!ast_active_channels())
616                                         break;
617                                 if (!shuttingdown)
618                                         break;
619                                 /* Sleep 1/10 of a second */
620                                 usleep(100000);
621                         }
622                 } else {
623                         if (nice < 2)
624                                 ast_begin_shutdown(0);
625                         if (option_verbose && option_console)
626                                 ast_verbose("Waiting for inactivity to perform %s...\n", restart ? "restart" : "halt");
627                         for(;;) {
628                                 if (!ast_active_channels())
629                                         break;
630                                 if (!shuttingdown)
631                                         break;
632                                 sleep(1);
633                         }
634                 }
635
636                 if (!shuttingdown) {
637                         if (option_verbose && option_console)
638                                 ast_verbose("Asterisk %s cancelled.\n", restart ? "restart" : "shutdown");
639                         return;
640                 }
641         }
642         if (option_console || option_remote) {
643                 if (getenv("HOME")) 
644                         snprintf(filename, sizeof(filename), "%s/.asterisk_history", getenv("HOME"));
645                 if (!ast_strlen_zero(filename))
646                         ast_el_write_history(filename);
647                 if (el != NULL)
648                         el_end(el);
649                 if (el_hist != NULL)
650                         history_end(el_hist);
651         }
652         if (option_verbose)
653                 ast_verbose("Executing last minute cleanups\n");
654         ast_run_atexits();
655         /* Called on exit */
656         if (option_verbose && option_console)
657                 ast_verbose("Asterisk %s ending (%d).\n", ast_active_channels() ? "uncleanly" : "cleanly", num);
658         else if (option_debug)
659                 ast_log(LOG_DEBUG, "Asterisk ending (%d).\n", num);
660         manager_event(EVENT_FLAG_SYSTEM, "Shutdown", "Shutdown: %s\r\nRestart: %s\r\n", ast_active_channels() ? "Uncleanly" : "Cleanly", restart ? "True" : "False");
661         if (ast_socket > -1) {
662                 close(ast_socket);
663                 ast_socket = -1;
664         }
665         if (ast_consock > -1)
666                 close(ast_consock);
667         if (ast_socket > -1)
668                 unlink((char *)ast_config_AST_SOCKET);
669         if (!option_remote) unlink((char *)ast_config_AST_PID);
670         printf(term_quit());
671         if (restart) {
672                 if (option_verbose || option_console)
673                         ast_verbose("Preparing for Asterisk restart...\n");
674                 /* Mark all FD's for closing on exec */
675                 for (x=3;x<32768;x++) {
676                         fcntl(x, F_SETFD, FD_CLOEXEC);
677                 }
678                 if (option_verbose || option_console)
679                         ast_verbose("Restarting Asterisk NOW...\n");
680                 restartnow = 1;
681
682                 /* close logger */
683                 close_logger();
684
685                 /* If there is a consolethread running send it a SIGHUP 
686                    so it can execvp, otherwise we can do it ourselves */
687                 if (consolethread != AST_PTHREADT_NULL) {
688                         pthread_kill(consolethread, SIGHUP);
689                         /* Give the signal handler some time to complete */
690                         sleep(2);
691                 } else
692                         execvp(_argv[0], _argv);
693         
694         } else {
695                 /* close logger */
696                 close_logger();
697         }
698         exit(0);
699 }
700
701 static void __quit_handler(int num)
702 {
703         quit_handler(num, 0, 1, 0);
704 }
705
706 static const char *fix_header(char *outbuf, int maxout, const char *s, char *cmp)
707 {
708         const char *c;
709         if (!strncmp(s, cmp, strlen(cmp))) {
710                 c = s + strlen(cmp);
711                 term_color(outbuf, cmp, COLOR_GRAY, 0, maxout);
712                 return c;
713         }
714         return NULL;
715 }
716
717 static void console_verboser(const char *s, int pos, int replace, int complete)
718 {
719         char tmp[80];
720         const char *c=NULL;
721         /* Return to the beginning of the line */
722         if (!pos) {
723                 fprintf(stdout, "\r");
724                 if ((c = fix_header(tmp, sizeof(tmp), s, VERBOSE_PREFIX_4)) ||
725                         (c = fix_header(tmp, sizeof(tmp), s, VERBOSE_PREFIX_3)) ||
726                         (c = fix_header(tmp, sizeof(tmp), s, VERBOSE_PREFIX_2)) ||
727                         (c = fix_header(tmp, sizeof(tmp), s, VERBOSE_PREFIX_1)))
728                         fputs(tmp, stdout);
729         }
730         if (c)
731                 fputs(c + pos,stdout);
732         else
733                 fputs(s + pos,stdout);
734         fflush(stdout);
735         if (complete) {
736                 /* Wake up a poll()ing console */
737                 if (option_console && consolethread != AST_PTHREADT_NULL)
738                         pthread_kill(consolethread, SIGURG);
739         }
740 }
741
742 static int ast_all_zeros(char *s)
743 {
744         while(*s) {
745                 if (*s > 32)
746                         return 0;
747                 s++;  
748         }
749         return 1;
750 }
751
752 static void consolehandler(char *s)
753 {
754         printf(term_end());
755         fflush(stdout);
756         /* Called when readline data is available */
757         if (s && !ast_all_zeros(s))
758                 ast_el_add_history(s);
759         /* Give the console access to the shell */
760         if (s) {
761                 /* The real handler for bang */
762                 if (s[0] == '!') {
763                         if (s[1])
764                                 ast_safe_system(s+1);
765                         else
766                                 ast_safe_system(getenv("SHELL") ? getenv("SHELL") : "/bin/sh");
767                 } else 
768                 ast_cli_command(STDOUT_FILENO, s);
769         } else
770                 fprintf(stdout, "\nUse \"quit\" to exit\n");
771 }
772
773 static int remoteconsolehandler(char *s)
774 {
775         int ret = 0;
776         /* Called when readline data is available */
777         if (s && !ast_all_zeros(s))
778                 ast_el_add_history(s);
779         /* Give the console access to the shell */
780         if (s) {
781                 /* The real handler for bang */
782                 if (s[0] == '!') {
783                         if (s[1])
784                                 ast_safe_system(s+1);
785                         else
786                                 ast_safe_system(getenv("SHELL") ? getenv("SHELL") : "/bin/sh");
787                         ret = 1;
788                 }
789                 if ((strncasecmp(s, "quit", 4) == 0 || strncasecmp(s, "exit", 4) == 0) &&
790                     (s[4] == '\0' || isspace(s[4]))) {
791                         quit_handler(0, 0, 0, 0);
792                         ret = 1;
793                 }
794         } else
795                 fprintf(stdout, "\nUse \"quit\" to exit\n");
796
797         return ret;
798 }
799
800 static char quit_help[] = 
801 "Usage: quit\n"
802 "       Exits Asterisk.\n";
803
804 static char abort_halt_help[] = 
805 "Usage: abort shutdown\n"
806 "       Causes Asterisk to abort an executing shutdown or restart, and resume normal\n"
807 "       call operations.\n";
808
809 static char shutdown_now_help[] = 
810 "Usage: stop now\n"
811 "       Shuts down a running Asterisk immediately, hanging up all active calls .\n";
812
813 static char shutdown_gracefully_help[] = 
814 "Usage: stop gracefully\n"
815 "       Causes Asterisk to not accept new calls, and exit when all\n"
816 "       active calls have terminated normally.\n";
817
818 static char shutdown_when_convenient_help[] = 
819 "Usage: stop when convenient\n"
820 "       Causes Asterisk to perform a shutdown when all active calls have ended.\n";
821
822 static char restart_now_help[] = 
823 "Usage: restart now\n"
824 "       Causes Asterisk to hangup all calls and exec() itself performing a cold\n"
825 "       restart.\n";
826
827 static char restart_gracefully_help[] = 
828 "Usage: restart gracefully\n"
829 "       Causes Asterisk to stop accepting new calls and exec() itself performing a cold\n"
830 "       restart when all active calls have ended.\n";
831
832 static char restart_when_convenient_help[] = 
833 "Usage: restart when convenient\n"
834 "       Causes Asterisk to perform a cold restart when all active calls have ended.\n";
835
836 static char bang_help[] =
837 "Usage: !<command>\n"
838 "       Executes a given shell command\n";
839
840 #if 0
841 static int handle_quit(int fd, int argc, char *argv[])
842 {
843         if (argc != 1)
844                 return RESULT_SHOWUSAGE;
845         quit_handler(0, 0, 1, 0);
846         return RESULT_SUCCESS;
847 }
848 #endif
849
850 static int no_more_quit(int fd, int argc, char *argv[])
851 {
852         if (argc != 1)
853                 return RESULT_SHOWUSAGE;
854         ast_cli(fd, "The QUIT and EXIT commands may no longer be used to shutdown the PBX.\n"
855                     "Please use STOP NOW instead, if you wish to shutdown the PBX.\n");
856         return RESULT_SUCCESS;
857 }
858
859 static int handle_shutdown_now(int fd, int argc, char *argv[])
860 {
861         if (argc != 2)
862                 return RESULT_SHOWUSAGE;
863         quit_handler(0, 0 /* Not nice */, 1 /* safely */, 0 /* not restart */);
864         return RESULT_SUCCESS;
865 }
866
867 static int handle_shutdown_gracefully(int fd, int argc, char *argv[])
868 {
869         if (argc != 2)
870                 return RESULT_SHOWUSAGE;
871         quit_handler(0, 1 /* nicely */, 1 /* safely */, 0 /* no restart */);
872         return RESULT_SUCCESS;
873 }
874
875 static int handle_shutdown_when_convenient(int fd, int argc, char *argv[])
876 {
877         if (argc != 3)
878                 return RESULT_SHOWUSAGE;
879         quit_handler(0, 2 /* really nicely */, 1 /* safely */, 0 /* don't restart */);
880         return RESULT_SUCCESS;
881 }
882
883 static int handle_restart_now(int fd, int argc, char *argv[])
884 {
885         if (argc != 2)
886                 return RESULT_SHOWUSAGE;
887         quit_handler(0, 0 /* not nicely */, 1 /* safely */, 1 /* restart */);
888         return RESULT_SUCCESS;
889 }
890
891 static int handle_restart_gracefully(int fd, int argc, char *argv[])
892 {
893         if (argc != 2)
894                 return RESULT_SHOWUSAGE;
895         quit_handler(0, 1 /* nicely */, 1 /* safely */, 1 /* restart */);
896         return RESULT_SUCCESS;
897 }
898
899 static int handle_restart_when_convenient(int fd, int argc, char *argv[])
900 {
901         if (argc != 3)
902                 return RESULT_SHOWUSAGE;
903         quit_handler(0, 2 /* really nicely */, 1 /* safely */, 1 /* restart */);
904         return RESULT_SUCCESS;
905 }
906
907 static int handle_abort_halt(int fd, int argc, char *argv[])
908 {
909         if (argc != 2)
910                 return RESULT_SHOWUSAGE;
911         ast_cancel_shutdown();
912         shuttingdown = 0;
913         return RESULT_SUCCESS;
914 }
915
916 static int handle_bang(int fd, int argc, char *argv[])
917 {
918         return RESULT_SUCCESS;
919 }
920
921 #define ASTERISK_PROMPT "*CLI> "
922
923 #define ASTERISK_PROMPT2 "%s*CLI> "
924
925 static struct ast_cli_entry aborthalt = { { "abort", "halt", NULL }, handle_abort_halt, "Cancel a running halt", abort_halt_help };
926
927 static struct ast_cli_entry quit =      { { "quit", NULL }, no_more_quit, "Exit Asterisk", quit_help };
928 static struct ast_cli_entry astexit =   { { "exit", NULL }, no_more_quit, "Exit Asterisk", quit_help };
929
930 static struct ast_cli_entry astshutdownnow =    { { "stop", "now", NULL }, handle_shutdown_now, "Shut down Asterisk immediately", shutdown_now_help };
931 static struct ast_cli_entry astshutdowngracefully =     { { "stop", "gracefully", NULL }, handle_shutdown_gracefully, "Gracefully shut down Asterisk", shutdown_gracefully_help };
932 static struct ast_cli_entry astshutdownwhenconvenient =         { { "stop", "when","convenient", NULL }, handle_shutdown_when_convenient, "Shut down Asterisk at empty call volume", shutdown_when_convenient_help };
933 static struct ast_cli_entry astrestartnow =     { { "restart", "now", NULL }, handle_restart_now, "Restart Asterisk immediately", restart_now_help };
934 static struct ast_cli_entry astrestartgracefully =      { { "restart", "gracefully", NULL }, handle_restart_gracefully, "Restart Asterisk gracefully", restart_gracefully_help };
935 static struct ast_cli_entry astrestartwhenconvenient=   { { "restart", "when", "convenient", NULL }, handle_restart_when_convenient, "Restart Asterisk at empty call volume", restart_when_convenient_help };
936 static struct ast_cli_entry astbang = { { "!", NULL }, handle_bang, "Execute a shell command", bang_help };
937
938 static int ast_el_read_char(EditLine *el, char *cp)
939 {
940         int num_read=0;
941         int lastpos=0;
942         struct pollfd fds[2];
943         int res;
944         int max;
945         char buf[512];
946
947         for (;;) {
948                 max = 1;
949                 fds[0].fd = ast_consock;
950                 fds[0].events = POLLIN;
951                 if (!option_exec) {
952                         fds[1].fd = STDIN_FILENO;
953                         fds[1].events = POLLIN;
954                         max++;
955                 }
956                 res = poll(fds, max, -1);
957                 if (res < 0) {
958                         if (errno == EINTR)
959                                 continue;
960                         ast_log(LOG_ERROR, "poll failed: %s\n", strerror(errno));
961                         break;
962                 }
963
964                 if (!option_exec && fds[1].revents) {
965                         num_read = read(STDIN_FILENO, cp, 1);
966                         if (num_read < 1) {
967                                 break;
968                         } else 
969                                 return (num_read);
970                 }
971                 if (fds[0].revents) {
972                         res = read(ast_consock, buf, sizeof(buf) - 1);
973                         /* if the remote side disappears exit */
974                         if (res < 1) {
975                                 fprintf(stderr, "\nDisconnected from Asterisk server\n");
976                                 if (!option_reconnect) {
977                                         quit_handler(0, 0, 0, 0);
978                                 } else {
979                                         int tries;
980                                         int reconnects_per_second = 20;
981                                         fprintf(stderr, "Attempting to reconnect for 30 seconds\n");
982                                         for (tries=0;tries<30 * reconnects_per_second;tries++) {
983                                                 if (ast_tryconnect()) {
984                                                         fprintf(stderr, "Reconnect succeeded after %.3f seconds\n", 1.0 / reconnects_per_second * tries);
985                                                         printf(term_quit());
986                                                         WELCOME_MESSAGE;
987                                                         break;
988                                                 } else {
989                                                         usleep(1000000 / reconnects_per_second);
990                                                 }
991                                         }
992                                         if (tries >= 30 * reconnects_per_second) {
993                                                 fprintf(stderr, "Failed to reconnect for 30 seconds.  Quitting.\n");
994                                                 quit_handler(0, 0, 0, 0);
995                                         }
996                                 }
997                         }
998
999                         buf[res] = '\0';
1000
1001                         if (!option_exec && !lastpos)
1002                                 write(STDOUT_FILENO, "\r", 1);
1003                         write(STDOUT_FILENO, buf, res);
1004                         if ((buf[res-1] == '\n') || (buf[res-2] == '\n')) {
1005                                 *cp = CC_REFRESH;
1006                                 return(1);
1007                         } else {
1008                                 lastpos = 1;
1009                         }
1010                 }
1011         }
1012
1013         *cp = '\0';
1014         return (0);
1015 }
1016
1017 static char *cli_prompt(EditLine *el)
1018 {
1019         static char prompt[200];
1020         char *pfmt;
1021         int color_used=0;
1022         char term_code[20];
1023
1024         if ((pfmt = getenv("ASTERISK_PROMPT"))) {
1025                 char *t = pfmt, *p = prompt;
1026                 memset(prompt, 0, sizeof(prompt));
1027                 while (*t != '\0' && *p < sizeof(prompt)) {
1028                         if (*t == '%') {
1029                                 char hostname[256];
1030                                 int i;
1031                                 struct timeval tv;
1032                                 struct tm tm;
1033 #ifdef linux
1034                                 FILE *LOADAVG;
1035 #endif
1036                                 int fgcolor = COLOR_WHITE, bgcolor = COLOR_BLACK;
1037
1038                                 t++;
1039                                 switch (*t) {
1040                                         case 'C': /* color */
1041                                                 t++;
1042                                                 if (sscanf(t, "%d;%d%n", &fgcolor, &bgcolor, &i) == 2) {
1043                                                         strncat(p, term_color_code(term_code, fgcolor, bgcolor, sizeof(term_code)),sizeof(prompt) - strlen(prompt) - 1);
1044                                                         t += i - 1;
1045                                                 } else if (sscanf(t, "%d%n", &fgcolor, &i) == 1) {
1046                                                         strncat(p, term_color_code(term_code, fgcolor, 0, sizeof(term_code)),sizeof(prompt) - strlen(prompt) - 1);
1047                                                         t += i - 1;
1048                                                 }
1049
1050                                                 /* If the color has been reset correctly, then there's no need to reset it later */
1051                                                 if ((fgcolor == COLOR_WHITE) && (bgcolor == COLOR_BLACK)) {
1052                                                         color_used = 0;
1053                                                 } else {
1054                                                         color_used = 1;
1055                                                 }
1056                                                 break;
1057                                         case 'd': /* date */
1058                                                 memset(&tm, 0, sizeof(struct tm));
1059                                                 gettimeofday(&tv, NULL);
1060                                                 if (localtime_r(&(tv.tv_sec), &tm)) {
1061                                                         strftime(p, sizeof(prompt) - strlen(prompt), "%Y-%m-%d", &tm);
1062                                                 }
1063                                                 break;
1064                                         case 'h': /* hostname */
1065                                                 if (!gethostname(hostname, sizeof(hostname) - 1)) {
1066                                                         strncat(p, hostname, sizeof(prompt) - strlen(prompt) - 1);
1067                                                 } else {
1068                                                         strncat(p, "localhost", sizeof(prompt) - strlen(prompt) - 1);
1069                                                 }
1070                                                 break;
1071                                         case 'H': /* short hostname */
1072                                                 if (!gethostname(hostname, sizeof(hostname) - 1)) {
1073                                                         for (i=0;i<sizeof(hostname);i++) {
1074                                                                 if (hostname[i] == '.') {
1075                                                                         hostname[i] = '\0';
1076                                                                         break;
1077                                                                 }
1078                                                         }
1079                                                         strncat(p, hostname, sizeof(prompt) - strlen(prompt) - 1);
1080                                                 } else {
1081                                                         strncat(p, "localhost", sizeof(prompt) - strlen(prompt) - 1);
1082                                                 }
1083                                                 break;
1084 #ifdef linux
1085                                         case 'l': /* load avg */
1086                                                 t++;
1087                                                 if ((LOADAVG = fopen("/proc/loadavg", "r"))) {
1088                                                         float avg1, avg2, avg3;
1089                                                         int actproc, totproc, npid, which;
1090                                                         fscanf(LOADAVG, "%f %f %f %d/%d %d",
1091                                                                 &avg1, &avg2, &avg3, &actproc, &totproc, &npid);
1092                                                         if (sscanf(t, "%d", &which) == 1) {
1093                                                                 switch (which) {
1094                                                                         case 1:
1095                                                                                 snprintf(p, sizeof(prompt) - strlen(prompt), "%.2f", avg1);
1096                                                                                 break;
1097                                                                         case 2:
1098                                                                                 snprintf(p, sizeof(prompt) - strlen(prompt), "%.2f", avg2);
1099                                                                                 break;
1100                                                                         case 3:
1101                                                                                 snprintf(p, sizeof(prompt) - strlen(prompt), "%.2f", avg3);
1102                                                                                 break;
1103                                                                         case 4:
1104                                                                                 snprintf(p, sizeof(prompt) - strlen(prompt), "%d/%d", actproc, totproc);
1105                                                                                 break;
1106                                                                         case 5:
1107                                                                                 snprintf(p, sizeof(prompt) - strlen(prompt), "%d", npid);
1108                                                                                 break;
1109                                                                 }
1110                                                         }
1111                                                 }
1112                                                 break;
1113 #endif
1114                                         case 't': /* time */
1115                                                 memset(&tm, 0, sizeof(struct tm));
1116                                                 gettimeofday(&tv, NULL);
1117                                                 if (localtime_r(&(tv.tv_sec), &tm)) {
1118                                                         strftime(p, sizeof(prompt) - strlen(prompt), "%H:%M:%S", &tm);
1119                                                 }
1120                                                 break;
1121                                         case '#': /* process console or remote? */
1122                                                 if (! option_remote) {
1123                                                         strncat(p, "#", sizeof(prompt) - strlen(prompt) - 1);
1124                                                 } else {
1125                                                         strncat(p, ">", sizeof(prompt) - strlen(prompt) - 1);
1126                                                 }
1127                                                 break;
1128                                         case '%': /* literal % */
1129                                                 strncat(p, "%", sizeof(prompt) - strlen(prompt) - 1);
1130                                                 break;
1131                                         case '\0': /* % is last character - prevent bug */
1132                                                 t--;
1133                                                 break;
1134                                 }
1135                                 while (*p != '\0') {
1136                                         p++;
1137                                 }
1138                                 t++;
1139                         } else {
1140                                 *p = *t;
1141                                 p++;
1142                                 t++;
1143                         }
1144                 }
1145                 if (color_used) {
1146                         /* Force colors back to normal at end */
1147                         term_color_code(term_code, COLOR_WHITE, COLOR_BLACK, sizeof(term_code));
1148                         if (strlen(term_code) > sizeof(prompt) - strlen(prompt)) {
1149                                 strncat(prompt + sizeof(prompt) - strlen(term_code) - 1, term_code, strlen(term_code));
1150                         } else {
1151                                 strncat(p, term_code, sizeof(term_code));
1152                         }
1153                 }
1154         } else if (remotehostname)
1155                 snprintf(prompt, sizeof(prompt), ASTERISK_PROMPT2, remotehostname);
1156         else
1157                 snprintf(prompt, sizeof(prompt), ASTERISK_PROMPT);
1158
1159         return(prompt); 
1160 }
1161
1162 static char **ast_el_strtoarr(char *buf)
1163 {
1164         char **match_list = NULL, *retstr;
1165         size_t match_list_len;
1166         int matches = 0;
1167
1168         match_list_len = 1;
1169         while ( (retstr = strsep(&buf, " ")) != NULL) {
1170
1171                 if (!strcmp(retstr, AST_CLI_COMPLETE_EOF))
1172                         break;
1173                 if (matches + 1 >= match_list_len) {
1174                         match_list_len <<= 1;
1175                         match_list = realloc(match_list, match_list_len * sizeof(char *));
1176                 }
1177
1178                 match_list[matches++] = strdup(retstr);
1179         }
1180
1181         if (!match_list)
1182                 return (char **) NULL;
1183
1184         if (matches>= match_list_len)
1185                 match_list = realloc(match_list, (match_list_len + 1) * sizeof(char *));
1186
1187         match_list[matches] = (char *) NULL;
1188
1189         return match_list;
1190 }
1191
1192 static int ast_el_sort_compare(const void *i1, const void *i2)
1193 {
1194         char *s1, *s2;
1195
1196         s1 = ((char **)i1)[0];
1197         s2 = ((char **)i2)[0];
1198
1199         return strcasecmp(s1, s2);
1200 }
1201
1202 static int ast_cli_display_match_list(char **matches, int len, int max)
1203 {
1204         int i, idx, limit, count;
1205         int screenwidth = 0;
1206         int numoutput = 0, numoutputline = 0;
1207
1208         screenwidth = ast_get_termcols(STDOUT_FILENO);
1209
1210         /* find out how many entries can be put on one line, with two spaces between strings */
1211         limit = screenwidth / (max + 2);
1212         if (limit == 0)
1213                 limit = 1;
1214
1215         /* how many lines of output */
1216         count = len / limit;
1217         if (count * limit < len)
1218                 count++;
1219
1220         idx = 1;
1221
1222         qsort(&matches[0], (size_t)(len + 1), sizeof(char *), ast_el_sort_compare);
1223
1224         for (; count > 0; count--) {
1225                 numoutputline = 0;
1226                 for (i=0; i < limit && matches[idx]; i++, idx++) {
1227
1228                         /* Don't print dupes */
1229                         if ( (matches[idx+1] != NULL && strcmp(matches[idx], matches[idx+1]) == 0 ) ) {
1230                                 i--;
1231                                 free(matches[idx]);
1232                                 matches[idx] = NULL;
1233                                 continue;
1234                         }
1235
1236                         numoutput++;
1237                         numoutputline++;
1238                         fprintf(stdout, "%-*s  ", max, matches[idx]);
1239                         free(matches[idx]);
1240                         matches[idx] = NULL;
1241                 }
1242                 if (numoutputline > 0)
1243                         fprintf(stdout, "\n");
1244         }
1245
1246         return numoutput;
1247 }
1248
1249
1250 static char *cli_complete(EditLine *el, int ch)
1251 {
1252         int len=0;
1253         char *ptr;
1254         int nummatches = 0;
1255         char **matches;
1256         int retval = CC_ERROR;
1257         char buf[2048];
1258         int res;
1259
1260         LineInfo *lf = (LineInfo *)el_line(el);
1261
1262         *(char *)lf->cursor = '\0';
1263         ptr = (char *)lf->cursor;
1264         if (ptr) {
1265                 while (ptr > lf->buffer) {
1266                         if (isspace(*ptr)) {
1267                                 ptr++;
1268                                 break;
1269                         }
1270                         ptr--;
1271                 }
1272         }
1273
1274         len = lf->cursor - ptr;
1275
1276         if (option_remote) {
1277                 snprintf(buf, sizeof(buf),"_COMMAND NUMMATCHES \"%s\" \"%s\"", lf->buffer, ptr); 
1278                 fdprint(ast_consock, buf);
1279                 res = read(ast_consock, buf, sizeof(buf));
1280                 buf[res] = '\0';
1281                 nummatches = atoi(buf);
1282
1283                 if (nummatches > 0) {
1284                         char *mbuf;
1285                         int mlen = 0, maxmbuf = 2048;
1286                         /* Start with a 2048 byte buffer */
1287                         mbuf = malloc(maxmbuf);
1288                         if (!mbuf)
1289                                 return (char *)(CC_ERROR);
1290                         snprintf(buf, sizeof(buf),"_COMMAND MATCHESARRAY \"%s\" \"%s\"", lf->buffer, ptr); 
1291                         fdprint(ast_consock, buf);
1292                         res = 0;
1293                         mbuf[0] = '\0';
1294                         while (!strstr(mbuf, AST_CLI_COMPLETE_EOF) && res != -1) {
1295                                 if (mlen + 1024 > maxmbuf) {
1296                                         /* Every step increment buffer 1024 bytes */
1297                                         maxmbuf += 1024;
1298                                         mbuf = realloc(mbuf, maxmbuf);
1299                                         if (!mbuf)
1300                                                 return (char *)(CC_ERROR);
1301                                 }
1302                                 /* Only read 1024 bytes at a time */
1303                                 res = read(ast_consock, mbuf + mlen, 1024);
1304                                 if (res > 0)
1305                                         mlen += res;
1306                         }
1307                         mbuf[mlen] = '\0';
1308
1309                         matches = ast_el_strtoarr(mbuf);
1310                         free(mbuf);
1311                 } else
1312                         matches = (char **) NULL;
1313
1314
1315         } else {
1316
1317                 nummatches = ast_cli_generatornummatches((char *)lf->buffer,ptr);
1318                 matches = ast_cli_completion_matches((char *)lf->buffer,ptr);
1319         }
1320
1321         if (matches) {
1322                 int i;
1323                 int matches_num, maxlen, match_len;
1324
1325                 if (matches[0][0] != '\0') {
1326                         el_deletestr(el, (int) len);
1327                         el_insertstr(el, matches[0]);
1328                         retval = CC_REFRESH;
1329                 }
1330
1331                 if (nummatches == 1) {
1332                         /* Found an exact match */
1333                         el_insertstr(el, " ");
1334                         retval = CC_REFRESH;
1335                 } else {
1336                         /* Must be more than one match */
1337                         for (i=1, maxlen=0; matches[i]; i++) {
1338                                 match_len = strlen(matches[i]);
1339                                 if (match_len > maxlen)
1340                                         maxlen = match_len;
1341                         }
1342                         matches_num = i - 1;
1343                         if (matches_num >1) {
1344                                 fprintf(stdout, "\n");
1345                                 ast_cli_display_match_list(matches, nummatches, maxlen);
1346                                 retval = CC_REDISPLAY;
1347                         } else { 
1348                                 el_insertstr(el," ");
1349                                 retval = CC_REFRESH;
1350                         }
1351                 }
1352         free(matches);
1353         }
1354
1355         return (char *)(long)retval;
1356 }
1357
1358 static int ast_el_initialize(void)
1359 {
1360         HistEvent ev;
1361         char *editor = getenv("AST_EDITOR");
1362
1363         if (el != NULL)
1364                 el_end(el);
1365         if (el_hist != NULL)
1366                 history_end(el_hist);
1367
1368         el = el_init("asterisk", stdin, stdout, stderr);
1369         el_set(el, EL_PROMPT, cli_prompt);
1370
1371         el_set(el, EL_EDITMODE, 1);             
1372         el_set(el, EL_EDITOR, editor ? editor : "emacs");               
1373         el_hist = history_init();
1374         if (!el || !el_hist)
1375                 return -1;
1376
1377         /* setup history with 100 entries */
1378         history(el_hist, &ev, H_SETSIZE, 100);
1379
1380         el_set(el, EL_HIST, history, el_hist);
1381
1382         el_set(el, EL_ADDFN, "ed-complete", "Complete argument", cli_complete);
1383         /* Bind <tab> to command completion */
1384         el_set(el, EL_BIND, "^I", "ed-complete", NULL);
1385         /* Bind ? to command completion */
1386         el_set(el, EL_BIND, "?", "ed-complete", NULL);
1387         /* Bind ^D to redisplay */
1388         el_set(el, EL_BIND, "^D", "ed-redisplay", NULL);
1389
1390         return 0;
1391 }
1392
1393 static int ast_el_add_history(char *buf)
1394 {
1395         HistEvent ev;
1396
1397         if (el_hist == NULL || el == NULL)
1398                 ast_el_initialize();
1399         if (strlen(buf) > 256)
1400                 return 0;
1401         return (history(el_hist, &ev, H_ENTER, buf));
1402 }
1403
1404 static int ast_el_write_history(char *filename)
1405 {
1406         HistEvent ev;
1407
1408         if (el_hist == NULL || el == NULL)
1409                 ast_el_initialize();
1410
1411         return (history(el_hist, &ev, H_SAVE, filename));
1412 }
1413
1414 static int ast_el_read_history(char *filename)
1415 {
1416         char buf[256];
1417         FILE *f;
1418         int ret = -1;
1419
1420         if (el_hist == NULL || el == NULL)
1421                 ast_el_initialize();
1422
1423         if ((f = fopen(filename, "r")) == NULL)
1424                 return ret;
1425
1426         while (!feof(f)) {
1427                 fgets(buf, sizeof(buf), f);
1428                 if (!strcmp(buf, "_HiStOrY_V2_\n"))
1429                         continue;
1430                 if (ast_all_zeros(buf))
1431                         continue;
1432                 if ((ret = ast_el_add_history(buf)) == -1)
1433                         break;
1434         }
1435         fclose(f);
1436
1437         return ret;
1438 }
1439
1440 static void ast_remotecontrol(char * data)
1441 {
1442         char buf[80];
1443         int res;
1444         char filename[80] = "";
1445         char *hostname;
1446         char *cpid;
1447         char *version;
1448         int pid;
1449         char tmp[80];
1450         char *stringp=NULL;
1451
1452         char *ebuf;
1453         int num = 0;
1454
1455         read(ast_consock, buf, sizeof(buf));
1456         if (data)
1457                 write(ast_consock, data, strlen(data) + 1);
1458         stringp=buf;
1459         hostname = strsep(&stringp, "/");
1460         cpid = strsep(&stringp, "/");
1461         version = strsep(&stringp, "\n");
1462         if (!version)
1463                 version = "<Version Unknown>";
1464         stringp=hostname;
1465         strsep(&stringp, ".");
1466         if (cpid)
1467                 pid = atoi(cpid);
1468         else
1469                 pid = -1;
1470         snprintf(tmp, sizeof(tmp), "set verbose atleast %d", option_verbose);
1471         fdprint(ast_consock, tmp);
1472         snprintf(tmp, sizeof(tmp), "set debug atleast %d", option_debug);
1473         fdprint(ast_consock, tmp);
1474         ast_verbose("Connected to Asterisk %s currently running on %s (pid = %d)\n", version, hostname, pid);
1475         remotehostname = hostname;
1476         if (getenv("HOME")) 
1477                 snprintf(filename, sizeof(filename), "%s/.asterisk_history", getenv("HOME"));
1478         if (el_hist == NULL || el == NULL)
1479                 ast_el_initialize();
1480
1481         el_set(el, EL_GETCFN, ast_el_read_char);
1482
1483         if (!ast_strlen_zero(filename))
1484                 ast_el_read_history(filename);
1485
1486         ast_cli_register(&quit);
1487         ast_cli_register(&astexit);
1488 #if 0
1489         ast_cli_register(&astshutdown);
1490 #endif  
1491         if (option_exec && data) {  /* hack to print output then exit if asterisk -rx is used */
1492                 char tempchar;
1493                 struct pollfd fds[0];
1494                 fds[0].fd = ast_consock;
1495                 fds[0].events = POLLIN;
1496                 fds[0].revents = 0;
1497                 while(poll(fds, 1, 100) > 0) {
1498                         ast_el_read_char(el, &tempchar);
1499                 }
1500                 return;
1501         }
1502         for(;;) {
1503                 ebuf = (char *)el_gets(el, &num);
1504
1505                 if (ebuf && !ast_strlen_zero(ebuf)) {
1506                         if (ebuf[strlen(ebuf)-1] == '\n')
1507                                 ebuf[strlen(ebuf)-1] = '\0';
1508                         if (!remoteconsolehandler(ebuf)) {
1509                                 res = write(ast_consock, ebuf, strlen(ebuf) + 1);
1510                                 if (res < 1) {
1511                                         ast_log(LOG_WARNING, "Unable to write: %s\n", strerror(errno));
1512                                         break;
1513                                 }
1514                         }
1515                 }
1516         }
1517         printf("\nDisconnected from Asterisk server\n");
1518 }
1519
1520 static int show_version(void)
1521 {
1522         printf("Asterisk " ASTERISK_VERSION "\n");
1523         return 0;
1524 }
1525
1526 static int show_cli_help(void) {
1527         printf("Asterisk " ASTERISK_VERSION ", Copyright (C) 2000 - 2005, Digium.\n");
1528         printf("Usage: asterisk [OPTIONS]\n");
1529         printf("Valid Options:\n");
1530         printf("   -V              Display version number and exit\n");
1531         printf("   -C <configfile> Use an alternate configuration file\n");
1532         printf("   -G <group>      Run as a group other than the caller\n");
1533         printf("   -U <user>       Run as a user other than the caller\n");
1534         printf("   -c              Provide console CLI\n");
1535         printf("   -d              Enable extra debugging\n");
1536         printf("   -f              Do not fork\n");
1537         printf("   -g              Dump core in case of a crash\n");
1538         printf("   -h              This help screen\n");
1539         printf("   -i              Initialize crypto keys at startup\n");
1540         printf("   -n              Disable console colorization\n");
1541         printf("   -p              Run as pseudo-realtime thread\n");
1542         printf("   -q              Quiet mode (suppress output)\n");
1543         printf("   -r              Connect to Asterisk on this machine\n");
1544         printf("   -R              Connect to Asterisk, and attempt to reconnect if disconnected\n");
1545         printf("   -t              Record soundfiles in /var/tmp and move them where they belong after they are done.\n");
1546         printf("   -T              Display the time in [Mmm dd hh:mm:ss] format for each line of output to the CLI.\n");
1547         printf("   -v              Increase verbosity (multiple v's = more verbose)\n");
1548         printf("   -x <cmd>        Execute command <cmd> (only valid with -r)\n");
1549         printf("\n");
1550         return 0;
1551 }
1552
1553 static void ast_readconfig(void) {
1554         struct ast_config *cfg;
1555         struct ast_variable *v;
1556         struct ast_variable *v_ctlfile;
1557         char *config = ASTCONFPATH;
1558
1559         if (option_overrideconfig == 1) {
1560                 cfg = ast_config_load((char *)ast_config_AST_CONFIG_FILE);
1561                 if (!cfg)
1562                         ast_log(LOG_WARNING, "Unable to open specified master config file '%s', using builtin defaults\n", ast_config_AST_CONFIG_FILE);
1563         } else {
1564                 cfg = ast_config_load(config);
1565         }
1566
1567         /* init with buildtime config */
1568         strncpy((char *)ast_config_AST_CONFIG_DIR,AST_CONFIG_DIR,sizeof(ast_config_AST_CONFIG_DIR)-1);
1569         strncpy((char *)ast_config_AST_SPOOL_DIR,AST_SPOOL_DIR,sizeof(ast_config_AST_SPOOL_DIR)-1);
1570         strncpy((char *)ast_config_AST_MODULE_DIR,AST_MODULE_DIR,sizeof(ast_config_AST_VAR_DIR)-1);
1571         strncpy((char *)ast_config_AST_VAR_DIR,AST_VAR_DIR,sizeof(ast_config_AST_VAR_DIR)-1);
1572         strncpy((char *)ast_config_AST_LOG_DIR,AST_LOG_DIR,sizeof(ast_config_AST_LOG_DIR)-1);
1573         strncpy((char *)ast_config_AST_AGI_DIR,AST_AGI_DIR,sizeof(ast_config_AST_AGI_DIR)-1);
1574         strncpy((char *)ast_config_AST_DB,AST_DB,sizeof(ast_config_AST_DB)-1);
1575         strncpy((char *)ast_config_AST_KEY_DIR,AST_KEY_DIR,sizeof(ast_config_AST_KEY_DIR)-1);
1576         strncpy((char *)ast_config_AST_PID,AST_PID,sizeof(ast_config_AST_PID)-1);
1577         strncpy((char *)ast_config_AST_SOCKET,AST_SOCKET,sizeof(ast_config_AST_SOCKET)-1);
1578         strncpy((char *)ast_config_AST_RUN_DIR,AST_RUN_DIR,sizeof(ast_config_AST_RUN_DIR)-1);
1579         
1580         /* no asterisk.conf? no problem, use buildtime config! */
1581         if (!cfg) {
1582                 return;
1583         }
1584
1585         v_ctlfile = ast_variable_browse(cfg, "files");
1586         while (v_ctlfile!=NULL) {
1587                 if (strcmp(v_ctlfile->name,"astctl")==0)
1588                         break;
1589                 v_ctlfile=v_ctlfile->next;
1590         }
1591
1592         v = ast_variable_browse(cfg, "directories");
1593         while(v) {
1594                 if (!strcasecmp(v->name, "astetcdir")) {
1595                         strncpy((char *)ast_config_AST_CONFIG_DIR,v->value,sizeof(ast_config_AST_CONFIG_DIR)-1);
1596                 } else if (!strcasecmp(v->name, "astspooldir")) {
1597                         strncpy((char *)ast_config_AST_SPOOL_DIR,v->value,sizeof(ast_config_AST_SPOOL_DIR)-1);
1598                 } else if (!strcasecmp(v->name, "astvarlibdir")) {
1599                         strncpy((char *)ast_config_AST_VAR_DIR,v->value,sizeof(ast_config_AST_VAR_DIR)-1);
1600                         snprintf((char *)ast_config_AST_DB,sizeof(ast_config_AST_DB),"%s/%s",v->value,"astdb");    
1601                 } else if (!strcasecmp(v->name, "astlogdir")) {
1602                         strncpy((char *)ast_config_AST_LOG_DIR,v->value,sizeof(ast_config_AST_LOG_DIR)-1);
1603                 } else if (!strcasecmp(v->name, "astagidir")) {
1604                         strncpy((char *)ast_config_AST_AGI_DIR,v->value,sizeof(ast_config_AST_AGI_DIR)-1);
1605                 } else if (!strcasecmp(v->name, "astrundir")) {
1606                         snprintf((char *)ast_config_AST_PID,sizeof(ast_config_AST_PID),"%s/%s",v->value,"asterisk.pid");
1607                         snprintf((char *)ast_config_AST_SOCKET,sizeof(ast_config_AST_SOCKET),"%s/%s",v->value,v_ctlfile==NULL?"asterisk.ctl":v_ctlfile->value);
1608                         strncpy((char *)ast_config_AST_RUN_DIR,v->value,sizeof(ast_config_AST_RUN_DIR)-1);
1609                 } else if (!strcasecmp(v->name, "astmoddir")) {
1610                         strncpy((char *)ast_config_AST_MODULE_DIR,v->value,sizeof(ast_config_AST_MODULE_DIR)-1);
1611                 }
1612                 v = v->next;
1613         }
1614         v = ast_variable_browse(cfg, "options");
1615         while(v) {
1616                 /* verbose level (-v at startup) */
1617                 if (!strcasecmp(v->name, "verbose")) {
1618                         option_verbose= atoi(v->value);
1619                 /* whether or not to force timestamping. (-T at startup) */
1620                 } else if (!strcasecmp(v->name, "timestamp")) {
1621                         option_timestamp = ast_true(v->value);
1622                 /* whether or not to support #exec in config files */
1623                 } else if (!strcasecmp(v->name, "execincludes")) {
1624                         option_exec_includes = ast_true(v->value);
1625                 /* debug level (-d at startup) */
1626                 } else if (!strcasecmp(v->name, "debug")) {
1627                         option_debug = 0;
1628                         if (sscanf(v->value, "%d", &option_debug) != 1) {
1629                                 option_debug = ast_true(v->value);
1630                         }
1631                 /* Disable forking (-f at startup) */
1632                 } else if (!strcasecmp(v->name, "nofork")) {
1633                         option_nofork = ast_true(v->value);
1634                 /* Run quietly (-q at startup ) */
1635                 } else if (!strcasecmp(v->name, "quiet")) {
1636                         option_quiet = ast_true(v->value);
1637                 /* Run as console (-c at startup, implies nofork) */
1638                 } else if (!strcasecmp(v->name, "console")) {
1639                         option_console = ast_true(v->value);
1640                 /* Run with highg priority if the O/S permits (-p at startup) */
1641                 } else if (!strcasecmp(v->name, "highpriority")) {
1642                         option_highpriority = ast_true(v->value);
1643                 /* Initialize RSA auth keys (IAX2) (-i at startup) */
1644                 } else if (!strcasecmp(v->name, "initcrypto")) {
1645                         option_initcrypto = ast_true(v->value);
1646                 /* Disable ANSI colors for console (-c at startup) */
1647                 } else if (!strcasecmp(v->name, "nocolor")) {
1648                         option_nocolor = ast_true(v->value);
1649                 /* Dump core in case of crash (-g) */
1650                 } else if (!strcasecmp(v->name, "dumpcore")) {
1651                         option_dumpcore = ast_true(v->value);
1652                 /* Cache recorded sound files to another directory during recording */
1653                 } else if (!strcasecmp(v->name, "cache_record_files")) {
1654                         option_cache_record_files = ast_true(v->value);
1655                 /* Specify cache directory */
1656                 }  else if (!strcasecmp(v->name, "record_cache_dir")) {
1657                         strncpy(record_cache_dir,v->value,AST_CACHE_DIR_LEN);
1658                 /* Build transcode paths via SLINEAR, instead of directly */
1659                 } else if (!strcasecmp(v->name, "transcode_via_sln")) {
1660                         option_transcode_slin = ast_true(v->value);
1661                 }
1662                 v = v->next;
1663         }
1664         ast_config_destroy(cfg);
1665 }
1666
1667 int main(int argc, char *argv[])
1668 {
1669         int c;
1670         char filename[80] = "";
1671         char hostname[256];
1672         char tmp[80];
1673         char * xarg = NULL;
1674         int x;
1675         FILE *f;
1676         sigset_t sigs;
1677         int num;
1678         char *buf;
1679         char *runuser=NULL, *rungroup=NULL;
1680         struct pollfd silly_macos[1];   
1681
1682         /* Remember original args for restart */
1683         if (argc > sizeof(_argv) / sizeof(_argv[0]) - 1) {
1684                 fprintf(stderr, "Truncating argument size to %d\n", (int)(sizeof(_argv) / sizeof(_argv[0])) - 1);
1685                 argc = sizeof(_argv) / sizeof(_argv[0]) - 1;
1686         }
1687         for (x=0;x<argc;x++)
1688                 _argv[x] = argv[x];
1689         _argv[x] = NULL;
1690
1691         /* if the progname is rasterisk consider it a remote console */
1692         if (argv[0] && (strstr(argv[0], "rasterisk")) != NULL) {
1693                 option_remote++;
1694                 option_nofork++;
1695         }
1696         if (gethostname(hostname, sizeof(hostname)))
1697                 strncpy(hostname, "<Unknown>", sizeof(hostname)-1);
1698         ast_mainpid = getpid();
1699         ast_ulaw_init();
1700         ast_alaw_init();
1701         callerid_init();
1702         ast_utils_init();
1703         tdd_init();
1704         if (getenv("HOME")) 
1705                 snprintf(filename, sizeof(filename), "%s/.asterisk_history", getenv("HOME"));
1706         /* Check if we're root */
1707         /*
1708         if (geteuid()) {
1709                 ast_log(LOG_ERROR, "Must be run as root\n");
1710                 exit(1);
1711         }
1712         */
1713         /* Check for options */
1714         while((c=getopt(argc, argv, "tThfdvVqprRgcinx:U:G:C:")) != -1) {
1715                 switch(c) {
1716                 case 'd':
1717                         option_debug++;
1718                         option_nofork++;
1719                         break;
1720                 case 'c':
1721                         option_console++;
1722                         option_nofork++;
1723                         break;
1724                 case 'f':
1725                         option_nofork++;
1726                         break;
1727                 case 'n':
1728                         option_nocolor++;
1729                         break;
1730                 case 'r':
1731                         option_remote++;
1732                         option_nofork++;
1733                         break;
1734                 case 'R':
1735                         option_remote++;
1736                         option_nofork++;
1737                         option_reconnect++;
1738                         break;
1739                 case 'p':
1740                         option_highpriority++;
1741                         break;
1742                 case 'v':
1743                         option_verbose++;
1744                         option_nofork++;
1745                         break;
1746                 case 'q':
1747                         option_quiet++;
1748                         break;
1749                 case 't':
1750                         option_cache_record_files++;
1751                         break;
1752                 case 'T':
1753                         option_timestamp++;
1754                         break;
1755                 case 'x':
1756                         option_exec++;
1757                         xarg = optarg;
1758                         break;
1759                 case 'C':
1760                         strncpy((char *)ast_config_AST_CONFIG_FILE,optarg,sizeof(ast_config_AST_CONFIG_FILE) - 1);
1761                         option_overrideconfig++;
1762                         break;
1763                 case 'i':
1764                         option_initcrypto++;
1765                         break;
1766                 case'g':
1767                         option_dumpcore++;
1768                         break;
1769                 case 'h':
1770                         show_cli_help();
1771                         exit(0);
1772                 case 'V':
1773                         show_version();
1774                         exit(0);
1775                 case 'U':
1776                         runuser = optarg;
1777                         break;
1778                 case 'G':
1779                         rungroup = optarg;
1780                         break;
1781                 case '?':
1782                         exit(1);
1783                 }
1784         }
1785
1786         if (option_dumpcore) {
1787                 struct rlimit l;
1788                 memset(&l, 0, sizeof(l));
1789                 l.rlim_cur = RLIM_INFINITY;
1790                 l.rlim_max = RLIM_INFINITY;
1791                 if (setrlimit(RLIMIT_CORE, &l)) {
1792                         ast_log(LOG_WARNING, "Unable to disable core size resource limit: %s\n", strerror(errno));
1793                 }
1794         }
1795
1796         if (option_console && !option_verbose) 
1797                 ast_verbose("[ Reading Master Configuration ]");
1798         ast_readconfig();
1799
1800         if (set_priority(option_highpriority)) {
1801                 exit(1);
1802         }
1803
1804         if (rungroup) {
1805                 struct group *gr;
1806                 gr = getgrnam(rungroup);
1807                 if (!gr) {
1808                         ast_log(LOG_WARNING, "No such group '%s'!\n", rungroup);
1809                         exit(1);
1810                 }
1811                 if (setgid(gr->gr_gid)) {
1812                         ast_log(LOG_WARNING, "Unable to setgid to %d (%s)\n", gr->gr_gid, rungroup);
1813                         exit(1);
1814                 }
1815                 if (option_verbose)
1816                         ast_verbose("Running as group '%s'\n", rungroup);
1817         }
1818
1819         if (runuser) {
1820                 struct passwd *pw;
1821                 pw = getpwnam(runuser);
1822                 if (!pw) {
1823                         ast_log(LOG_WARNING, "No such user '%s'!\n", runuser);
1824                         exit(1);
1825                 }
1826                 if (setuid(pw->pw_uid)) {
1827                         ast_log(LOG_WARNING, "Unable to setuid to %d (%s)\n", pw->pw_uid, runuser);
1828                         exit(1);
1829                 }
1830                 if (option_verbose)
1831                         ast_verbose("Running as user '%s'\n", runuser);
1832         }
1833
1834         term_init();
1835         printf(term_end());
1836         fflush(stdout);
1837
1838         if (option_console && !option_verbose) 
1839                 ast_verbose("[ Initializing Custom Configuration Options ]");
1840         /* custom config setup */
1841         register_config_cli();
1842         read_config_maps();
1843         
1844
1845         if (option_console) {
1846                 if (el_hist == NULL || el == NULL)
1847                         ast_el_initialize();
1848
1849                 if (!ast_strlen_zero(filename))
1850                         ast_el_read_history(filename);
1851         }
1852
1853         if (ast_tryconnect()) {
1854                 /* One is already running */
1855                 if (option_remote) {
1856                         if (option_exec) {
1857                                 ast_remotecontrol(xarg);
1858                                 quit_handler(0, 0, 0, 0);
1859                                 exit(0);
1860                         }
1861                         printf(term_quit());
1862                         ast_register_verbose(console_verboser);
1863                         WELCOME_MESSAGE;
1864                         ast_remotecontrol(NULL);
1865                         quit_handler(0, 0, 0, 0);
1866                         exit(0);
1867                 } else {
1868                         ast_log(LOG_ERROR, "Asterisk already running on %s.  Use 'asterisk -r' to connect.\n", (char *)ast_config_AST_SOCKET);
1869                         printf(term_quit());
1870                         exit(1);
1871                 }
1872         } else if (option_remote || option_exec) {
1873                 ast_log(LOG_ERROR, "Unable to connect to remote asterisk (does %s exist?)\n",ast_config_AST_SOCKET);
1874                 printf(term_quit());
1875                 exit(1);
1876         }
1877         /* Blindly write pid file since we couldn't connect */
1878         unlink((char *)ast_config_AST_PID);
1879         f = fopen((char *)ast_config_AST_PID, "w");
1880         if (f) {
1881                 fprintf(f, "%d\n", getpid());
1882                 fclose(f);
1883         } else
1884                 ast_log(LOG_WARNING, "Unable to open pid file '%s': %s\n", (char *)ast_config_AST_PID, strerror(errno));
1885
1886         if (!option_verbose && !option_debug && !option_nofork && !option_console) {
1887                 daemon(0,0);
1888                 /* Blindly re-write pid file since we are forking */
1889                 unlink((char *)ast_config_AST_PID);
1890                 f = fopen((char *)ast_config_AST_PID, "w");
1891                 if (f) {
1892                         fprintf(f, "%d\n", getpid());
1893                         fclose(f);
1894                 } else
1895                         ast_log(LOG_WARNING, "Unable to open pid file '%s': %s\n", (char *)ast_config_AST_PID, strerror(errno));
1896         }
1897
1898         /* Test recursive mutex locking. */
1899         if (test_for_thread_safety())
1900                 ast_verbose("Warning! Asterisk is not thread safe.\n");
1901
1902         ast_makesocket();
1903         sigemptyset(&sigs);
1904         sigaddset(&sigs, SIGHUP);
1905         sigaddset(&sigs, SIGTERM);
1906         sigaddset(&sigs, SIGINT);
1907         sigaddset(&sigs, SIGPIPE);
1908         sigaddset(&sigs, SIGWINCH);
1909         pthread_sigmask(SIG_BLOCK, &sigs, NULL);
1910         if (option_console || option_verbose || option_remote)
1911                 ast_register_verbose(console_verboser);
1912         /* Print a welcome message if desired */
1913         if (option_verbose || option_console) {
1914                 WELCOME_MESSAGE;
1915         }
1916         if (option_console && !option_verbose) 
1917                 ast_verbose("[ Booting...");
1918
1919         signal(SIGURG, urg_handler);
1920         signal(SIGINT, __quit_handler);
1921         signal(SIGTERM, __quit_handler);
1922         signal(SIGHUP, hup_handler);
1923         signal(SIGCHLD, child_handler);
1924         signal(SIGPIPE, SIG_IGN);
1925
1926         /* ensure that the random number generators are seeded with a different value every time
1927            Asterisk is started
1928         */
1929         srand((unsigned int) getpid() + (unsigned int) time(NULL));
1930         srandom((unsigned int) getpid() + (unsigned int) time(NULL));
1931
1932         if (init_logger()) {
1933                 printf(term_quit());
1934                 exit(1);
1935         }
1936         ast_channels_init();
1937         if (init_manager()) {
1938                 printf(term_quit());
1939                 exit(1);
1940         }
1941         ast_rtp_init();
1942         if (ast_image_init()) {
1943                 printf(term_quit());
1944                 exit(1);
1945         }
1946         if (ast_file_init()) {
1947                 printf(term_quit());
1948                 exit(1);
1949         }
1950         if (load_pbx()) {
1951                 printf(term_quit());
1952                 exit(1);
1953         }
1954         if (load_modules()) {
1955                 printf(term_quit());
1956                 exit(1);
1957         }
1958         if (init_framer()) {
1959                 printf(term_quit());
1960                 exit(1);
1961         }
1962         if (astdb_init()) {
1963                 printf(term_quit());
1964                 exit(1);
1965         }
1966         if (ast_enum_init()) {
1967                 printf(term_quit());
1968                 exit(1);
1969         }
1970         if (dnsmgr_init()) {
1971                 printf(term_quit());
1972                 exit(1);
1973         }
1974 #if 0
1975         /* This should no longer be necessary */
1976         /* sync cust config and reload some internals in case a custom config handler binded to them */
1977         read_ast_cust_config();
1978         reload_logger(0);
1979         reload_manager();
1980         ast_enum_reload();
1981         ast_rtp_reload();
1982 #endif
1983
1984
1985         /* We might have the option of showing a console, but for now just
1986            do nothing... */
1987         if (option_console && !option_verbose)
1988                 ast_verbose(" ]\n");
1989         if (option_verbose || option_console)
1990                 ast_verbose(term_color(tmp, "Asterisk Ready.\n", COLOR_BRWHITE, COLOR_BLACK, sizeof(tmp)));
1991         if (option_nofork)
1992                 consolethread = pthread_self();
1993         fully_booted = 1;
1994         pthread_sigmask(SIG_UNBLOCK, &sigs, NULL);
1995 #ifdef __AST_DEBUG_MALLOC
1996         __ast_mm_init();
1997 #endif  
1998         time(&ast_startuptime);
1999         ast_cli_register(&astshutdownnow);
2000         ast_cli_register(&astshutdowngracefully);
2001         ast_cli_register(&astrestartnow);
2002         ast_cli_register(&astrestartgracefully);
2003         ast_cli_register(&astrestartwhenconvenient);
2004         ast_cli_register(&astshutdownwhenconvenient);
2005         ast_cli_register(&aborthalt);
2006         ast_cli_register(&astbang);
2007         if (option_console) {
2008                 /* Console stuff now... */
2009                 /* Register our quit function */
2010                 char title[256];
2011                 set_icon("Asterisk");
2012                 snprintf(title, sizeof(title), "Asterisk Console on '%s' (pid %d)", hostname, ast_mainpid);
2013                 set_title(title);
2014                 ast_cli_register(&quit);
2015                 ast_cli_register(&astexit);
2016
2017                 for (;;) {
2018                         buf = (char *)el_gets(el, &num);
2019                         if (buf) {
2020                                 if (buf[strlen(buf)-1] == '\n')
2021                                         buf[strlen(buf)-1] = '\0';
2022
2023                                 consolehandler((char *)buf);
2024                         } else {
2025                                 if (write(STDOUT_FILENO, "\nUse EXIT or QUIT to exit the asterisk console\n",
2026                                                                   strlen("\nUse EXIT or QUIT to exit the asterisk console\n")) < 0) {
2027                                         /* Whoa, stdout disappeared from under us... Make /dev/null's */
2028                                         int fd;
2029                                         fd = open("/dev/null", O_RDWR);
2030                                         if (fd > -1) {
2031                                                 dup2(fd, STDOUT_FILENO);
2032                                                 dup2(fd, STDIN_FILENO);
2033                                         } else
2034                                                 ast_log(LOG_WARNING, "Failed to open /dev/null to recover from dead console.  Bad things will happen!\n");
2035                                         break;
2036                                 }
2037                         }
2038                 }
2039
2040         }
2041         /* Do nothing */
2042         for(;;) 
2043                 poll(silly_macos,0, -1);
2044         return 0;
2045 }