Version 0.1.3 from FTP
[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 <stdio.h>
21 #include <signal.h>
22 #include <sched.h>
23 #include <pthread.h>
24 #include <readline/readline.h>
25 #include <readline/history.h>
26 #include "asterisk.h"
27
28 int option_verbose=0;
29 int option_debug=0;
30 int option_nofork=0;
31 int option_quiet=0;
32 int option_console=0;
33 int option_highpriority=0;
34 int fully_booted = 0;
35
36 char defaultlanguage[MAX_LANGUAGE] = DEFAULT_LANGUAGE;
37
38 #define HIGH_PRIORITY 1
39 #define HIGH_PRIORITY_SCHED SCHED_RR
40
41 static void urg_handler(int num)
42 {
43         /* Called by soft_hangup to interrupt the select, read, or other
44            system call.  We don't actually need to do anything though.  */
45         if (option_debug)
46                 ast_log(LOG_DEBUG, "Urgent handler\n");
47         signal(num, urg_handler);
48         return;
49 }
50
51 static int set_priority(int pri)
52 {
53         struct sched_param sched;
54         /* We set ourselves to a high priority, that we might pre-empt everything
55            else.  If your PBX has heavy activity on it, this is a good thing.  */
56         if (pri) {  
57                 sched.sched_priority = HIGH_PRIORITY;
58                 if (sched_setscheduler(0, HIGH_PRIORITY_SCHED, &sched)) {
59                         ast_log(LOG_WARNING, "Unable to set high priority\n");
60                         return -1;
61                 }
62         } else {
63                 sched.sched_priority = 0;
64                 if (sched_setscheduler(0, SCHED_OTHER, &sched)) {
65                         ast_log(LOG_WARNING, "Unable to set normal priority\n");
66                         return -1;
67                 }
68         }
69         return 0;
70 }
71
72 static void quit_handler(int num)
73 {
74         static pthread_mutex_t quitlock = PTHREAD_MUTEX_INITIALIZER;
75         char filename[80] = "";
76         if (getenv("HOME")) 
77                 snprintf(filename, sizeof(filename), "%s/.asterisk_history", getenv("HOME"));
78         /* Quit only once */
79         pthread_mutex_lock(&quitlock);
80         /* Called on exit */
81         if (option_verbose)
82                 ast_verbose("Asterisk ending (%d).\n", num);
83         else if (option_debug)
84                 ast_log(LOG_DEBUG, "Asterisk ending (%d).\n", num);
85         if (strlen(filename))
86                 write_history(filename);
87         exit(0);
88 }
89
90 static pthread_t consolethread = -1;
91
92 static void console_verboser(char *s, int pos, int replace, int complete)
93 {
94         /* Return to the beginning of the line */
95         if (!pos)
96                 fprintf(stdout, "\r");
97         fprintf(stdout, s + pos);
98         fflush(stdout);
99         if (complete)
100         /* Wake up a select()ing console */
101                 pthread_kill(consolethread, SIGURG);
102 }
103
104 static void consolehandler(char *s)
105 {
106         /* Called when readline data is available */
107         if (s && strlen(s))
108                 add_history(s);
109         /* Give the console access to the shell */
110         if (s) {
111                 if (s[0] == '!') {
112                         if (s[1])
113                                 system(s+1);
114                         else
115                                 system(getenv("SHELL") ? getenv("SHELL") : "/bin/sh");
116                 } else 
117                 ast_cli_command(STDOUT_FILENO, s);
118                 if (!strcasecmp(s, "help"))
119                         fprintf(stdout, "          !<command>   Executes a given shell command\n");
120         } else
121                 fprintf(stdout, "\nUse \"quit\" to exit\n");
122 }
123
124 static char quit_help[] = 
125 "Usage: quit\n"
126 "       Exits Asterisk.\n";
127
128 static int handle_quit(int fd, int argc, char *argv[])
129 {
130         if (argc != 1)
131                 return RESULT_SHOWUSAGE;
132         quit_handler(0);
133         return RESULT_SUCCESS;
134 }
135
136 #define ASTERISK_PROMPT "*CLI> "
137
138 static struct ast_cli_entry quit =      { { "quit", NULL }, handle_quit, "Exit Asterisk", quit_help };
139
140 static char *cli_generator(char *text, int state)
141 {
142         return ast_cli_generator(rl_line_buffer, text, state);
143 }
144
145 int main(int argc, char *argv[])
146 {
147         char c;
148         fd_set rfds;
149         int res;
150         char filename[80] = "";
151         if (getenv("HOME")) 
152                 snprintf(filename, sizeof(filename), "%s/.asterisk_history", getenv("HOME"));
153         /* Check if we're root */
154         if (geteuid()) {
155                 ast_log(LOG_ERROR, "Must be run as root\n");
156                 exit(1);
157         }
158         /* Check for options */
159         while((c=getopt(argc, argv, "dvqpc")) != EOF) {
160                 switch(c) {
161                 case 'd':
162                         option_debug++;
163                         option_nofork++;
164                         break;
165                 case 'c':
166                         option_console++;
167                         option_nofork++;
168                 case 'p':
169                         option_highpriority++;
170                         break;
171                 case 'v':
172                         option_verbose++;
173                         option_nofork++;
174                         break;
175                 case 'q':
176                         option_quiet++;
177                         break;
178                 case '?':
179                         exit(1);
180                 }
181         }
182         ast_register_verbose(console_verboser);
183         /* Print a welcome message if desired */
184         if (option_verbose || option_console) {
185                 ast_verbose( "Asterisk, Copyright (C) 1999 Mark Spencer\n");
186                 ast_verbose( "Written by Mark Spencer <markster@linux-support.net>\n");
187                 ast_verbose( "=========================================================================\n");
188         }
189         if (option_console && !option_verbose) 
190                 ast_verbose("[ Booting...");
191         signal(SIGURG, urg_handler);
192         signal(SIGINT, quit_handler);
193         signal(SIGTERM, quit_handler);
194         signal(SIGHUP, quit_handler);
195         if (init_logger())
196                 exit(1);
197         if (load_pbx())
198                 exit(1);
199         if (load_modules())
200                 exit(1);
201         if (set_priority(option_highpriority))
202                 exit(1);
203         /* We might have the option of showing a console, but for now just
204            do nothing... */
205         if (option_console && !option_verbose)
206                 ast_verbose(" ]\n");
207         if (option_verbose || option_console)
208                 ast_verbose( "Asterisk Ready.\n");
209         fully_booted = 1;
210         if (option_console) {
211                 /* Console stuff now... */
212                 /* Register our quit function */
213             ast_cli_register(&quit);
214                 consolethread = pthread_self();
215                 if (strlen(filename))
216                         read_history(filename);
217                 rl_callback_handler_install(ASTERISK_PROMPT, consolehandler);
218                 rl_completion_entry_function = (Function *)cli_generator;
219                 for(;;) {
220                         FD_ZERO(&rfds);
221                         FD_SET(STDIN_FILENO, &rfds);
222                         res = select(STDIN_FILENO + 1, &rfds, NULL, NULL, NULL);
223                         if (res > 0) {
224                                 rl_callback_read_char();
225                         } else if (res < 1) {
226                                 rl_forced_update_display();
227                         }
228         
229                 }       
230         } else {
231                 /* Do nothing */
232                 select(0,NULL,NULL,NULL,NULL);
233         }
234         return 0;
235 }