Skip to content
Snippets Groups Projects
asterisk.c 6.12 KiB
Newer Older
Mark Spencer's avatar
Mark Spencer committed
/*
 * Asterisk -- A telephony toolkit for Linux.
 *
 * Top level source file for asterisk
 * 
Mark Spencer's avatar
Mark Spencer committed
 * Copyright (C) 1999, Mark Spencer
Mark Spencer's avatar
Mark Spencer committed
 *
 * Mark Spencer <markster@linux-support.net>
 *
 * This program is free software, distributed under the terms of
 * the GNU General Public License
 */

#include <unistd.h>
#include <stdlib.h>
#include <asterisk/logger.h>
#include <asterisk/options.h>
Mark Spencer's avatar
Mark Spencer committed
#include <asterisk/cli.h>
Mark Spencer's avatar
Mark Spencer committed
#include <asterisk/channel.h>
Mark Spencer's avatar
Mark Spencer committed
#include <stdio.h>
#include <signal.h>
Mark Spencer's avatar
Mark Spencer committed
#include <sched.h>
#include <pthread.h>
#include <readline/readline.h>
#include <readline/history.h>
Mark Spencer's avatar
Mark Spencer committed
#include "asterisk.h"

int option_verbose=0;
int option_debug=0;
int option_nofork=0;
int option_quiet=0;
Mark Spencer's avatar
Mark Spencer committed
int option_console=0;
Mark Spencer's avatar
Mark Spencer committed
int option_highpriority=0;
Mark Spencer's avatar
Mark Spencer committed
int fully_booted = 0;
Mark Spencer's avatar
Mark Spencer committed
char defaultlanguage[MAX_LANGUAGE] = DEFAULT_LANGUAGE;

Mark Spencer's avatar
Mark Spencer committed
#define HIGH_PRIORITY 1
#define HIGH_PRIORITY_SCHED SCHED_RR
Mark Spencer's avatar
Mark Spencer committed

static void urg_handler(int num)
{
	/* Called by soft_hangup to interrupt the select, read, or other
	   system call.  We don't actually need to do anything though.  */
	if (option_debug)
		ast_log(LOG_DEBUG, "Urgent handler\n");
Mark Spencer's avatar
Mark Spencer committed
	signal(num, urg_handler);
Mark Spencer's avatar
Mark Spencer committed
	return;
}

Mark Spencer's avatar
Mark Spencer committed
static void set_title(char *text)
{
	/* Set an X-term or screen title */
	if (getenv("TERM") && strstr(getenv("TERM"), "xterm"))
		fprintf(stdout, "\033]2;%s\007", text);
}

static void set_icon(char *text)
{
	if (getenv("TERM") && strstr(getenv("TERM"), "xterm"))
		fprintf(stdout, "\033]1;%s\007", text);
}

Mark Spencer's avatar
Mark Spencer committed
static int set_priority(int pri)
{
	struct sched_param sched;
	/* We set ourselves to a high priority, that we might pre-empt everything
	   else.  If your PBX has heavy activity on it, this is a good thing.  */
	if (pri) {  
		sched.sched_priority = HIGH_PRIORITY;
		if (sched_setscheduler(0, HIGH_PRIORITY_SCHED, &sched)) {
			ast_log(LOG_WARNING, "Unable to set high priority\n");
			return -1;
		}
	} else {
		sched.sched_priority = 0;
		if (sched_setscheduler(0, SCHED_OTHER, &sched)) {
			ast_log(LOG_WARNING, "Unable to set normal priority\n");
			return -1;
		}
	}
	return 0;
}

Mark Spencer's avatar
Mark Spencer committed
static void quit_handler(int num)
{
Mark Spencer's avatar
Mark Spencer committed
	static pthread_mutex_t quitlock = PTHREAD_MUTEX_INITIALIZER;
	char filename[80] = "";
	if (getenv("HOME")) 
		snprintf(filename, sizeof(filename), "%s/.asterisk_history", getenv("HOME"));
	/* Quit only once */
	pthread_mutex_lock(&quitlock);
Mark Spencer's avatar
Mark Spencer committed
	/* Called on exit */
	if (option_verbose)
		ast_verbose("Asterisk ending (%d).\n", num);
	else if (option_debug)
		ast_log(LOG_DEBUG, "Asterisk ending (%d).\n", num);
Mark Spencer's avatar
Mark Spencer committed
	if (strlen(filename))
		write_history(filename);
Mark Spencer's avatar
Mark Spencer committed
	exit(0);
}

Mark Spencer's avatar
Mark Spencer committed
static pthread_t consolethread = -1;

static void console_verboser(char *s, int pos, int replace, int complete)
{
	/* Return to the beginning of the line */
	if (!pos)
		fprintf(stdout, "\r");
	fprintf(stdout, s + pos);
Mark Spencer's avatar
Mark Spencer committed
	fflush(stdout);
Mark Spencer's avatar
Mark Spencer committed
	if (complete)
	/* Wake up a select()ing console */
		pthread_kill(consolethread, SIGURG);
}

static void consolehandler(char *s)
{
	/* Called when readline data is available */
	if (s && strlen(s))
		add_history(s);
Mark Spencer's avatar
Mark Spencer committed
	/* Give the console access to the shell */
	if (s) {
		if (s[0] == '!') {
			if (s[1])
				system(s+1);
			else
				system(getenv("SHELL") ? getenv("SHELL") : "/bin/sh");
		} else 
Mark Spencer's avatar
Mark Spencer committed
		ast_cli_command(STDOUT_FILENO, s);
Mark Spencer's avatar
Mark Spencer committed
		if (!strcasecmp(s, "help"))
			fprintf(stdout, "          !<command>   Executes a given shell command\n");
	} else
		fprintf(stdout, "\nUse \"quit\" to exit\n");
Mark Spencer's avatar
Mark Spencer committed
}

static char quit_help[] = 
"Usage: quit\n"
"       Exits Asterisk.\n";

static int handle_quit(int fd, int argc, char *argv[])
{
	if (argc != 1)
		return RESULT_SHOWUSAGE;
	quit_handler(0);
	return RESULT_SUCCESS;
}

#define ASTERISK_PROMPT "*CLI> "

static struct ast_cli_entry quit = 	{ { "quit", NULL }, handle_quit, "Exit Asterisk", quit_help };

static char *cli_generator(char *text, int state)
{
	return ast_cli_generator(rl_line_buffer, text, state);
}

Mark Spencer's avatar
Mark Spencer committed
int main(int argc, char *argv[])
{
	char c;
Mark Spencer's avatar
Mark Spencer committed
	fd_set rfds;
	int res;
	char filename[80] = "";
	if (getenv("HOME")) 
		snprintf(filename, sizeof(filename), "%s/.asterisk_history", getenv("HOME"));
Mark Spencer's avatar
Mark Spencer committed
	/* Check if we're root */
	if (geteuid()) {
		ast_log(LOG_ERROR, "Must be run as root\n");
		exit(1);
	}
	/* Check for options */
Mark Spencer's avatar
Mark Spencer committed
	while((c=getopt(argc, argv, "dvqpc")) != EOF) {
Mark Spencer's avatar
Mark Spencer committed
		switch(c) {
		case 'd':
			option_debug++;
			option_nofork++;
Mark Spencer's avatar
Mark Spencer committed
			break;
Mark Spencer's avatar
Mark Spencer committed
		case 'c':
			option_console++;
			option_nofork++;
Mark Spencer's avatar
Mark Spencer committed
		case 'p':
			option_highpriority++;
Mark Spencer's avatar
Mark Spencer committed
			break;
		case 'v':
			option_verbose++;
Mark Spencer's avatar
Mark Spencer committed
			option_nofork++;
Mark Spencer's avatar
Mark Spencer committed
			break;
		case 'q':
			option_quiet++;
			break;
		case '?':
			exit(1);
		}
	}
Mark Spencer's avatar
Mark Spencer committed
	ast_register_verbose(console_verboser);
Mark Spencer's avatar
Mark Spencer committed
	/* Print a welcome message if desired */
Mark Spencer's avatar
Mark Spencer committed
	if (option_verbose || option_console) {
Mark Spencer's avatar
Mark Spencer committed
		ast_verbose( "Asterisk, Copyright (C) 1999 Mark Spencer\n");
Mark Spencer's avatar
Mark Spencer committed
		ast_verbose( "Written by Mark Spencer <markster@linux-support.net>\n");
		ast_verbose( "=========================================================================\n");
	}
Mark Spencer's avatar
Mark Spencer committed
	if (option_console && !option_verbose) 
		ast_verbose("[ Booting...");
Mark Spencer's avatar
Mark Spencer committed
	signal(SIGURG, urg_handler);
	signal(SIGINT, quit_handler);
	signal(SIGTERM, quit_handler);
	signal(SIGHUP, quit_handler);
	if (init_logger())
		exit(1);
	if (load_pbx())
		exit(1);
	if (load_modules())
		exit(1);
Mark Spencer's avatar
Mark Spencer committed
	if (set_priority(option_highpriority))
		exit(1);
Mark Spencer's avatar
Mark Spencer committed
	/* We might have the option of showing a console, but for now just
	   do nothing... */
Mark Spencer's avatar
Mark Spencer committed
	if (option_console && !option_verbose)
		ast_verbose(" ]\n");
	if (option_verbose || option_console)
Mark Spencer's avatar
Mark Spencer committed
		ast_verbose( "Asterisk Ready.\n");
Mark Spencer's avatar
Mark Spencer committed
	fully_booted = 1;
	if (option_console) {
		/* Console stuff now... */
		/* Register our quit function */
Mark Spencer's avatar
Mark Spencer committed
		char title[256];
		set_icon("Asterisk");
		snprintf(title, sizeof(title), "Asterisk Console (pid %d)", getpid());
		set_title(title);
Mark Spencer's avatar
Mark Spencer committed
	    ast_cli_register(&quit);
		consolethread = pthread_self();
		if (strlen(filename))
			read_history(filename);
		rl_callback_handler_install(ASTERISK_PROMPT, consolehandler);
		rl_completion_entry_function = (Function *)cli_generator;
		for(;;) {
			FD_ZERO(&rfds);
			FD_SET(STDIN_FILENO, &rfds);
			res = select(STDIN_FILENO + 1, &rfds, NULL, NULL, NULL);
			if (res > 0) {
				rl_callback_read_char();
			} else if (res < 1) {
				rl_forced_update_display();
			}
	
		}	
	} else {
		/* Do nothing */
		select(0,NULL,NULL,NULL,NULL);
	}
Mark Spencer's avatar
Mark Spencer committed
	return 0;
}