Skip to content
Snippets Groups Projects
asterisk.c 136 KiB
Newer Older
  • Learn to ignore specific revisions
  • 	}
    	ast_verb(1, "Setting %s thread priority on all threads\n", policy_str);
    	AST_RWLIST_RDLOCK(&thread_list);
    	AST_RWLIST_TRAVERSE(&thread_list, cur, list) {
    		/* Don't care about the return value. It should work. */
    		sched_setscheduler(cur->lwp, policy, &sched);
    	}
    	AST_RWLIST_UNLOCK(&thread_list);
    	return 0;
    #endif
    }
    
    
    /*! \brief 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.
     */
    
    Mark Spencer's avatar
    Mark Spencer committed
    {
    	struct sched_param sched;
    
    Mark Spencer's avatar
    Mark Spencer committed
    	memset(&sched, 0, sizeof(sched));
    
    Mark Spencer's avatar
    Mark Spencer committed
    #ifdef __linux__
    
    Mark Spencer's avatar
    Mark Spencer committed
    		sched.sched_priority = 10;
    		if (sched_setscheduler(0, SCHED_RR, &sched)) {
    
    Mark Spencer's avatar
    Mark Spencer committed
    			ast_log(LOG_WARNING, "Unable to set high priority\n");
    			return -1;
    
    Mark Spencer's avatar
    Mark Spencer committed
    		} else
    
    			ast_verb(1, "Set to realtime thread\n");
    
    Mark Spencer's avatar
    Mark Spencer committed
    	} else {
    		sched.sched_priority = 0;
    
    		/* According to the manpage, these parameters can never fail. */
    		sched_setscheduler(0, SCHED_OTHER, &sched);
    
    Mark Spencer's avatar
    Mark Spencer committed
    	}
    
    Mark Spencer's avatar
    Mark Spencer committed
    #else
    	if (pri) {
    		if (setpriority(PRIO_PROCESS, 0, -10) == -1) {
    			ast_log(LOG_WARNING, "Unable to set high priority\n");
    			return -1;
    		} else
    
    			ast_verb(1, "Set to high priority\n");
    
    Mark Spencer's avatar
    Mark Spencer committed
    	} else {
    
    		/* According to the manpage, these parameters can never fail. */
    		setpriority(PRIO_PROCESS, 0, 0);
    
    Mark Spencer's avatar
    Mark Spencer committed
    	}
    #endif
    
    Mark Spencer's avatar
    Mark Spencer committed
    	return 0;
    }
    
    
    int ast_shutdown_final(void)
    {
    	return shuttingdown == SHUTTING_DOWN_FINAL;
    }
    
    int ast_shutting_down(void)
    {
    	return shutdown_pending;
    }
    
    int ast_cancel_shutdown(void)
    {
    	int shutdown_aborted = 0;
    
    	ast_mutex_lock(&safe_system_lock);
    	if (shuttingdown >= SHUTDOWN_FAST) {
    		shuttingdown = NOT_SHUTTING_DOWN;
    		shutdown_pending = 0;
    		shutdown_aborted = 1;
    	}
    	ast_mutex_unlock(&safe_system_lock);
    	return shutdown_aborted;
    }
    
    /*!
     * \internal
     * \brief Initiate system shutdown -- prevents new channels from being allocated.
     */
    static void ast_begin_shutdown(void)
    {
    	ast_mutex_lock(&safe_system_lock);
    	if (shuttingdown != NOT_SHUTTING_DOWN) {
    		shutdown_pending = 1;
    	}
    	ast_mutex_unlock(&safe_system_lock);
    }
    
    
    static int can_safely_quit(shutdown_nice_t niceness, int restart);
    static void really_quit(int num, shutdown_nice_t niceness, int restart);
    
    static void quit_handler(int num, shutdown_nice_t niceness, int restart)
    
    Mark Spencer's avatar
    Mark Spencer committed
    {
    
    	if (can_safely_quit(niceness, restart)) {
    		really_quit(num, niceness, restart);
    		/* No one gets here. */
    	}
    	/* It wasn't our time. */
    }
    
    
    #define SHUTDOWN_TIMEOUT	15	/* Seconds */
    
    /*!
     * \internal
     * \brief Wait for all channels to die, a timeout, or shutdown cancelled.
     * \since 13.3.0
     *
     * \param niceness Shutdown niceness in effect
     * \param seconds Number of seconds to wait or less than zero if indefinitely.
     *
     * \retval zero if waiting wasn't necessary.  We were idle.
     * \retval non-zero if we had to wait.
     */
    static int wait_for_channels_to_die(shutdown_nice_t niceness, int seconds)
    {
    	time_t start;
    	time_t now;
    	int waited = 0;
    
    	time(&start);
    	for (;;) {
    		if (!ast_undestroyed_channels() || shuttingdown != niceness) {
    			break;
    		}
    		if (seconds < 0) {
    			/* No timeout so just poll every second */
    			sleep(1);
    		} else {
    			time(&now);
    
    			/* Wait up to the given seconds for all channels to go away */
    			if (seconds < (now - start)) {
    				break;
    			}
    
    			/* Sleep 1/10 of a second */
    			usleep(100000);
    		}
    		waited = 1;
    	}
    	return waited;
    }
    
    
    static int can_safely_quit(shutdown_nice_t niceness, int restart)
    {
    
    	/* Check if someone else isn't already doing this. */
    	ast_mutex_lock(&safe_system_lock);
    	if (shuttingdown != NOT_SHUTTING_DOWN && niceness >= shuttingdown) {
    		/* Already in progress and other request was less nice. */
    		ast_mutex_unlock(&safe_system_lock);
    		ast_verbose("Ignoring asterisk %s request, already in progress.\n", restart ? "restart" : "shutdown");
    		return 0;
    	}
    	shuttingdown = niceness;
    	ast_mutex_unlock(&safe_system_lock);
    
    	/* Try to get as many CDRs as possible submitted to the backend engines
    	 * (if in batch mode). really_quit happens to call it again when running
    	 * the atexit handlers, otherwise this would be a bit early. */
    
    	/*
    	 * Shutdown the message queue for the technology agnostic message channel.
    	 * This has to occur before we pause shutdown pending ast_undestroyed_channels.
    	 *
    	 * XXX This is not reversed on shutdown cancel.
    	 */
    
    
    	if (niceness == SHUTDOWN_NORMAL) {
    		/* Begin shutdown routine, hanging up active channels */
    
    		if (ast_opt_console) {
    			ast_verb(0, "Beginning asterisk %s....\n", restart ? "restart" : "shutdown");
    
    		ast_softhangup_all();
    		waited |= wait_for_channels_to_die(niceness, SHUTDOWN_TIMEOUT);
    
    	} else if (niceness >= SHUTDOWN_NICE) {
    		if (niceness != SHUTDOWN_REALLY_NICE) {
    
    		if (ast_opt_console) {
    
    			ast_verb(0, "Waiting for inactivity to perform %s...\n", restart ? "restart" : "halt");
    
    		waited |= wait_for_channels_to_die(niceness, -1);
    
    	/* Re-acquire lock and check if someone changed the niceness, in which
    
    	 * case someone else has taken over the shutdown.
    	 */
    
    	ast_mutex_lock(&safe_system_lock);
    	if (shuttingdown != niceness) {
    
    		if (shuttingdown == NOT_SHUTTING_DOWN && ast_opt_console) {
    
    			ast_verb(0, "Asterisk %s cancelled.\n", restart ? "restart" : "shutdown");
    
    		ast_mutex_unlock(&safe_system_lock);
    		return 0;
    	}
    
    
    	if (niceness >= SHUTDOWN_REALLY_NICE) {
    		shuttingdown = SHUTTING_DOWN;
    		ast_mutex_unlock(&safe_system_lock);
    
    		/* No more Mr. Nice guy.  We are committed to shutting down now. */
    		ast_begin_shutdown();
    		ast_softhangup_all();
    		waited |= wait_for_channels_to_die(SHUTTING_DOWN, SHUTDOWN_TIMEOUT);
    
    		ast_mutex_lock(&safe_system_lock);
    	}
    	shuttingdown = SHUTTING_DOWN_FINAL;
    
    	ast_mutex_unlock(&safe_system_lock);
    
    
    	if (niceness >= SHUTDOWN_NORMAL && waited) {
    		/*
    		 * We were not idle.  Give things in progress a chance to
    		 * recognize the final shutdown phase.
    		 */
    		sleep(1);
    	}
    
    /*! Called when exiting is certain. */
    
    static void really_quit(int num, shutdown_nice_t niceness, int restart)
    {
    
    	int active_channels;
    
    Kevin Harwell's avatar
    Kevin Harwell committed
    	struct ast_json *json_object = NULL;
    
    	int run_cleanups = niceness >= SHUTDOWN_NICE;
    
    	if (run_cleanups && modules_shutdown()) {
    		ast_verb(0, "Some modules could not be unloaded, switching to fast shutdown\n");
    		run_cleanups = 0;
    
    	if (!restart) {
    		ast_sd_notify("STOPPING=1");
    	}
    
    	if (ast_opt_console || (ast_opt_remote && !ast_opt_exec)) {
    
    		ast_el_write_default_histfile();
    
    		if (consolethread == AST_PTHREADT_NULL || consolethread == pthread_self()) {
    			/* Only end if we are the consolethread, otherwise there's a race with that thread. */
    
    			if (el != NULL) {
    				el_end(el);
    			}
    			if (el_hist != NULL) {
    				history_end(el_hist);
    			}
    
    		} else if (mon_sig_flags == pthread_self()) {
    			if (consolethread != AST_PTHREADT_NULL) {
    				pthread_kill(consolethread, SIGURG);
    			}
    
    Mark Spencer's avatar
    Mark Spencer committed
    	}
    
    	active_channels = ast_active_channels();
    
    	/* Don't publish messages if we're a remote console - we won't have all of the Stasis
    	 * topics or message types
    	 */
    	if (!ast_opt_remote) {
    		json_object = ast_json_pack("{s: s, s: s}",
    				"Shutdown", active_channels ? "Uncleanly" : "Cleanly",
    				"Restart", restart ? "True" : "False");
    
    		ast_manager_publish_event("Shutdown", EVENT_FLAG_SYSTEM, json_object);
    
    Kevin Harwell's avatar
    Kevin Harwell committed
    		ast_json_unref(json_object);
    		json_object = NULL;
    
    	ast_verb(0, "Asterisk %s ending (%d).\n",
    		active_channels ? "uncleanly" : "cleanly", num);
    
    
    	ast_verb(0, "Executing last minute cleanups\n");
    
    	ast_run_atexits(run_cleanups);
    
    	ast_debug(1, "Asterisk ending (%d).\n", num);
    
    Mark Spencer's avatar
    Mark Spencer committed
    	if (ast_socket > -1) {
    
    		pthread_cancel(lthread);
    
    Mark Spencer's avatar
    Mark Spencer committed
    		close(ast_socket);
    
    Mark Spencer's avatar
    Mark Spencer committed
    		ast_socket = -1;
    
    		pthread_kill(lthread, SIGURG);
    		pthread_join(lthread, NULL);
    
    Mark Spencer's avatar
    Mark Spencer committed
    	}
    
    Mark Spencer's avatar
    Mark Spencer committed
    	if (ast_consock > -1)
    		close(ast_consock);
    
    	if (!ast_opt_remote)
    		unlink(ast_config_AST_PID);
    
    	if (sig_alert_pipe[0])
    		close(sig_alert_pipe[0]);
    	if (sig_alert_pipe[1])
    		close(sig_alert_pipe[1]);
    
    Mark Spencer's avatar
    Mark Spencer committed
    	if (restart) {
    
    		ast_verb(0, "Preparing for Asterisk restart...\n");
    
    Mark Spencer's avatar
    Mark Spencer committed
    		/* Mark all FD's for closing on exec */
    
    		for (i = 3; i < 32768; i++) {
    			fcntl(i, F_SETFD, FD_CLOEXEC);
    
    		ast_verb(0, "Asterisk is now restarting...\n");
    
    		clean_time_zones();
    
    		/* If there is a consolethread running send it a SIGHUP
    
    		   so it can execvp, otherwise we can do it ourselves */
    
    		if ((consolethread != AST_PTHREADT_NULL) && (consolethread != pthread_self())) {
    
    			pthread_kill(consolethread, SIGHUP);
    
    James Golovich's avatar
    James Golovich committed
    			/* Give the signal handler some time to complete */
    			sleep(2);
    		} else
    
    	} else {
    		/* close logger */
    		close_logger();
    
    		clean_time_zones();
    
    Mark Spencer's avatar
    Mark Spencer committed
    }
    
    static void __quit_handler(int num)
    {
    
    	int a = 0;
    	sig_flags.need_quit = 1;
    
    	if (sig_alert_pipe[1] != -1) {
    		if (write(sig_alert_pipe[1], &a, sizeof(a)) < 0) {
    
    			fprintf(stderr, "quit_handler: write() failed: %s\n", strerror(errno));
    
    	/* There is no need to restore the signal handler here, since the app
    	 * is going to exit */
    
    static void __remote_quit_handler(int num)
    {
    	sig_flags.need_quit = 1;
    }
    
    
    static void set_header(char *outbuf, int maxout, char level)
    
    	const char *cmp;
    
    
    	switch (level) {
    
    	case 1: cmp = VERBOSE_PREFIX_1;
    		break;
    	case 2: cmp = VERBOSE_PREFIX_2;
    		break;
    	case 3: cmp = VERBOSE_PREFIX_3;
    		break;
    	default: cmp = VERBOSE_PREFIX_4;
    		break;
    	}
    
    	if (ast_opt_timestamp) {
    		struct ast_tm tm;
    		struct timeval now = ast_tvnow();
    		ast_localtime(&now, &tm, NULL);
    		ast_strftime(date, sizeof(date), ast_logger_get_dateformat(), &tm);
    
    	snprintf(outbuf, maxout, "%s%s%s%s%s%s",
    		ast_opt_timestamp ? "[" : "",
    		ast_opt_timestamp ? date : "",
    		ast_opt_timestamp ? "] " : "",
    		cmp ? ast_term_color(COLOR_GRAY, 0) : "",
    		cmp ? cmp : "",
    		cmp ? ast_term_reset() : "");
    
    struct console_state_data {
    	char verbose_line_level;
    };
    
    static int console_state_init(void *ptr)
    {
    	struct console_state_data *state = ptr;
    	state->verbose_line_level = 0;
    	return 0;
    }
    
    AST_THREADSTORAGE_CUSTOM(console_state, console_state_init, ast_free_ptr);
    
    
    static int console_print(const char *s, int local)
    
    Mark Spencer's avatar
    Mark Spencer committed
    {
    
    	struct console_state_data *state =
    		ast_threadstorage_get(&console_state, sizeof(*state));
    
    	char prefix[80];
    
    	int num, res = 0;
    
    	unsigned int newline;
    
    
    	do {
    		if (VERBOSE_HASMAGIC(s)) {
    
    			/* always use the given line's level, otherwise
    			   we'll use the last line's level */
    
    			state->verbose_line_level = VERBOSE_MAGIC2LEVEL(s);
    
    			/* move past magic */
    			s++;
    
    
    			set_header(prefix, sizeof(prefix), state->verbose_line_level);
    
    			*prefix = '\0';
    		}
    
    		/* for a given line separate on verbose magic, newline, and eol */
    		if ((s = strchr(c, '\n'))) {
    
    			newline = 1;
    		} else {
    			s = strchr(c, '\0');
    			newline = 0;
    
    		}
    
    		/* check if we should write this line after calculating begin/end
    		   so we process the case of a higher level line embedded within
    		   two lower level lines */
    		if (state->verbose_line_level > option_verbose) {
    			continue;
    		}
    
    
    			fputs(prefix, stdout);
    		}
    
    
    		num = s - c;
    		if (fwrite(c, sizeof(char), num, stdout) < num) {
    			break;
    		}
    
    
    		if (!res) {
    			/* if at least some info has been written
    			   we'll want to return true */
    			res = 1;
    		}
    	} while (*s);
    
    
    	if (newline) {
    		/* if ending on a newline then reset last level to zero
    		    since what follows may be not be logging output */
    		state->verbose_line_level = 0;
    	}
    
    
    	if (res) {
    		fflush(stdout);
    
    	return res;
    }
    
    static void console_verboser(const char *s)
    {
    
    	if (!console_print(s, 1)) {
    
    	/* Wake up a poll()ing console */
    
    	if (ast_opt_console && consolethread != AST_PTHREADT_NULL) {
    
    		pthread_kill(consolethread, SIGURG);
    
    static int ast_all_zeros(const char *s)
    
    /* This is the main console CLI command handler.  Run by the main() thread. */
    
    static void consolehandler(const char *s)
    
    Mark Spencer's avatar
    Mark Spencer committed
    {
    
    Mark Spencer's avatar
    Mark Spencer committed
    	fflush(stdout);
    
    Mark Spencer's avatar
    Mark Spencer committed
    	/* Called when readline data is available */
    
    	if (!ast_all_zeros(s))
    
    Mark Spencer's avatar
    Mark Spencer committed
    		ast_el_add_history(s);
    
    	/* The real handler for bang */
    	if (s[0] == '!') {
    		if (s[1])
    			ast_safe_system(s+1);
    		else
    			ast_safe_system(getenv("SHELL") ? getenv("SHELL") : "/bin/sh");
    
    Mark Spencer's avatar
    Mark Spencer committed
    		ast_cli_command(STDOUT_FILENO, s);
    }
    
    
    static int remoteconsolehandler(const char *s)
    
    Mark Spencer's avatar
    Mark Spencer committed
    {
    
    Mark Spencer's avatar
    Mark Spencer committed
    	int ret = 0;
    
    Mark Spencer's avatar
    Mark Spencer committed
    	/* Called when readline data is available */
    
    	if (!ast_all_zeros(s))
    
    Mark Spencer's avatar
    Mark Spencer committed
    		ast_el_add_history(s);
    
    	/* The real handler for bang */
    	if (s[0] == '!') {
    		if (s[1])
    			ast_safe_system(s+1);
    		else
    			ast_safe_system(getenv("SHELL") ? getenv("SHELL") : "/bin/sh");
    		ret = 1;
    
    	} else if ((strncasecmp(s, "quit", 4) == 0 || strncasecmp(s, "exit", 4) == 0) &&
    	    (s[4] == '\0' || isspace(s[4]))) {
    		quit_handler(0, SHUTDOWN_FAST, 0);
    		ret = 1;
    
    Mark Spencer's avatar
    Mark Spencer committed
    
    	return ret;
    
    static char *handle_version(struct ast_cli_entry *e, int cmd, struct ast_cli_args *a)
    
    	switch (cmd) {
    	case CLI_INIT:
    		e->command = "core show version";
    
    			"Usage: core show version\n"
    			"       Shows Asterisk version information.\n";
    		return NULL;
    	case CLI_GENERATE:
    		return NULL;
    	}
    
    	if (a->argc != 3)
    		return CLI_SHOWUSAGE;
    	ast_cli(a->fd, "Asterisk %s built by %s @ %s on a %s running %s on %s\n",
    
    		ast_get_version(), ast_build_user, ast_build_hostname,
    
    		ast_build_machine, ast_build_os, ast_build_date);
    
    static char *handle_stop_now(struct ast_cli_entry *e, int cmd, struct ast_cli_args *a)
    
    		e->command = "core stop now";
    
    			"Usage: core stop now\n"
    
    			"       Shuts down a running Asterisk immediately, hanging up all active calls .\n";
    
    		ast_cli_allow_at_shutdown(e);
    
    	if (a->argc != e->args)
    
    	quit_handler(0, SHUTDOWN_NORMAL, 0 /* not restart */);
    
    static char *handle_stop_gracefully(struct ast_cli_entry *e, int cmd, struct ast_cli_args *a)
    
    		e->command = "core stop gracefully";
    
    			"Usage: core stop gracefully\n"
    
    			"       Causes Asterisk to not accept new calls, and exit when all\n"
    			"       active calls have terminated normally.\n";
    
    		ast_cli_allow_at_shutdown(e);
    
    	if (a->argc != e->args)
    
    	quit_handler(0, SHUTDOWN_NICE, 0 /* no restart */);
    
    static char *handle_stop_when_convenient(struct ast_cli_entry *e, int cmd, struct ast_cli_args *a)
    
    		e->command = "core stop when convenient";
    
    			"Usage: core stop when convenient\n"
    
    			"       Causes Asterisk to perform a shutdown when all active calls have ended.\n";
    
    		ast_cli_allow_at_shutdown(e);
    
    	if (a->argc != e->args)
    
    		return CLI_SHOWUSAGE;
    	ast_cli(a->fd, "Waiting for inactivity to perform halt\n");
    
    	quit_handler(0, SHUTDOWN_REALLY_NICE, 0 /* don't restart */);
    
    static char *handle_restart_now(struct ast_cli_entry *e, int cmd, struct ast_cli_args *a)
    
    		e->command = "core restart now";
    
    			"Usage: core restart now\n"
    
    			"       Causes Asterisk to hangup all calls and exec() itself performing a cold\n"
    			"       restart.\n";
    
    		ast_cli_allow_at_shutdown(e);
    
    	if (a->argc != e->args)
    
    	quit_handler(0, SHUTDOWN_NORMAL, 1 /* restart */);
    
    static char *handle_restart_gracefully(struct ast_cli_entry *e, int cmd, struct ast_cli_args *a)
    
    		e->command = "core restart gracefully";
    
    			"Usage: core restart gracefully\n"
    
    			"       Causes Asterisk to stop accepting new calls and exec() itself performing a cold\n"
    			"       restart when all active calls have ended.\n";
    
    		ast_cli_allow_at_shutdown(e);
    
    	if (a->argc != e->args)
    
    	quit_handler(0, SHUTDOWN_NICE, 1 /* restart */);
    
    static char *handle_restart_when_convenient(struct ast_cli_entry *e, int cmd, struct ast_cli_args *a)
    
    		e->command = "core restart when convenient";
    
    			"Usage: core restart when convenient\n"
    
    			"       Causes Asterisk to perform a cold restart when all active calls have ended.\n";
    
    		ast_cli_allow_at_shutdown(e);
    
    	if (a->argc != e->args)
    
    		return CLI_SHOWUSAGE;
    	ast_cli(a->fd, "Waiting for inactivity to perform restart\n");
    
    	quit_handler(0, SHUTDOWN_REALLY_NICE, 1 /* restart */);
    
    static char *handle_abort_shutdown(struct ast_cli_entry *e, int cmd, struct ast_cli_args *a)
    
    		e->command = "core abort shutdown";
    
    			"Usage: core abort shutdown\n"
    
    			"       Causes Asterisk to abort an executing shutdown or restart, and resume normal\n"
    			"       call operations.\n";
    
    		ast_cli_allow_at_shutdown(e);
    
    	if (a->argc != e->args)
    
    static char *handle_bang(struct ast_cli_entry *e, int cmd, struct ast_cli_args *a)
    
    Mark Spencer's avatar
    Mark Spencer committed
    {
    
    	switch (cmd) {
    	case CLI_INIT:
    		e->command = "!";
    
    			"Usage: !<command>\n"
    			"       Executes a given shell command\n";
    		return NULL;
    	case CLI_GENERATE:
    		return NULL;
    	}
    
    	return CLI_SUCCESS;
    
    Mark Spencer's avatar
    Mark Spencer committed
    }
    
    static const char warranty_lines[] = {
    	"\n"
    	"			    NO WARRANTY\n"
    	"\n"
    	"BECAUSE THE PROGRAM IS LICENSED FREE OF CHARGE, THERE IS NO WARRANTY\n"
    	"FOR THE PROGRAM, TO THE EXTENT PERMITTED BY APPLICABLE LAW.  EXCEPT WHEN\n"
    	"OTHERWISE STATED IN WRITING THE COPYRIGHT HOLDERS AND/OR OTHER PARTIES\n"
    	"PROVIDE THE PROGRAM \"AS IS\" WITHOUT WARRANTY OF ANY KIND, EITHER EXPRESSED\n"
    	"OR IMPLIED, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF\n"
    	"MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE.  THE ENTIRE RISK AS\n"
    	"TO THE QUALITY AND PERFORMANCE OF THE PROGRAM IS WITH YOU.  SHOULD THE\n"
    	"PROGRAM PROVE DEFECTIVE, YOU ASSUME THE COST OF ALL NECESSARY SERVICING,\n"
    	"REPAIR OR CORRECTION.\n"
    	"\n"
    	"IN NO EVENT UNLESS REQUIRED BY APPLICABLE LAW OR AGREED TO IN WRITING\n"
    	"WILL ANY COPYRIGHT HOLDER, OR ANY OTHER PARTY WHO MAY MODIFY AND/OR\n"
    	"REDISTRIBUTE THE PROGRAM AS PERMITTED ABOVE, BE LIABLE TO YOU FOR DAMAGES,\n"
    	"INCLUDING ANY GENERAL, SPECIAL, INCIDENTAL OR CONSEQUENTIAL DAMAGES ARISING\n"
    	"OUT OF THE USE OR INABILITY TO USE THE PROGRAM (INCLUDING BUT NOT LIMITED\n"
    	"TO LOSS OF DATA OR DATA BEING RENDERED INACCURATE OR LOSSES SUSTAINED BY\n"
    	"YOU OR THIRD PARTIES OR A FAILURE OF THE PROGRAM TO OPERATE WITH ANY OTHER\n"
    	"PROGRAMS), EVEN IF SUCH HOLDER OR OTHER PARTY HAS BEEN ADVISED OF THE\n"
    	"POSSIBILITY OF SUCH DAMAGES.\n"
    
    static char *show_warranty(struct ast_cli_entry *e, int cmd, struct ast_cli_args *a)
    
    	switch (cmd) {
    	case CLI_INIT:
    		e->command = "core show warranty";
    
    			"Usage: core show warranty\n"
    			"       Shows the warranty (if any) for this copy of Asterisk.\n";
    		return NULL;
    	case CLI_GENERATE:
    		return NULL;
    	}
    
    static const char license_lines[] = {
    	"\n"
    	"This program is free software; you can redistribute it and/or modify\n"
    	"it under the terms of the GNU General Public License version 2 as\n"
    	"published by the Free Software Foundation.\n"
    	"\n"
    	"This program also contains components licensed under other licenses.\n"
    	"They include:\n"
    	"\n"
    	"This program is distributed in the hope that it will be useful,\n"
    	"but WITHOUT ANY WARRANTY; without even the implied warranty of\n"
    	"MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the\n"
    	"GNU General Public License for more details.\n"
    	"\n"
    	"You should have received a copy of the GNU General Public License\n"
    	"along with this program; if not, write to the Free Software\n"
    	"Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA\n"
    
    static char *show_license(struct ast_cli_entry *e, int cmd, struct ast_cli_args *a)
    
    	switch (cmd) {
    	case CLI_INIT:
    		e->command = "core show license";
    
    			"Usage: core show license\n"
    			"       Shows the license(s) for this copy of Asterisk.\n";
    		return NULL;
    	case CLI_GENERATE:
    		return NULL;
    	}
    
    Mark Spencer's avatar
    Mark Spencer committed
    
    
    Mark Spencer's avatar
    Mark Spencer committed
    #define ASTERISK_PROMPT "*CLI> "
    
    
    /*!
     * \brief Shutdown Asterisk CLI commands.
     *
     * \note These CLI commands cannot be unregistered at shutdown
     * because one of them is likely the reason for the shutdown.
     * The CLI generates a warning if a command is in-use when it is
     * unregistered.
     */
    static struct ast_cli_entry cli_asterisk_shutdown[] = {
    
    	AST_CLI_DEFINE(handle_stop_now, "Shut down Asterisk immediately"),
    	AST_CLI_DEFINE(handle_stop_gracefully, "Gracefully shut down Asterisk"),
    	AST_CLI_DEFINE(handle_stop_when_convenient, "Shut down Asterisk at empty call volume"),
    
    	AST_CLI_DEFINE(handle_restart_now, "Restart Asterisk immediately"),
    
    	AST_CLI_DEFINE(handle_restart_gracefully, "Restart Asterisk gracefully"),
    	AST_CLI_DEFINE(handle_restart_when_convenient, "Restart Asterisk at empty call volume"),
    
    };
    
    static struct ast_cli_entry cli_asterisk[] = {
    	AST_CLI_DEFINE(handle_abort_shutdown, "Cancel a running shutdown"),
    
    	AST_CLI_DEFINE(show_warranty, "Show the warranty (if any) for this copy of Asterisk"),
    	AST_CLI_DEFINE(show_license, "Show the license(s) for this copy of Asterisk"),
    	AST_CLI_DEFINE(handle_version, "Display version info"),
    	AST_CLI_DEFINE(handle_bang, "Execute a shell command"),
    
    #if !defined(LOW_MEMORY)
    
    	AST_CLI_DEFINE(handle_show_version_files, "List versions of files used to build Asterisk"),
    	AST_CLI_DEFINE(handle_show_threads, "Show running threads"),
    
    #if defined(HAVE_SYSINFO) || defined(HAVE_SYSCTL)
    
    	AST_CLI_DEFINE(handle_show_sysinfo, "Show System Information"),
    
    	AST_CLI_DEFINE(handle_show_profile, "Display profiling info"),
    	AST_CLI_DEFINE(handle_show_settings, "Show some core settings"),
    	AST_CLI_DEFINE(handle_clear_profile, "Clear profiling info"),
    
    #endif /* ! LOW_MEMORY */
    
    static void send_rasterisk_connect_commands(void)
    {
    	char buf[80];
    
    	/*
    	 * Tell the server asterisk instance about the verbose level
    	 * initially desired.
    	 */
    	if (option_verbose) {
    		snprintf(buf, sizeof(buf), "core set verbose atleast %d silent", option_verbose);
    		fdsend(ast_consock, buf);
    	}
    
    	if (option_debug) {
    		snprintf(buf, sizeof(buf), "core set debug atleast %d", option_debug);
    		fdsend(ast_consock, buf);
    	}
    
    
    	/* Leave verbose filtering to the server. */
    	option_verbose = INT_MAX;
    
    
    	if (!ast_opt_mute) {
    		fdsend(ast_consock, "logger mute silent");
    	} else {
    		printf("log and verbose output currently muted ('logger mute' to unmute)\n");
    	}
    }
    
    
    #ifdef HAVE_LIBEDIT_IS_UNICODE
    static int ast_el_read_char(EditLine *editline, wchar_t *cp)
    #else
    
    static int ast_el_read_char(EditLine *editline, char *cp)
    
    Mark Spencer's avatar
    Mark Spencer committed
    {
    
    Mark Spencer's avatar
    Mark Spencer committed
    	int res;
    	int max;
    
    #define EL_BUF_SIZE 512
    	char buf[EL_BUF_SIZE];
    
    Mark Spencer's avatar
    Mark Spencer committed
    
    	for (;;) {
    
    		max = 1;
    		fds[0].fd = ast_consock;
    		fds[0].events = POLLIN;
    
    			fds[1].fd = STDIN_FILENO;
    			fds[1].events = POLLIN;
    			max++;
    
    Mark Spencer's avatar
    Mark Spencer committed
    		}
    
    		res = ast_poll(fds, max, -1);
    
    Mark Spencer's avatar
    Mark Spencer committed
    		if (res < 0) {
    
    			if (sig_flags.need_quit || sig_flags.need_quit_handler)
    
    Mark Spencer's avatar
    Mark Spencer committed
    			if (errno == EINTR)
    				continue;
    
    			fprintf(stderr, "poll failed: %s\n", strerror(errno));
    
    			char c = '\0';
    			num_read = read(STDIN_FILENO, &c, 1);
    
    Mark Spencer's avatar
    Mark Spencer committed
    			if (num_read < 1) {
    				break;
    
    #ifdef 	HAVE_LIBEDIT_IS_UNICODE
    				*cp = btowc(c);
    #else
    				*cp = c;
    #endif
    
    Mark Spencer's avatar
    Mark Spencer committed
    				return (num_read);
    
    Mark Spencer's avatar
    Mark Spencer committed
    		}
    
    Mark Spencer's avatar
    Mark Spencer committed
    			res = read(ast_consock, buf, sizeof(buf) - 1);
    			/* if the remote side disappears exit */
    			if (res < 1) {
    				fprintf(stderr, "\nDisconnected from Asterisk server\n");
    
    					quit_handler(0, SHUTDOWN_FAST, 0);
    
    Mark Spencer's avatar
    Mark Spencer committed
    					int reconnects_per_second = 20;
    					fprintf(stderr, "Attempting to reconnect for 30 seconds\n");
    
    					for (tries = 0; tries < 30 * reconnects_per_second; tries++) {
    
    Mark Spencer's avatar
    Mark Spencer committed
    							fprintf(stderr, "Reconnect succeeded after %.3f seconds\n", 1.0 / reconnects_per_second * tries);
    
    Mark Spencer's avatar
    Mark Spencer committed
    							WELCOME_MESSAGE;
    
    							send_rasterisk_connect_commands();
    
    Olle Johansson's avatar
    Olle Johansson committed
    						} else
    
    							usleep(1000000 / reconnects_per_second);
    					}
    
    					if (tries >= 30 * reconnects_per_second) {
    
    						fprintf(stderr, "Failed to reconnect for 30 seconds.  Quitting.\n");
    
    						quit_handler(0, SHUTDOWN_FAST, 0);
    
    Mark Spencer's avatar
    Mark Spencer committed
    			}
    
    			buf[res] = '\0';
    
    
    			/* Write over the CLI prompt */
    
    				if (write(STDOUT_FILENO, "\r", 5) < 0) {
    
    			console_print(buf, 0);
    
    			if ((res < EL_BUF_SIZE - 1) && ((buf[res-1] == '\n') || (res >= 2 && buf[res-2] == '\n'))) {
    
    #ifdef 	HAVE_LIBEDIT_IS_UNICODE
    				*cp = btowc(CC_REFRESH);
    #else
    
    				*cp = CC_REFRESH;
    
    				return(1);
    
    Mark Spencer's avatar
    Mark Spencer committed
    				lastpos = 1;
    
    #ifdef 	HAVE_LIBEDIT_IS_UNICODE
    	*cp = btowc('\0');
    #else
    
    Mark Spencer's avatar
    Mark Spencer committed
    	*cp = '\0';
    
    Mark Spencer's avatar
    Mark Spencer committed
    	return (0);
    }
    
    
    static char *cli_prompt(EditLine *editline)
    
    Mark Spencer's avatar
    Mark Spencer committed
    {
    
    	static int cli_prompt_changes = 0;
    	struct passwd *pw;
    	struct group *gr;
    
    	if (prompt == NULL) {
    		prompt = ast_str_create(100);
    	} else if (!cli_prompt_changes) {
    
    
    	if ((pfmt = getenv("ASTERISK_PROMPT"))) {
    
    		char *t = pfmt;
    		struct timeval ts = ast_tvnow();
    		while (*t != '\0') {
    
    				char hostname[MAXHOSTNAMELEN] = "";
    				int i, which;
    
    				int fgcolor = COLOR_WHITE, bgcolor = COLOR_BLACK;
    
    
    Tilghman Lesher's avatar
    Tilghman Lesher committed
    					if (sscanf(t, "%30d;%30d%n", &fgcolor, &bgcolor, &i) == 2) {
    
    						ast_term_color_code(&prompt, fgcolor, bgcolor);
    
    Tilghman Lesher's avatar
    Tilghman Lesher committed
    					} else if (sscanf(t, "%30d%n", &fgcolor, &i) == 1) {