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