Only send 180 ringing once, fix CTRL+D in main code
[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, Mark Spencer
7  *
8  * Mark Spencer <markster@linux-support.net>
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 <asterisk/logger.h>
17 #include <asterisk/options.h>
18 #include <asterisk/cli.h>
19 #include <asterisk/channel.h>
20 #include <asterisk/ulaw.h>
21 #include <asterisk/alaw.h>
22 #include <asterisk/callerid.h>
23 #include <asterisk/module.h>
24 #include <asterisk/image.h>
25 #include <asterisk/tdd.h>
26 #include <asterisk/term.h>
27 #include <asterisk/manager.h>
28 #include <asterisk/pbx.h>
29 #include <asterisk/enum.h>
30 #include <asterisk/rtp.h>
31 #include <sys/resource.h>
32 #include <fcntl.h>
33 #include <stdio.h>
34 #include <signal.h>
35 #include <sched.h>
36 #include <asterisk/io.h>
37 #include <pthread.h>
38 #include <sys/socket.h>
39 #include <sys/un.h>
40 #include <sys/select.h>
41 #include <string.h>
42 #include <errno.h>
43 #include <ctype.h>
44 #include "editline/histedit.h"
45 #include "asterisk.h"
46 #include <asterisk/config.h>
47
48 #define AST_MAX_CONNECTS 128
49 #define NUM_MSGS 64
50
51 int option_verbose=0;
52 int option_debug=0;
53 int option_nofork=0;
54 int option_quiet=0;
55 int option_console=0;
56 int option_highpriority=0;
57 int option_remote=0;
58 int option_exec=0;
59 int option_initcrypto=0;
60 int option_nocolor;
61 int option_dumpcore = 0;
62 int option_overrideconfig = 0;
63 int fully_booted = 0;
64
65 static int ast_socket = -1;             /* UNIX Socket for allowing remote control */
66 static int ast_consock = -1;            /* UNIX Socket for controlling another asterisk */
67 static int mainpid;
68 struct console {
69         int fd;                                 /* File descriptor */
70         int p[2];                               /* Pipe */
71         pthread_t t;                    /* Thread of handler */
72 };
73
74 time_t ast_startuptime;
75 time_t ast_lastreloadtime;
76
77 static History *el_hist = NULL;
78 static EditLine *el = NULL;
79 static char *remotehostname;
80
81 struct console consoles[AST_MAX_CONNECTS];
82
83 char defaultlanguage[MAX_LANGUAGE] = DEFAULT_LANGUAGE;
84
85 static int ast_el_add_history(char *);
86 static int ast_el_read_history(char *);
87 static int ast_el_write_history(char *);
88
89 char ast_config_AST_CONFIG_DIR[AST_CONFIG_MAX_PATH];
90 char ast_config_AST_CONFIG_FILE[AST_CONFIG_MAX_PATH];
91 char ast_config_AST_MODULE_DIR[AST_CONFIG_MAX_PATH];
92 char ast_config_AST_SPOOL_DIR[AST_CONFIG_MAX_PATH];
93 char ast_config_AST_VAR_DIR[AST_CONFIG_MAX_PATH];
94 char ast_config_AST_LOG_DIR[AST_CONFIG_MAX_PATH];
95 char ast_config_AST_AGI_DIR[AST_CONFIG_MAX_PATH];
96 char ast_config_AST_DB[AST_CONFIG_MAX_PATH];
97 char ast_config_AST_KEY_DIR[AST_CONFIG_MAX_PATH];
98 char ast_config_AST_PID[AST_CONFIG_MAX_PATH];
99 char ast_config_AST_SOCKET[AST_CONFIG_MAX_PATH];
100 char ast_config_AST_RUN_DIR[AST_CONFIG_MAX_PATH];
101
102 static int fdprint(int fd, const char *s)
103 {
104         return write(fd, s, strlen(s) + 1);
105 }
106
107 static void network_verboser(const char *s, int pos, int replace, int complete)
108 {
109         int x;
110         for (x=0;x<AST_MAX_CONNECTS; x++) {
111                 if (consoles[x].fd > -1) 
112                         fdprint(consoles[x].p[1], s);
113         }
114 }
115
116 static pthread_t lthread;
117
118 static void *netconsole(void *vconsole)
119 {
120         struct console *con = vconsole;
121         char hostname[256];
122         char tmp[512];
123         int res;
124         int max;
125         fd_set rfds;
126         
127         if (gethostname(hostname, sizeof(hostname)))
128                 strncpy(hostname, "<Unknown>", sizeof(hostname)-1);
129         snprintf(tmp, sizeof(tmp), "%s/%d/%s\n", hostname, mainpid, ASTERISK_VERSION);
130         fdprint(con->fd, tmp);
131         for(;;) {
132                 FD_ZERO(&rfds); 
133                 FD_SET(con->fd, &rfds);
134                 FD_SET(con->p[0], &rfds);
135                 max = con->fd;
136                 if (con->p[0] > max)
137                         max = con->p[0];
138                 res = ast_select(max + 1, &rfds, NULL, NULL, NULL);
139                 if (res < 0) {
140                         ast_log(LOG_WARNING, "select returned < 0: %s\n", strerror(errno));
141                         continue;
142                 }
143                 if (FD_ISSET(con->fd, &rfds)) {
144                         res = read(con->fd, tmp, sizeof(tmp));
145                         if (res < 1) {
146                                 break;
147                         }
148                         tmp[res] = 0;
149                         ast_cli_command(con->fd, tmp);
150                 }
151                 if (FD_ISSET(con->p[0], &rfds)) {
152                         res = read(con->p[0], tmp, sizeof(tmp));
153                         if (res < 1) {
154                                 ast_log(LOG_ERROR, "read returned %d\n", res);
155                                 break;
156                         }
157                         res = write(con->fd, tmp, res);
158                         if (res < 1)
159                                 break;
160                 }
161         }
162         if (option_verbose > 2) 
163                 ast_verbose(VERBOSE_PREFIX_3 "Remote UNIX connection disconnected\n");
164         close(con->fd);
165         close(con->p[0]);
166         close(con->p[1]);
167         con->fd = -1;
168         
169         return NULL;
170 }
171
172 static void *listener(void *unused)
173 {
174         struct sockaddr_un sun;
175         int s;
176         int len;
177         int x;
178         int flags;
179         pthread_attr_t attr;
180         pthread_attr_init(&attr);
181         pthread_attr_setdetachstate(&attr, PTHREAD_CREATE_DETACHED);
182         for(;;) {
183                 if (ast_socket < 0)
184                         return NULL;
185                 len = sizeof(sun);
186                 s = accept(ast_socket, (struct sockaddr *)&sun, &len);
187                 if (s < 0) {
188                         ast_log(LOG_WARNING, "Accept retured %d: %s\n", s, strerror(errno));
189                 } else {
190                         for (x=0;x<AST_MAX_CONNECTS;x++) {
191                                 if (consoles[x].fd < 0) {
192                                         if (socketpair(AF_LOCAL, SOCK_STREAM, 0, consoles[x].p)) {
193                                                 ast_log(LOG_ERROR, "Unable to create pipe: %s\n", strerror(errno));
194                                                 consoles[x].fd = -1;
195                                                 fdprint(s, "Server failed to create pipe\n");
196                                                 close(s);
197                                                 break;
198                                         }
199                                         flags = fcntl(consoles[x].p[1], F_GETFL);
200                                         fcntl(consoles[x].p[1], F_SETFL, flags | O_NONBLOCK);
201                                         consoles[x].fd = s;
202                                         if (pthread_create(&consoles[x].t, &attr, netconsole, &consoles[x])) {
203                                                 ast_log(LOG_ERROR, "Unable to spawn thread to handle connection\n");
204                                                 consoles[x].fd = -1;
205                                                 fdprint(s, "Server failed to spawn thread\n");
206                                                 close(s);
207                                         }
208                                         break;
209                                 }
210                         }
211                         if (x >= AST_MAX_CONNECTS) {
212                                 fdprint(s, "No more connections allowed\n");
213                                 ast_log(LOG_WARNING, "No more connections allowed\n");
214                                 close(s);
215                         } else if (consoles[x].fd > -1) {
216                                 if (option_verbose > 2) 
217                                         ast_verbose(VERBOSE_PREFIX_3 "Remote UNIX connection\n");
218                         }
219                 }
220         }
221         return NULL;
222 }
223
224 static int ast_makesocket(void)
225 {
226         struct sockaddr_un sun;
227         int res;
228         int x;
229         for (x=0;x<AST_MAX_CONNECTS;x++)        
230                 consoles[x].fd = -1;
231         unlink((char *)ast_config_AST_SOCKET);
232         ast_socket = socket(PF_LOCAL, SOCK_STREAM, 0);
233         if (ast_socket < 0) {
234                 ast_log(LOG_WARNING, "Unable to create control socket: %s\n", strerror(errno));
235                 return -1;
236         }               
237         memset(&sun, 0, sizeof(sun));
238         sun.sun_family = AF_LOCAL;
239         strncpy(sun.sun_path, (char *)ast_config_AST_SOCKET, sizeof(sun.sun_path)-1);
240         res = bind(ast_socket, (struct sockaddr *)&sun, sizeof(sun));
241         if (res) {
242                 ast_log(LOG_WARNING, "Unable to bind socket to %s: %s\n", (char *)ast_config_AST_SOCKET, strerror(errno));
243                 close(ast_socket);
244                 ast_socket = -1;
245                 return -1;
246         }
247         res = listen(ast_socket, 2);
248         if (res < 0) {
249                 ast_log(LOG_WARNING, "Unable to listen on socket %s: %s\n", (char *)ast_config_AST_SOCKET, strerror(errno));
250                 close(ast_socket);
251                 ast_socket = -1;
252                 return -1;
253         }
254         ast_register_verbose(network_verboser);
255         pthread_create(&lthread, NULL, listener, NULL);
256         return 0;
257 }
258
259 static int ast_tryconnect(void)
260 {
261         struct sockaddr_un sun;
262         int res;
263         ast_consock = socket(PF_LOCAL, SOCK_STREAM, 0);
264         if (ast_consock < 0) {
265                 ast_log(LOG_WARNING, "Unable to create socket: %s\n", strerror(errno));
266                 return 0;
267         }
268         memset(&sun, 0, sizeof(sun));
269         sun.sun_family = AF_LOCAL;
270         strncpy(sun.sun_path, (char *)ast_config_AST_SOCKET, sizeof(sun.sun_path)-1);
271         res = connect(ast_consock, (struct sockaddr *)&sun, sizeof(sun));
272         if (res) {
273                 close(ast_consock);
274                 ast_consock = -1;
275                 return 0;
276         } else
277                 return 1;
278 }
279
280 static void urg_handler(int num)
281 {
282         /* Called by soft_hangup to interrupt the select, read, or other
283            system call.  We don't actually need to do anything though.  */
284         if (option_debug) 
285                 ast_log(LOG_DEBUG, "Urgent handler\n");
286         signal(num, urg_handler);
287         return;
288 }
289
290 static void hup_handler(int num)
291 {
292         if (option_verbose > 1) 
293                 ast_verbose(VERBOSE_PREFIX_2 "Received HUP signal -- Reloading configs\n");
294         ast_module_reload();
295 }
296
297
298 static void pipe_handler(int num)
299 {
300         /* Ignore sigpipe */
301 }
302 static void set_title(char *text)
303 {
304         /* Set an X-term or screen title */
305         if (getenv("TERM") && strstr(getenv("TERM"), "xterm"))
306                 fprintf(stdout, "\033]2;%s\007", text);
307 }
308
309 static void set_icon(char *text)
310 {
311         if (getenv("TERM") && strstr(getenv("TERM"), "xterm"))
312                 fprintf(stdout, "\033]1;%s\007", text);
313 }
314
315 static int set_priority(int pri)
316 {
317         struct sched_param sched;
318         memset(&sched, 0, sizeof(sched));
319         /* We set ourselves to a high priority, that we might pre-empt everything
320            else.  If your PBX has heavy activity on it, this is a good thing.  */
321 #ifdef __linux__
322         if (pri) {  
323                 sched.sched_priority = 10;
324                 if (sched_setscheduler(0, SCHED_RR, &sched)) {
325                         ast_log(LOG_WARNING, "Unable to set high priority\n");
326                         return -1;
327                 } else
328                         if (option_verbose)
329                                 ast_verbose("Set to realtime thread\n");
330         } else {
331                 sched.sched_priority = 0;
332                 if (sched_setscheduler(0, SCHED_OTHER, &sched)) {
333                         ast_log(LOG_WARNING, "Unable to set normal priority\n");
334                         return -1;
335                 }
336         }
337 #else
338         if (pri) {
339                 if (setpriority(PRIO_PROCESS, 0, -10) == -1) {
340                         ast_log(LOG_WARNING, "Unable to set high priority\n");
341                         return -1;
342                 } else
343                         if (option_verbose)
344                                 ast_verbose("Set to high priority\n");
345         } else {
346                 if (setpriority(PRIO_PROCESS, 0, 0) == -1) {
347                         ast_log(LOG_WARNING, "Unable to set normal priority\n");
348                         return -1;
349                 }
350         }
351 #endif
352         return 0;
353 }
354
355 static char *_argv[256];
356
357 static int shuttingdown = 0;
358
359 static void quit_handler(int num, int nice, int safeshutdown, int restart)
360 {
361         char filename[80] = "";
362         time_t s,e;
363         int x;
364         if (safeshutdown) {
365                 shuttingdown = 1;
366                 if (!nice) {
367                         /* Begin shutdown routine, hanging up active channels */
368                         ast_begin_shutdown(1);
369                         if (option_verbose && option_console)
370                                 ast_verbose("Beginning asterisk %s....\n", restart ? "restart" : "shutdown");
371                         time(&s);
372                         for(;;) {
373                                 time(&e);
374                                 /* Wait up to 15 seconds for all channels to go away */
375                                 if ((e - s) > 15)
376                                         break;
377                                 if (!ast_active_channels())
378                                         break;
379                                 if (!shuttingdown)
380                                         break;
381                                 /* Sleep 1/10 of a second */
382                                 usleep(100000);
383                         }
384                 } else {
385                         if (nice < 2)
386                                 ast_begin_shutdown(0);
387                         if (option_verbose && option_console)
388                                 ast_verbose("Waiting for inactivity to perform %s...\n", restart ? "restart" : "halt");
389                         for(;;) {
390                                 if (!ast_active_channels())
391                                         break;
392                                 if (!shuttingdown)
393                                         break;
394                                 sleep(1);
395                         }
396                 }
397
398                 if (!shuttingdown) {
399                         if (option_verbose && option_console)
400                                 ast_verbose("Asterisk %s cancelled.\n", restart ? "restart" : "shutdown");
401                         return;
402                 }
403         }
404         if (option_console || option_remote) {
405                 if (getenv("HOME")) 
406                         snprintf(filename, sizeof(filename), "%s/.asterisk_history", getenv("HOME"));
407                 if (strlen(filename))
408                         ast_el_write_history(filename);
409                 if (el != NULL)
410                         el_end(el);
411                 if (el_hist != NULL)
412                         history_end(el_hist);
413         }
414         /* Called on exit */
415         if (option_verbose && option_console)
416                 ast_verbose("Asterisk %s ending (%d).\n", ast_active_channels() ? "uncleanly" : "cleanly", num);
417         else if (option_debug)
418                 ast_log(LOG_DEBUG, "Asterisk ending (%d).\n", num);
419         manager_event(EVENT_FLAG_SYSTEM, "Shutdown", "Shutdown: %s\r\nRestart: %s\r\n", ast_active_channels() ? "Uncleanly" : "Cleanly", restart ? "True" : "False");
420         if (ast_socket > -1) {
421                 close(ast_socket);
422                 ast_socket = -1;
423         }
424         if (ast_consock > -1)
425                 close(ast_consock);
426         if (ast_socket > -1)
427                 unlink((char *)ast_config_AST_SOCKET);
428         unlink((char *)ast_config_AST_PID);
429         printf(term_quit());
430         if (restart) {
431                 if (option_verbose || option_console)
432                         ast_verbose("Preparing for Asterisk restart...\n");
433                 /* Mark all FD's for closing on exec */
434                 for (x=3;x<32768;x++) {
435                         fcntl(x, F_SETFD, FD_CLOEXEC);
436                 }
437                 if (option_verbose || option_console)
438                         ast_verbose("Restarting Asterisk NOW...\n");
439                 execvp(_argv[0], _argv);
440         } else
441                 exit(0);
442 }
443
444 static void __quit_handler(int num)
445 {
446         quit_handler(num, 0, 1, 0);
447 }
448
449 static pthread_t consolethread = -1;
450
451 static int fix_header(char *outbuf, int maxout, char **s, char *cmp)
452 {
453         if (!strncmp(*s, cmp, strlen(cmp))) {
454                 *s += strlen(cmp);
455                 term_color(outbuf, cmp, COLOR_GRAY, 0, maxout);
456                 return 1;
457         }
458         return 0;
459 }
460
461 static void console_verboser(const char *s, int pos, int replace, int complete)
462 {
463         char tmp[80];
464         /* Return to the beginning of the line */
465         if (!pos) {
466                 fprintf(stdout, "\r");
467                 if (fix_header(tmp, sizeof(tmp), &s, VERBOSE_PREFIX_4) ||
468                         fix_header(tmp, sizeof(tmp), &s, VERBOSE_PREFIX_3) ||
469                         fix_header(tmp, sizeof(tmp), &s, VERBOSE_PREFIX_2) ||
470                         fix_header(tmp, sizeof(tmp), &s, VERBOSE_PREFIX_1))
471                         fputs(tmp, stdout);
472         }
473         fputs(s + pos,stdout);
474         fflush(stdout);
475         if (complete)
476         /* Wake up a select()ing console */
477                 if (consolethread > -1)
478                         pthread_kill(consolethread, SIGURG);
479 }
480
481 static void consolehandler(char *s)
482 {
483         printf(term_end());
484         fflush(stdout);
485         /* Called when readline data is available */
486         if (s && strlen(s))
487                 ast_el_add_history(s);
488         /* Give the console access to the shell */
489         if (s) {
490                 if (s[0] == '!') {
491                         if (s[1])
492                                 system(s+1);
493                         else
494                                 system(getenv("SHELL") ? getenv("SHELL") : "/bin/sh");
495                 } else 
496                 ast_cli_command(STDOUT_FILENO, s);
497                 if (!strcasecmp(s, "help"))
498                         fprintf(stdout, "          !<command>   Executes a given shell command\n");
499         } else
500                 fprintf(stdout, "\nUse \"quit\" to exit\n");
501 }
502
503 static int remoteconsolehandler(char *s)
504 {
505         int ret = 0;
506         /* Called when readline data is available */
507         if (s && strlen(s))
508                 ast_el_add_history(s);
509         /* Give the console access to the shell */
510         if (s) {
511                 if (s[0] == '!') {
512                         if (s[1])
513                                 system(s+1);
514                         else
515                                 system(getenv("SHELL") ? getenv("SHELL") : "/bin/sh");
516                         ret = 1;
517                 }
518                 if (!strcasecmp(s, "help")) {
519                         fprintf(stdout, "          !<command>   Executes a given shell command\n");
520                         ret = 0;
521                 }
522                 if (!strcasecmp(s, "quit")) {
523                         quit_handler(0, 0, 0, 0);
524                         ret = 1;
525                 }
526                 if (!strcasecmp(s, "exit")) {
527                         quit_handler(0, 0, 0, 0);
528                         ret = 1;
529                 }
530         } else
531                 fprintf(stdout, "\nUse \"quit\" to exit\n");
532
533         return ret;
534 }
535
536 static char quit_help[] = 
537 "Usage: quit\n"
538 "       Exits Asterisk.\n";
539
540 static char abort_halt_help[] = 
541 "Usage: abort shutdown\n"
542 "       Causes Asterisk to abort an executing shutdown or restart, and resume normal\n"
543 "       call operations.\n";
544
545 static char shutdown_now_help[] = 
546 "Usage: stop now\n"
547 "       Shuts down a running Asterisk immediately, hanging up all active calls .\n";
548
549 static char shutdown_gracefully_help[] = 
550 "Usage: stop gracefully\n"
551 "       Causes Asterisk to not accept new calls, and exit when all\n"
552 "       active calls have terminated normally.\n";
553
554 static char shutdown_when_convenient_help[] = 
555 "Usage: stop when convenient\n"
556 "       Causes Asterisk to perform a shutdown when all active calls have ended.\n";
557
558 static char restart_now_help[] = 
559 "Usage: restart now\n"
560 "       Causes Asterisk to hangup all calls and exec() itself performing a cold.\n"
561 "       restart.\n";
562
563 static char restart_gracefully_help[] = 
564 "Usage: restart gracefully\n"
565 "       Causes Asterisk to stop accepting new calls and exec() itself performing a cold.\n"
566 "       restart when all active calls have ended.\n";
567
568 static char restart_when_convenient_help[] = 
569 "Usage: restart when convenient\n"
570 "       Causes Asterisk to perform a cold restart when all active calls have ended.\n";
571
572 #if 0
573 static int handle_quit(int fd, int argc, char *argv[])
574 {
575         if (argc != 1)
576                 return RESULT_SHOWUSAGE;
577         quit_handler(0, 0, 1, 0);
578         return RESULT_SUCCESS;
579 }
580 #endif
581
582 static int no_more_quit(int fd, int argc, char *argv[])
583 {
584         if (argc != 1)
585                 return RESULT_SHOWUSAGE;
586         ast_cli(fd, "The QUIT and EXIT commands may no longer be used to shutdown the PBX.\n"
587                     "Please use STOP NOW instead, if you wish to shutdown the PBX.\n");
588         return RESULT_SUCCESS;
589 }
590
591 static int handle_shutdown_now(int fd, int argc, char *argv[])
592 {
593         if (argc != 2)
594                 return RESULT_SHOWUSAGE;
595         quit_handler(0, 0 /* Not nice */, 1 /* safely */, 0 /* not restart */);
596         return RESULT_SUCCESS;
597 }
598
599 static int handle_shutdown_gracefully(int fd, int argc, char *argv[])
600 {
601         if (argc != 2)
602                 return RESULT_SHOWUSAGE;
603         quit_handler(0, 1 /* nicely */, 1 /* safely */, 0 /* no restart */);
604         return RESULT_SUCCESS;
605 }
606
607 static int handle_shutdown_when_convenient(int fd, int argc, char *argv[])
608 {
609         if (argc != 3)
610                 return RESULT_SHOWUSAGE;
611         quit_handler(0, 2 /* really nicely */, 1 /* safely */, 0 /* don't restart */);
612         return RESULT_SUCCESS;
613 }
614
615 static int handle_restart_now(int fd, int argc, char *argv[])
616 {
617         if (argc != 2)
618                 return RESULT_SHOWUSAGE;
619         quit_handler(0, 0 /* not nicely */, 1 /* safely */, 1 /* restart */);
620         return RESULT_SUCCESS;
621 }
622
623 static int handle_restart_gracefully(int fd, int argc, char *argv[])
624 {
625         if (argc != 2)
626                 return RESULT_SHOWUSAGE;
627         quit_handler(0, 1 /* nicely */, 1 /* safely */, 1 /* restart */);
628         return RESULT_SUCCESS;
629 }
630
631 static int handle_restart_when_convenient(int fd, int argc, char *argv[])
632 {
633         if (argc != 3)
634                 return RESULT_SHOWUSAGE;
635         quit_handler(0, 2 /* really nicely */, 1 /* safely */, 1 /* restart */);
636         return RESULT_SUCCESS;
637 }
638
639 static int handle_abort_halt(int fd, int argc, char *argv[])
640 {
641         if (argc != 2)
642                 return RESULT_SHOWUSAGE;
643         ast_cancel_shutdown();
644         shuttingdown = 0;
645         return RESULT_SUCCESS;
646 }
647
648 #define ASTERISK_PROMPT "*CLI> "
649
650 #define ASTERISK_PROMPT2 "%s*CLI> "
651
652 static struct ast_cli_entry aborthalt = { { "abort", "halt", NULL }, handle_abort_halt, "Cancel a running halt", abort_halt_help };
653
654 static struct ast_cli_entry quit =      { { "quit", NULL }, no_more_quit, "Exit Asterisk", quit_help };
655 static struct ast_cli_entry astexit =   { { "exit", NULL }, no_more_quit, "Exit Asterisk", quit_help };
656
657 static struct ast_cli_entry astshutdownnow =    { { "stop", "now", NULL }, handle_shutdown_now, "Shut down Asterisk imediately", shutdown_now_help };
658 static struct ast_cli_entry astshutdowngracefully =     { { "stop", "gracefully", NULL }, handle_shutdown_gracefully, "Gracefully shut down Asterisk", shutdown_gracefully_help };
659 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 };
660 static struct ast_cli_entry astrestartnow =     { { "restart", "now", NULL }, handle_restart_now, "Restart Asterisk immediately", restart_now_help };
661 static struct ast_cli_entry astrestartgracefully =      { { "restart", "gracefully", NULL }, handle_restart_gracefully, "Restart Asterisk gracefully", restart_gracefully_help };
662 static struct ast_cli_entry astrestartwhenconvenient=   { { "restart", "when", "convenient", NULL }, handle_restart_when_convenient, "Restart Asterisk at empty call volume", restart_when_convenient_help };
663
664 static int ast_el_read_char(EditLine *el, char *cp)
665 {
666         int num_read=0;
667         int lastpos=0;
668         fd_set rfds;
669         int res;
670         int max;
671         char buf[512];
672
673         for (;;) {
674                 FD_ZERO(&rfds);
675                 FD_SET(ast_consock, &rfds);
676                 FD_SET(STDIN_FILENO, &rfds);
677                 max = ast_consock;
678                 if (STDIN_FILENO > max)
679                         max = STDIN_FILENO;
680                 res = ast_select(max+1, &rfds, NULL, NULL, NULL);
681                 if (res < 0) {
682                         if (errno == EINTR)
683                                 continue;
684                         ast_log(LOG_ERROR, "select failed: %s\n", strerror(errno));
685                         break;
686                 }
687
688                 if (FD_ISSET(STDIN_FILENO, &rfds)) {
689                         num_read = read(STDIN_FILENO, cp, 1);
690                         if (num_read < 1) {
691                                 break;
692                         } else 
693                                 return (num_read);
694                 }
695                 if (FD_ISSET(ast_consock, &rfds)) {
696                         res = read(ast_consock, buf, sizeof(buf) - 1);
697                         /* if the remote side disappears exit */
698                         if (res < 1) {
699                                 fprintf(stderr, "\nDisconnected from Asterisk server\n");
700                                 quit_handler(0, 0, 0, 0);
701                         }
702
703                         buf[res] = '\0';
704
705                         if (!lastpos)
706                                 write(STDOUT_FILENO, "\r", 1);
707                         write(STDOUT_FILENO, buf, res);
708                         if ((buf[res-1] == '\n') || (buf[res-2] == '\n')) {
709                                 *cp = CC_REFRESH;
710                                 return(1);
711                         } else {
712                                 lastpos = 1;
713                         }
714                 }
715         }
716
717         *cp = '\0';
718         return (0);
719 }
720
721 static char *cli_prompt(EditLine *el)
722 {
723         static char prompt[80];
724
725         if (remotehostname)
726                 snprintf(prompt, sizeof(prompt), ASTERISK_PROMPT2, remotehostname);
727         else
728                 snprintf(prompt, sizeof(prompt), ASTERISK_PROMPT);
729
730         return(prompt); 
731 }
732
733 static char **ast_el_strtoarr(char *buf)
734 {
735         char **match_list = NULL, *retstr;
736         size_t match_list_len;
737         int matches = 0;
738
739         match_list_len = 1;
740         while ( (retstr = strsep(&buf, " ")) != NULL) {
741
742                 if (matches + 1 >= match_list_len) {
743                         match_list_len <<= 1;
744                         match_list = realloc(match_list, match_list_len * sizeof(char *));
745                 }
746
747                 match_list[matches++] = retstr;
748         }
749
750         if (!match_list)
751                 return (char **) NULL;
752
753         if (matches>= match_list_len)
754                 match_list = realloc(match_list, (match_list_len + 1) * sizeof(char *));
755
756         match_list[matches] = (char *) NULL;
757
758         return match_list;
759 }
760
761 static int ast_el_sort_compare(const void *i1, const void *i2)
762 {
763         char *s1, *s2;
764
765         s1 = ((char **)i1)[0];
766         s2 = ((char **)i2)[0];
767
768         return strcasecmp(s1, s2);
769 }
770
771 static int ast_cli_display_match_list(char **matches, int len, int max)
772 {
773         int i, idx, limit, count;
774         int screenwidth = 0;
775         int numoutput = 0, numoutputline = 0;
776
777         screenwidth = ast_get_termcols(STDOUT_FILENO);
778
779         /* find out how many entries can be put on one line, with two spaces between strings */
780         limit = screenwidth / (max + 2);
781         if (limit == 0)
782                 limit = 1;
783
784         /* how many lines of output */
785         count = len / limit;
786         if (count * limit < len)
787                 count++;
788
789         idx = 1;
790
791         qsort(&matches[0], (size_t)(len + 1), sizeof(char *), ast_el_sort_compare);
792
793         for (; count > 0; count--) {
794                 numoutputline = 0;
795                 for (i=0; i < limit && matches[idx]; i++, idx++) {
796
797                         /* Don't print dupes */
798                         if ( (matches[idx+1] != NULL && strcmp(matches[idx], matches[idx+1]) == 0 ) ) {
799                                 i--;
800                                 continue;
801                         }
802
803                         numoutput++;  numoutputline++;
804                         fprintf(stdout, "%-*s  ", max, matches[idx]);
805                 }
806                 if (numoutputline > 0)
807                         fprintf(stdout, "\n");
808         }
809
810         return numoutput;
811 }
812
813
814 static char *cli_complete(EditLine *el, int ch)
815 {
816         int len=0;
817         char *ptr;
818         int nummatches = 0;
819         char **matches;
820         int retval = CC_ERROR;
821         char buf[1024];
822         int res;
823
824         LineInfo *lf = (LineInfo *)el_line(el);
825
826         *lf->cursor = '\0';
827         ptr = (char *)lf->cursor;
828         if (ptr) {
829                 while (ptr > lf->buffer) {
830                         if (isspace(*ptr)) {
831                                 ptr++;
832                                 break;
833                         }
834                         ptr--;
835                 }
836         }
837
838         len = lf->cursor - ptr;
839
840         if (option_remote) {
841                 snprintf(buf, sizeof(buf),"_COMMAND NUMMATCHES \"%s\" \"%s\"", lf->buffer, ptr); 
842                 fdprint(ast_consock, buf);
843                 res = read(ast_consock, buf, sizeof(buf));
844                 buf[res] = '\0';
845                 nummatches = atoi(buf);
846
847                 if (nummatches > 0) {
848                         snprintf(buf, sizeof(buf),"_COMMAND MATCHESARRAY \"%s\" \"%s\"", lf->buffer, ptr); 
849                         fdprint(ast_consock, buf);
850                         res = read(ast_consock, buf, sizeof(buf));
851                         buf[res] = '\0';
852
853                         matches = ast_el_strtoarr(buf);
854                 } else
855                         matches = (char **) NULL;
856
857
858         }  else {
859
860                 nummatches = ast_cli_generatornummatches((char *)lf->buffer,ptr);
861                 matches = ast_cli_completion_matches((char *)lf->buffer,ptr);
862         }
863
864         if (matches) {
865                 int i;
866                 int matches_num, maxlen, match_len;
867
868                 if (matches[0][0] != '\0') {
869                         el_deletestr(el, (int) len);
870                         el_insertstr(el, matches[0]);
871                         retval = CC_REFRESH;
872                 }
873
874                 if (nummatches == 1) {
875                         /* Found an exact match */
876                         el_insertstr(el, " ");
877                         retval = CC_REFRESH;
878                 } else {
879                         /* Must be more than one match */
880                         for (i=1, maxlen=0; matches[i]; i++) {
881                                 match_len = strlen(matches[i]);
882                                 if (match_len > maxlen)
883                                         maxlen = match_len;
884                         }
885                         matches_num = i - 1;
886                         if (matches_num >1) {
887                                 fprintf(stdout, "\n");
888                                 ast_cli_display_match_list(matches, nummatches, maxlen);
889                                 retval = CC_REDISPLAY;
890                         } else { 
891                                 el_insertstr(el," ");
892                                 retval = CC_REFRESH;
893                         }
894                 }
895         free(matches);
896         }
897
898         return (char *)retval;
899 }
900
901 static int ast_el_initialize(void)
902 {
903         HistEvent ev;
904
905         if (el != NULL)
906                 el_end(el);
907         if (el_hist != NULL)
908                 history_end(el_hist);
909
910         el = el_init("asterisk", stdin, stdout, stderr);
911         el_set(el, EL_PROMPT, cli_prompt);
912
913         el_set(el, EL_EDITMODE, 1);             
914         el_set(el, EL_EDITOR, "emacs");         
915         el_hist = history_init();
916         if (!el || !el_hist)
917                 return -1;
918
919         /* setup history with 100 entries */
920         history(el_hist, &ev, H_SETSIZE, 100);
921
922         el_set(el, EL_HIST, history, el_hist);
923
924         el_set(el, EL_ADDFN, "ed-complete", "Complete argument", cli_complete);
925         /* Bind <tab> to command completion */
926         el_set(el, EL_BIND, "^I", "ed-complete", NULL);
927         /* Bind ? to command completion */
928         el_set(el, EL_BIND, "?", "ed-complete", NULL);
929
930         return 0;
931 }
932
933 static int ast_el_add_history(char *buf)
934 {
935         HistEvent ev;
936
937         if (el_hist == NULL || el == NULL)
938                 ast_el_initialize();
939
940         return (history(el_hist, &ev, H_ENTER, buf));
941 }
942
943 static int ast_el_write_history(char *filename)
944 {
945         HistEvent ev;
946
947         if (el_hist == NULL || el == NULL)
948                 ast_el_initialize();
949
950         return (history(el_hist, &ev, H_SAVE, filename));
951 }
952
953 static int ast_el_read_history(char *filename)
954 {
955         char buf[256];
956         FILE *f;
957         int ret = -1;
958
959         if (el_hist == NULL || el == NULL)
960                 ast_el_initialize();
961
962         if ((f = fopen(filename, "r")) == NULL)
963                 return ret;
964
965         while (!feof(f)) {
966                 fgets(buf, sizeof(buf), f);
967                 if (!strcmp(buf, "_HiStOrY_V2_\n"))
968                         continue;
969                 if ((ret = ast_el_add_history(buf)) == -1)
970                         break;
971         }
972         fclose(f);
973
974         return ret;
975 }
976
977 static void ast_remotecontrol(char * data)
978 {
979         char buf[80];
980         int res;
981         char filename[80] = "";
982         char *hostname;
983         char *cpid;
984         char *version;
985         int pid;
986         char tmp[80];
987         char *stringp=NULL;
988
989         char *ebuf;
990         int num = 0;
991
992         read(ast_consock, buf, sizeof(buf));
993         if (data)
994                 write(ast_consock, data, strlen(data) + 1);
995         stringp=buf;
996         hostname = strsep(&stringp, "/");
997         cpid = strsep(&stringp, "/");
998         version = strsep(&stringp, "/");
999         if (!version)
1000                 version = "<Version Unknown>";
1001         stringp=hostname;
1002         strsep(&stringp, ".");
1003         if (cpid)
1004                 pid = atoi(cpid);
1005         else
1006                 pid = -1;
1007         snprintf(tmp, sizeof(tmp), "set verbose atleast %d", option_verbose);
1008         fdprint(ast_consock, tmp);
1009         ast_verbose("Connected to Asterisk %s currently running on %s (pid = %d)\n", version, hostname, pid);
1010         remotehostname = hostname;
1011         if (getenv("HOME")) 
1012                 snprintf(filename, sizeof(filename), "%s/.asterisk_history", getenv("HOME"));
1013         if (el_hist == NULL || el == NULL)
1014                 ast_el_initialize();
1015
1016         el_set(el, EL_GETCFN, ast_el_read_char);
1017
1018         if (strlen(filename))
1019                 ast_el_read_history(filename);
1020
1021         ast_cli_register(&quit);
1022         ast_cli_register(&astexit);
1023 #if 0
1024         ast_cli_register(&astshutdown);
1025 #endif  
1026         for(;;) {
1027                 ebuf = (char *)el_gets(el, &num);
1028
1029                 if (data)       /* hack to print output then exit if asterisk -rx is used */
1030                         ebuf = strdup("quit");
1031
1032                 if (ebuf && strlen(ebuf)) {
1033                         if (ebuf[strlen(ebuf)-1] == '\n')
1034                                 ebuf[strlen(ebuf)-1] = '\0';
1035                         if (!remoteconsolehandler(ebuf)) {
1036                                 res = write(ast_consock, ebuf, strlen(ebuf) + 1);
1037                                 if (res < 1) {
1038                                         ast_log(LOG_WARNING, "Unable to write: %s\n", strerror(errno));
1039                                         break;
1040                                 }
1041                         }
1042                 }
1043         }
1044         printf("\nDisconnected from Asterisk server\n");
1045 }
1046
1047 static int show_cli_help(void) {
1048         printf("Asterisk " ASTERISK_VERSION ", Copyright (C) 2000-2002, Digium.\n");
1049         printf("Usage: asterisk [OPTIONS]\n");
1050         printf("Valid Options:\n");
1051         printf("   -h           This help screen\n");
1052         printf("   -r           Connect to Asterisk on this machine\n");
1053         printf("   -f           Do not fork\n");
1054         printf("   -n           Disable console colorization\n");
1055         printf("   -p           Run as pseudo-realtime thread\n");
1056         printf("   -v           Increase verbosity (multiple v's = more verbose)\n");
1057         printf("   -q           Quiet mode (supress output)\n");
1058         printf("   -g           Dump core in case of a crash\n");
1059         printf("   -x <cmd>     Execute command <cmd> (only valid with -r)\n");
1060         printf("   -i           Initializie crypto keys at startup\n");
1061         printf("   -c           Provide console CLI\n");
1062         printf("   -d           Enable extra debugging\n");
1063         printf("\n");
1064         return 0;
1065 }
1066
1067 static void ast_readconfig(void) {
1068         struct ast_config *cfg;
1069         struct ast_variable *v;
1070         char *config = ASTCONFPATH;
1071
1072         if (option_overrideconfig == 1) {
1073             cfg = ast_load((char *)ast_config_AST_CONFIG_FILE);
1074         } else {
1075             cfg = ast_load(config);
1076         }
1077
1078         /* init with buildtime config */
1079         strncpy((char *)ast_config_AST_CONFIG_DIR,AST_CONFIG_DIR,sizeof(ast_config_AST_CONFIG_DIR)-1);
1080         strncpy((char *)ast_config_AST_SPOOL_DIR,AST_SPOOL_DIR,sizeof(ast_config_AST_SPOOL_DIR)-1);
1081         strncpy((char *)ast_config_AST_MODULE_DIR,AST_MODULE_DIR,sizeof(ast_config_AST_VAR_DIR)-1);
1082         strncpy((char *)ast_config_AST_VAR_DIR,AST_VAR_DIR,sizeof(ast_config_AST_VAR_DIR)-1);
1083         strncpy((char *)ast_config_AST_LOG_DIR,AST_LOG_DIR,sizeof(ast_config_AST_LOG_DIR)-1);
1084         strncpy((char *)ast_config_AST_AGI_DIR,AST_AGI_DIR,sizeof(ast_config_AST_AGI_DIR)-1);
1085         strncpy((char *)ast_config_AST_DB,AST_DB,sizeof(ast_config_AST_DB)-1);
1086         strncpy((char *)ast_config_AST_KEY_DIR,AST_KEY_DIR,sizeof(ast_config_AST_KEY_DIR)-1);
1087         strncpy((char *)ast_config_AST_PID,AST_PID,sizeof(ast_config_AST_PID)-1);
1088         strncpy((char *)ast_config_AST_SOCKET,AST_SOCKET,sizeof(ast_config_AST_SOCKET)-1);
1089         strncpy((char *)ast_config_AST_RUN_DIR,AST_RUN_DIR,sizeof(ast_config_AST_RUN_DIR)-1);
1090         
1091         /* no asterisk.conf? no problem, use buildtime config! */
1092         if (!cfg) {
1093             return;
1094         }
1095         v = ast_variable_browse(cfg, "directories");
1096         while(v) {
1097                 if (!strcasecmp(v->name, "astetcdir")) {
1098                     strncpy((char *)ast_config_AST_CONFIG_DIR,v->value,sizeof(ast_config_AST_CONFIG_DIR)-1);
1099                 } else if (!strcasecmp(v->name, "astspooldir")) {
1100                     strncpy((char *)ast_config_AST_SPOOL_DIR,v->value,sizeof(ast_config_AST_SPOOL_DIR)-1);
1101                 } else if (!strcasecmp(v->name, "astvarlibdir")) {
1102                     strncpy((char *)ast_config_AST_VAR_DIR,v->value,sizeof(ast_config_AST_VAR_DIR)-1);
1103                     snprintf((char *)ast_config_AST_DB,sizeof(ast_config_AST_DB)-1,"%s/%s",v->value,"astdb");    
1104                 } else if (!strcasecmp(v->name, "astlogdir")) {
1105                     strncpy((char *)ast_config_AST_LOG_DIR,v->value,sizeof(ast_config_AST_LOG_DIR)-1);
1106                 } else if (!strcasecmp(v->name, "astagidir")) {
1107                     strncpy((char *)ast_config_AST_AGI_DIR,v->value,sizeof(ast_config_AST_AGI_DIR)-1);
1108                 } else if (!strcasecmp(v->name, "astrundir")) {
1109                     snprintf((char *)ast_config_AST_PID,sizeof(ast_config_AST_PID)-1,"%s/%s",v->value,"asterisk.pid");    
1110                     snprintf((char *)ast_config_AST_SOCKET,sizeof(ast_config_AST_SOCKET)-1,"%s/%s",v->value,"asterisk.ctl");    
1111                     strncpy((char *)ast_config_AST_RUN_DIR,v->value,sizeof(ast_config_AST_RUN_DIR)-1);
1112                 } else if (!strcasecmp(v->name, "astmoddir")) {
1113                     strncpy((char *)ast_config_AST_MODULE_DIR,v->value,sizeof(ast_config_AST_MODULE_DIR)-1);
1114                 }
1115                 v = v->next;
1116         }
1117         ast_destroy(cfg);
1118 }
1119
1120 int main(int argc, char *argv[])
1121 {
1122         char c;
1123         char filename[80] = "";
1124         char hostname[256];
1125         char tmp[80];
1126         char * xarg = NULL;
1127         int x;
1128         FILE *f;
1129         sigset_t sigs;
1130         int num;
1131         char *buf;
1132
1133         /* Remember original args for restart */
1134         if (argc > sizeof(_argv) / sizeof(_argv[0]) - 1) {
1135                 fprintf(stderr, "Truncating argument size to %d\n", sizeof(_argv) / sizeof(_argv[0]) - 1);
1136                 argc = sizeof(_argv) / sizeof(_argv[0]) - 1;
1137         }
1138         for (x=0;x<argc;x++)
1139                 _argv[x] = argv[x];
1140         _argv[x] = NULL;
1141
1142         if (gethostname(hostname, sizeof(hostname)))
1143                 strncpy(hostname, "<Unknown>", sizeof(hostname)-1);
1144         mainpid = getpid();
1145         ast_ulaw_init();
1146         ast_alaw_init();
1147         callerid_init();
1148         tdd_init();
1149         if (getenv("HOME")) 
1150                 snprintf(filename, sizeof(filename), "%s/.asterisk_history", getenv("HOME"));
1151         /* Check if we're root */
1152         /*
1153         if (geteuid()) {
1154                 ast_log(LOG_ERROR, "Must be run as root\n");
1155                 exit(1);
1156         }
1157         */
1158         /* Check for options */
1159         while((c=getopt(argc, argv, "hfdvqprgcinx:C:")) != EOF) {
1160                 switch(c) {
1161                 case 'd':
1162                         option_debug++;
1163                         option_nofork++;
1164                         break;
1165                 case 'c':
1166                         option_console++;
1167                         option_nofork++;
1168                         break;
1169                 case 'f':
1170                         option_nofork++;
1171                         break;
1172                 case 'n':
1173                         option_nocolor++;
1174                         break;
1175                 case 'r':
1176                         option_remote++;
1177                         option_nofork++;
1178                         break;
1179                 case 'p':
1180                         option_highpriority++;
1181                         break;
1182                 case 'v':
1183                         option_verbose++;
1184                         option_nofork++;
1185                         break;
1186                 case 'q':
1187                         option_quiet++;
1188                         break;
1189                 case 'x':
1190                         option_exec++;
1191                         xarg = optarg;
1192                         break;
1193                 case 'C':
1194                         strncpy((char *)ast_config_AST_CONFIG_FILE,optarg,sizeof(ast_config_AST_CONFIG_FILE));
1195                         option_overrideconfig++;
1196                         break;
1197                 case 'i':
1198                         option_initcrypto++;
1199                         break;
1200                 case'g':
1201                         option_dumpcore++;
1202                         break;
1203                 case 'h':
1204                         show_cli_help();
1205                         exit(0);
1206                 case '?':
1207                         exit(1);
1208                 }
1209         }
1210
1211         if (option_dumpcore) {
1212                 struct rlimit l;
1213                 memset(&l, 0, sizeof(l));
1214                 l.rlim_cur = RLIM_INFINITY;
1215                 l.rlim_max = RLIM_INFINITY;
1216                 if (setrlimit(RLIMIT_CORE, &l)) {
1217                         ast_log(LOG_WARNING, "Unable to disable core size resource limit: %s\n", strerror(errno));
1218                 }
1219         }
1220
1221         term_init();
1222         printf(term_end());
1223         fflush(stdout);
1224         if (option_console && !option_verbose) 
1225                 ast_verbose("[ Reading Master Configuration ]");
1226         ast_readconfig();
1227
1228         if (option_console) {
1229                 if (el_hist == NULL || el == NULL)
1230                         ast_el_initialize();
1231
1232                 if (strlen(filename))
1233                         ast_el_read_history(filename);
1234         }
1235
1236         if (ast_tryconnect()) {
1237                 /* One is already running */
1238                 if (option_remote) {
1239                         if (option_exec) {
1240                                 ast_remotecontrol(xarg);
1241                                 quit_handler(0, 0, 0, 0);
1242                                 exit(0);
1243                         }
1244                         printf(term_quit());
1245                         ast_register_verbose(console_verboser);
1246                         ast_verbose( "Asterisk " ASTERISK_VERSION ", Copyright (C) 1999-2001 Linux Support Services, Inc.\n");
1247                         ast_verbose( "Written by Mark Spencer <markster@linux-support.net>\n");
1248                         ast_verbose( "=========================================================================\n");
1249                         ast_remotecontrol(NULL);
1250                         quit_handler(0, 0, 0, 0);
1251                         exit(0);
1252                 } else {
1253                         ast_log(LOG_ERROR, "Asterisk already running on %s.  Use 'asterisk -r' to connect.\n", (char *)ast_config_AST_SOCKET);
1254                         printf(term_quit());
1255                         exit(1);
1256                 }
1257         } else if (option_remote || option_exec) {
1258                 ast_log(LOG_ERROR, "Unable to connect to remote asterisk\n");
1259                 printf(term_quit());
1260                 exit(1);
1261         }
1262         /* Blindly write pid file since we couldn't connect */
1263         unlink((char *)ast_config_AST_PID);
1264         f = fopen((char *)ast_config_AST_PID, "w");
1265         if (f) {
1266                 fprintf(f, "%d\n", getpid());
1267                 fclose(f);
1268         } else
1269                 ast_log(LOG_WARNING, "Unable to open pid file '%s': %s\n", (char *)ast_config_AST_PID, strerror(errno));
1270
1271         if (!option_verbose && !option_debug && !option_nofork && !option_console) {
1272 #if 1
1273                 daemon(0,0);
1274 #else   
1275                 pid = fork();
1276                 if (pid < 0) {
1277                         ast_log(LOG_ERROR, "Unable to fork(): %s\n", strerror(errno));
1278                         printf(term_quit());
1279                         exit(1);
1280                 }
1281                 if (pid) 
1282                         exit(0);
1283 #endif                  
1284         }
1285
1286         ast_makesocket();
1287         sigemptyset(&sigs);
1288         sigaddset(&sigs, SIGHUP);
1289         sigaddset(&sigs, SIGTERM);
1290         sigaddset(&sigs, SIGINT);
1291         sigaddset(&sigs, SIGPIPE);
1292         sigaddset(&sigs, SIGWINCH);
1293         pthread_sigmask(SIG_BLOCK, &sigs, NULL);
1294         if (option_console || option_verbose || option_remote)
1295                 ast_register_verbose(console_verboser);
1296         /* Print a welcome message if desired */
1297         if (option_verbose || option_console) {
1298                 ast_verbose( "Asterisk " ASTERISK_VERSION ", Copyright (C) 1999-2001 Linux Support Services, Inc.\n");
1299                 ast_verbose( "Written by Mark Spencer <markster@linux-support.net>\n");
1300                 ast_verbose( "=========================================================================\n");
1301         }
1302         if (option_console && !option_verbose) 
1303                 ast_verbose("[ Booting...");
1304         signal(SIGURG, urg_handler);
1305         signal(SIGINT, __quit_handler);
1306         signal(SIGTERM, __quit_handler);
1307         signal(SIGHUP, hup_handler);
1308         signal(SIGPIPE, pipe_handler);
1309         if (set_priority(option_highpriority)) {
1310                 printf(term_quit());
1311                 exit(1);
1312         }
1313         if (init_logger()) {
1314                 printf(term_quit());
1315                 exit(1);
1316         }
1317         if (init_manager()) {
1318                 printf(term_quit());
1319                 exit(1);
1320         }
1321         ast_rtp_init();
1322         if (ast_image_init()) {
1323                 printf(term_quit());
1324                 exit(1);
1325         }
1326         if (load_pbx()) {
1327                 printf(term_quit());
1328                 exit(1);
1329         }
1330         if (load_modules()) {
1331                 printf(term_quit());
1332                 exit(1);
1333         }
1334         if (init_framer()) {
1335                 printf(term_quit());
1336                 exit(1);
1337         }
1338         if (astdb_init()) {
1339                 printf(term_quit());
1340                 exit(1);
1341         }
1342         if (ast_enum_init()) {
1343                 printf(term_quit());
1344                 exit(1);
1345         }
1346         /* We might have the option of showing a console, but for now just
1347            do nothing... */
1348         if (option_console && !option_verbose)
1349                 ast_verbose(" ]\n");
1350         if (option_verbose || option_console)
1351                 ast_verbose(term_color(tmp, "Asterisk Ready.\n", COLOR_BRWHITE, COLOR_BLACK, sizeof(tmp)));
1352         fully_booted = 1;
1353         pthread_sigmask(SIG_UNBLOCK, &sigs, NULL);
1354 #ifdef __AST_DEBUG_MALLOC
1355         __ast_mm_init();
1356 #endif  
1357         time(&ast_startuptime);
1358         ast_cli_register(&astshutdownnow);
1359         ast_cli_register(&astshutdowngracefully);
1360         ast_cli_register(&astrestartnow);
1361         ast_cli_register(&astrestartgracefully);
1362         ast_cli_register(&astrestartwhenconvenient);
1363         ast_cli_register(&astshutdownwhenconvenient);
1364         ast_cli_register(&aborthalt);
1365         if (option_console) {
1366                 /* Console stuff now... */
1367                 /* Register our quit function */
1368                 char title[256];
1369                 set_icon("Asterisk");
1370                 snprintf(title, sizeof(title), "Asterisk Console on '%s' (pid %d)", hostname, mainpid);
1371                 set_title(title);
1372             ast_cli_register(&quit);
1373             ast_cli_register(&astexit);
1374                 consolethread = pthread_self();
1375
1376                 for (;;) {
1377                         buf = (char *)el_gets(el, &num);
1378                         if (buf) {
1379                                 if (buf[strlen(buf)-1] == '\n')
1380                                         buf[strlen(buf)-1] = '\0';
1381
1382                                 consolehandler((char *)buf);
1383                         } else
1384                                 ast_cli(STDOUT_FILENO, "\nUse EXIT or QUIT to exist, or STOP NOW to shutdown Asterisk\n");
1385                 }
1386
1387         } else {
1388                 /* Do nothing */
1389                 ast_select(0,NULL,NULL,NULL,NULL);
1390         }
1391         return 0;
1392 }