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