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