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