Skip to content
Snippets Groups Projects
asterisk.c 136 KiB
Newer Older
  • Learn to ignore specific revisions
  • 						ast_term_color_code(&prompt, fgcolor, 0);
    
    					/* If the color has been reset correctly, then there's no need to reset it later */
    
    Olle Johansson's avatar
    Olle Johansson committed
    					color_used = ((fgcolor == COLOR_WHITE) && (bgcolor == COLOR_BLACK)) ? 0 : 1;
    
    					if (ast_localtime(&ts, &tm, NULL)) {
    						ast_strftime(tmp, sizeof(tmp), "%Y-%m-%d", &tm);
    						ast_str_append(&prompt, 0, "%s", tmp);
    						cli_prompt_changes++;
    					}
    					break;
    				case 'g': /* group */
    					if ((gr = getgrgid(getgid()))) {
    						ast_str_append(&prompt, 0, "%s", gr->gr_name);
    					}
    
    					if (!gethostname(hostname, sizeof(hostname) - 1)) {
    						ast_str_append(&prompt, 0, "%s", hostname);
    					} else {
    						ast_str_append(&prompt, 0, "%s", "localhost");
    					}
    
    					break;
    				case 'H': /* short hostname */
    					if (!gethostname(hostname, sizeof(hostname) - 1)) {
    
    						char *dotptr;
    						if ((dotptr = strchr(hostname, '.'))) {
    							*dotptr = '\0';
    
    						ast_str_append(&prompt, 0, "%s", hostname);
    					} else {
    						ast_str_append(&prompt, 0, "%s", "localhost");
    					}
    
    Tilghman Lesher's avatar
    Tilghman Lesher committed
    					if (sscanf(t, "%30d", &which) == 1 && which > 0 && which <= 3) {
    
    						double list[3];
    						getloadavg(list, 3);
    						ast_str_append(&prompt, 0, "%.2f", list[which - 1]);
    						cli_prompt_changes++;
    
    				case 's': /* Asterisk system name (from asterisk.conf) */
    
    					ast_str_append(&prompt, 0, "%s", ast_config_AST_SYSTEM_NAME);
    
    					if (ast_localtime(&ts, &tm, NULL)) {
    						ast_strftime(tmp, sizeof(tmp), "%H:%M:%S", &tm);
    						ast_str_append(&prompt, 0, "%s", tmp);
    						cli_prompt_changes++;
    					}
    					break;
    				case 'u': /* username */
    					if ((pw = getpwuid(getuid()))) {
    						ast_str_append(&prompt, 0, "%s", pw->pw_name);
    					}
    
    					break;
    				case '#': /* process console or remote? */
    
    					ast_str_append(&prompt, 0, "%c", ast_opt_remote ? '>' : '#');
    
    					ast_str_append(&prompt, 0, "%c", '%');
    
    					break;
    				case '\0': /* % is last character - prevent bug */
    					t--;
    					break;
    
    				ast_str_append(&prompt, 0, "%c", *t);
    
    		if (color_used) {
    			/* Force colors back to normal at end */
    
    			ast_term_color_code(&prompt, 0, 0);
    
    		ast_str_set(&prompt, 0, "%s%s",
    			remotehostname ? remotehostname : "",
    			ASTERISK_PROMPT);
    
    	return ast_str_buffer(prompt);
    
    static struct ast_vector_string *ast_el_strtoarr(char *buf)
    
    Mark Spencer's avatar
    Mark Spencer committed
    {
    
    	char *bestmatch;
    
    	struct ast_vector_string *vec = ast_calloc(1, sizeof(*vec));
    
    	if (!vec) {
    		return NULL;
    	}
    
    	/* bestmatch must not be deduplicated */
    	bestmatch = strsep(&buf, " ");
    	if (!bestmatch || !strcmp(bestmatch, AST_CLI_COMPLETE_EOF)) {
    		goto vector_cleanup;
    	}
    
    
    	while ((retstr = strsep(&buf, " "))) {
    		if (!strcmp(retstr, AST_CLI_COMPLETE_EOF)) {
    
    		/* Older daemons sent duplicates. */
    
    		if (AST_VECTOR_GET_CMP(vec, retstr, !strcasecmp)) {
    
    		retstr = ast_strdup(retstr);
    
    		/* Older daemons sent unsorted. */
    		if (!retstr || AST_VECTOR_ADD_SORTED(vec, retstr, strcasecmp)) {
    
    			ast_free(retstr);
    			goto vector_cleanup;
    
    	bestmatch = ast_strdup(bestmatch);
    	if (!bestmatch || AST_VECTOR_INSERT_AT(vec, 0, bestmatch)) {
    		ast_free(bestmatch);
    
    
    vector_cleanup:
    	AST_VECTOR_CALLBACK_VOID(vec, ast_free);
    	AST_VECTOR_PTR_FREE(vec);
    
    	return NULL;
    
    static void ast_cli_display_match_list(struct ast_vector_string *matches, int max)
    
    Mark Spencer's avatar
    Mark Spencer committed
    {
    
    Mark Spencer's avatar
    Mark Spencer committed
    	/* find out how many entries can be put on one line, with two spaces between strings */
    
    	int limit = ast_get_termcols(STDOUT_FILENO) / (max + 2);
    
    	if (limit == 0) {
    		limit = 1;
    	}
    
    	for (;;) {
    		int numoutputline;
    
    		for (numoutputline = 0; numoutputline < limit && idx < AST_VECTOR_SIZE(matches); idx++) {
    
    			numoutputline++;
    
    			fprintf(stdout, "%-*s  ", max, AST_VECTOR_GET(matches, idx));
    
    		if (!numoutputline) {
    			break;
    		}
    
    		fprintf(stdout, "\n");
    	}
    
    static char *cli_complete(EditLine *editline, int ch)
    
    Mark Spencer's avatar
    Mark Spencer committed
    {
    
    Mark Spencer's avatar
    Mark Spencer committed
    	char *ptr;
    
    	struct ast_vector_string *matches;
    
    Mark Spencer's avatar
    Mark Spencer committed
    	int retval = CC_ERROR;
    
    	char savechr;
    
    Mark Spencer's avatar
    Mark Spencer committed
    	int res;
    
    	LineInfo *lf = (LineInfo *)el_line(editline);
    
    	savechr = *(char *)lf->cursor;
    
    	*(char *)lf->cursor = '\0';
    
    	ptr = (char *)lf->cursor;
    
    Mark Spencer's avatar
    Mark Spencer committed
    	if (ptr) {
    		while (ptr > lf->buffer) {
    			if (isspace(*ptr)) {
    				ptr++;
    				break;
    			}
    			ptr--;
    		}
    	}
    
    	len = lf->cursor - ptr;
    
    
    #define CMD_MATCHESARRAY "_COMMAND MATCHESARRAY \"%s\" \"%s\""
    		char *mbuf;
    		char *new_mbuf;
    		int mlen = 0, maxmbuf = 2048;
    
    		/* Start with a 2048 byte buffer */
    		mbuf = ast_malloc(maxmbuf);
    
    		/* This will run snprintf twice at most. */
    		while (mbuf && (mlen = snprintf(mbuf, maxmbuf, CMD_MATCHESARRAY, lf->buffer, ptr)) > maxmbuf) {
    			/* Return value does not include space for NULL terminator. */
    			maxmbuf = mlen + 1;
    			ast_free(mbuf);
    			mbuf = ast_malloc(maxmbuf);
    
    
    		if (!mbuf) {
    			*((char *) lf->cursor) = savechr;
    
    			return (char *)(CC_ERROR);
    		}
    
    		fdsend(ast_consock, mbuf);
    		res = 0;
    		mlen = 0;
    		mbuf[0] = '\0';
    
    		while (!strstr(mbuf, AST_CLI_COMPLETE_EOF) && res != -1) {
    			if (mlen + 1024 > maxmbuf) {
    				/* Expand buffer to the next 1024 byte increment. */
    				maxmbuf = mlen + 1024;
    				new_mbuf = ast_realloc(mbuf, maxmbuf);
    				if (!new_mbuf) {
    					ast_free(mbuf);
    					*((char *) lf->cursor) = savechr;
    
    					return (char *)(CC_ERROR);
    
    				mbuf = new_mbuf;
    			}
    			/* Only read 1024 bytes at a time */
    			res = read(ast_consock, mbuf + mlen, 1024);
    			if (res > 0) {
    				mlen += res;
    
    		}
    		mbuf[mlen] = '\0';
    
    		matches = ast_el_strtoarr(mbuf);
    		ast_free(mbuf);
    
    		matches = ast_cli_completion_vector((char *)lf->buffer, ptr);
    
    Mark Spencer's avatar
    Mark Spencer committed
    	}
    
    	if (matches) {
    		int i;
    
    		int maxlen, match_len;
    
    		const char *best_match = AST_VECTOR_GET(matches, 0);
    
    		if (!ast_strlen_zero(best_match)) {
    
    			el_insertstr(editline, best_match);
    
    Mark Spencer's avatar
    Mark Spencer committed
    			retval = CC_REFRESH;
    		}
    
    
    		if (AST_VECTOR_SIZE(matches) == 2) {
    
    Mark Spencer's avatar
    Mark Spencer committed
    			/* Found an exact match */
    
    Mark Spencer's avatar
    Mark Spencer committed
    			retval = CC_REFRESH;
    		} else {
    			/* Must be more than one match */
    
    			for (i = 1, maxlen = 0; i < AST_VECTOR_SIZE(matches); i++) {
    				match_len = strlen(AST_VECTOR_GET(matches, i));
    
    				if (match_len > maxlen) {
    
    Mark Spencer's avatar
    Mark Spencer committed
    					maxlen = match_len;
    
    Mark Spencer's avatar
    Mark Spencer committed
    			}
    
    
    			fprintf(stdout, "\n");
    			ast_cli_display_match_list(matches, maxlen);
    			retval = CC_REDISPLAY;
    
    Mark Spencer's avatar
    Mark Spencer committed
    		}
    
    		AST_VECTOR_CALLBACK_VOID(matches, ast_free);
    		AST_VECTOR_PTR_FREE(matches);
    
    	return (char *)(long)retval;
    
    Mark Spencer's avatar
    Mark Spencer committed
    }
    
    static int ast_el_initialize(void)
    {
    	HistEvent ev;
    
    	char *editor, *editrc = getenv("EDITRC");
    
    	if (!(editor = getenv("AST_EDITMODE"))) {
    		if (!(editor = getenv("AST_EDITOR"))) {
    			editor = "emacs";
    		}
    	}
    
    Mark Spencer's avatar
    Mark Spencer committed
    
    	if (el != NULL)
    		el_end(el);
    	if (el_hist != NULL)
    		history_end(el_hist);
    
    	el = el_init("asterisk", stdin, stdout, stderr);
    	el_set(el, EL_PROMPT, cli_prompt);
    
    
    	el_set(el, EL_EDITMODE, 1);
    
    Mark Spencer's avatar
    Mark Spencer committed
    	el_hist = history_init();
    	if (!el || !el_hist)
    		return -1;
    
    	/* setup history with 100 entries */
    	history(el_hist, &ev, H_SETSIZE, 100);
    
    	el_set(el, EL_HIST, history, el_hist);
    
    	el_set(el, EL_ADDFN, "ed-complete", "Complete argument", cli_complete);
    	/* Bind <tab> to command completion */
    	el_set(el, EL_BIND, "^I", "ed-complete", NULL);
    	/* Bind ? to command completion */
    	el_set(el, EL_BIND, "?", "ed-complete", NULL);
    
    	/* Bind ^D to redisplay */
    	el_set(el, EL_BIND, "^D", "ed-redisplay", NULL);
    
    	/* Bind Delete to delete char left */
    	el_set(el, EL_BIND, "\\e[3~", "ed-delete-next-char", NULL);
    	/* Bind Home and End to move to line start and end */
    	el_set(el, EL_BIND, "\\e[1~", "ed-move-to-beg", NULL);
    	el_set(el, EL_BIND, "\\e[4~", "ed-move-to-end", NULL);
    	/* Bind C-left and C-right to move by word (not all terminals) */
    	el_set(el, EL_BIND, "\\eOC", "vi-next-word", NULL);
    	el_set(el, EL_BIND, "\\eOD", "vi-prev-word", NULL);
    
    	if (editrc) {
    		el_source(el, editrc);
    	}
    
    #define MAX_HISTORY_COMMAND_LENGTH 256
    
    
    static int ast_el_add_history(const char *buf)
    
    Mark Spencer's avatar
    Mark Spencer committed
    {
    	HistEvent ev;
    
    	if (el_hist == NULL || el == NULL) {
    
    Mark Spencer's avatar
    Mark Spencer committed
    		ast_el_initialize();
    
    	}
    	if (strlen(buf) > (MAX_HISTORY_COMMAND_LENGTH - 1)) {
    		return 0;
    	}
    
    	stripped_buf = ast_strip(ast_strdupa(buf));
    
    	/* HISTCONTROL=ignoredups */
    	if (!history(el_hist, &ev, H_FIRST) && strcmp(ev.str, stripped_buf) == 0) {
    
    	}
    
    	return history(el_hist, &ev, H_ENTER, stripped_buf);
    
    static int ast_el_write_history(const char *filename)
    
    Mark Spencer's avatar
    Mark Spencer committed
    {
    	HistEvent ev;
    
    	if (el_hist == NULL || el == NULL)
    		ast_el_initialize();
    
    	return (history(el_hist, &ev, H_SAVE, filename));
    }
    
    
    static int ast_el_read_history(const char *filename)
    
    Mark Spencer's avatar
    Mark Spencer committed
    {
    
    	if (el_hist == NULL || el == NULL) {
    
    Mark Spencer's avatar
    Mark Spencer committed
    		ast_el_initialize();
    	}
    
    
    	return history(el_hist, &ev, H_LOAD, filename);
    
    static void ast_el_read_default_histfile(void)
    {
    	char histfile[80] = "";
    	const char *home = getenv("HOME");
    
    	if (!ast_strlen_zero(home)) {
    		snprintf(histfile, sizeof(histfile), "%s/.asterisk_history", home);
    		ast_el_read_history(histfile);
    	}
    }
    
    static void ast_el_write_default_histfile(void)
    {
    	char histfile[80] = "";
    	const char *home = getenv("HOME");
    
    	if (!ast_strlen_zero(home)) {
    		snprintf(histfile, sizeof(histfile), "%s/.asterisk_history", home);
    		ast_el_write_history(histfile);
    	}
    }
    
    
    static void ast_remotecontrol(char *data)
    
    Mark Spencer's avatar
    Mark Spencer committed
    {
    
    Mark Spencer's avatar
    Mark Spencer committed
    	int res;
    	char *hostname;
    	char *cpid;
    	char *version;
    	int pid;
    
    Mark Spencer's avatar
    Mark Spencer committed
    
    	char *ebuf;
    	int num = 0;
    
    
    	ast_term_init();
    	printf("%s", term_end());
    	fflush(stdout);
    
    
    	memset(&sig_flags, 0, sizeof(sig_flags));
    	signal(SIGINT, __remote_quit_handler);
    	signal(SIGTERM, __remote_quit_handler);
    	signal(SIGHUP, __remote_quit_handler);
    
    
    	if (read(ast_consock, buf, sizeof(buf) - 1) < 0) {
    
    		ast_log(LOG_ERROR, "read() failed: %s\n", strerror(errno));
    		return;
    	}
    
    	if (data) {
    		char prefix[] = "cli quit after ";
    
    		char *tmp = ast_alloca(strlen(data) + strlen(prefix) + 1);
    
    		sprintf(tmp, "%s%s", prefix, data);
    
    		if (write(ast_consock, tmp, strlen(tmp) + 1) < 0) {
    			ast_log(LOG_ERROR, "write() failed: %s\n", strerror(errno));
    
    			if (sig_flags.need_quit || sig_flags.need_quit_handler) {
    
    Mark Spencer's avatar
    Mark Spencer committed
    	hostname = strsep(&stringp, "/");
    	cpid = strsep(&stringp, "/");
    
    Mark Spencer's avatar
    Mark Spencer committed
    	version = strsep(&stringp, "\n");
    
    Mark Spencer's avatar
    Mark Spencer committed
    	if (!version)
    		version = "<Version Unknown>";
    
    Mark Spencer's avatar
    Mark Spencer committed
    	strsep(&stringp, ".");
    
    Mark Spencer's avatar
    Mark Spencer committed
    	if (cpid)
    		pid = atoi(cpid);
    	else
    		pid = -1;
    
    		send_rasterisk_connect_commands();
    
    	if (ast_opt_exec && data) {  /* hack to print output then exit if asterisk -rx is used */
    
    		int linefull = 1, prev_linefull = 1, prev_line_verbose = 0;
    
    		struct pollfd fds;
    		fds.fd = ast_consock;
    		fds.events = POLLIN;
    		fds.revents = 0;
    
    		while (ast_poll(&fds, 1, 60000) > 0) {
    
    			char buffer[512] = "", *curline = buffer, *nextline;
    
    			if (sig_flags.need_quit || sig_flags.need_quit_handler) {
    
    			if (read(ast_consock, buffer, sizeof(buffer) - 1) <= 0) {
    
    				prev_linefull = linefull;
    
    				if ((nextline = strchr(curline, '\n'))) {
    
    					linefull = 1;
    
    					linefull = 0;
    
    					nextline = strchr(curline, '\0');
    				}
    
    				/* Skip verbose lines */
    
    				/* Prev line full? | Line is verbose | Last line verbose? | Print
    				 * TRUE            | TRUE*           | TRUE               | FALSE
    				 * TRUE            | TRUE*           | FALSE              | FALSE
    				 * TRUE            | FALSE*          | TRUE               | TRUE
    				 * TRUE            | FALSE*          | FALSE              | TRUE
    				 * FALSE           | TRUE            | TRUE*              | FALSE
    				 * FALSE           | TRUE            | FALSE*             | TRUE
    				 * FALSE           | FALSE           | TRUE*              | FALSE
    				 * FALSE           | FALSE           | FALSE*             | TRUE
    				 */
    				if ((!prev_linefull && !prev_line_verbose) || (prev_linefull && *curline > 0)) {
    					prev_line_verbose = 0;
    
    					if (write(STDOUT_FILENO, curline, nextline - curline) < 0) {
    						ast_log(LOG_WARNING, "write() failed: %s\n", strerror(errno));
    					}
    
    				} else {
    					prev_line_verbose = 1;
    
    				}
    				curline = nextline;
    			} while (!ast_strlen_zero(curline));
    
    
    			/* No non-verbose output in 60 seconds. */
    
    Mark Spencer's avatar
    Mark Spencer committed
    		return;
    	}
    
    
    	ast_verbose("Connected to Asterisk %s currently running on %s (pid = %d)\n", version, hostname, pid);
    	remotehostname = hostname;
    	if (el_hist == NULL || el == NULL)
    		ast_el_initialize();
    
    	ast_el_read_default_histfile();
    
    
    	el_set(el, EL_GETCFN, ast_el_read_char);
    
    
    Mark Spencer's avatar
    Mark Spencer committed
    		ebuf = (char *)el_gets(el, &num);
    
    
    		if (sig_flags.need_quit || sig_flags.need_quit_handler) {
    
    		if (!ebuf && write(1, "", 1) < 0)
    			break;
    
    
    Mark Spencer's avatar
    Mark Spencer committed
    			if (ebuf[strlen(ebuf)-1] == '\n')
    				ebuf[strlen(ebuf)-1] = '\0';
    			if (!remoteconsolehandler(ebuf)) {
    				res = write(ast_consock, ebuf, strlen(ebuf) + 1);
    
    Mark Spencer's avatar
    Mark Spencer committed
    				if (res < 1) {
    					ast_log(LOG_WARNING, "Unable to write: %s\n", strerror(errno));
    					break;
    				}
    			}
    		}
    	}
    	printf("\nDisconnected from Asterisk server\n");
    }
    
    
    Mark Spencer's avatar
    Mark Spencer committed
    static int show_version(void)
    {
    
    	printf("Asterisk %s\n", ast_get_version());
    
    Mark Spencer's avatar
    Mark Spencer committed
    	return 0;
    }
    
    
    	printf("Asterisk %s, Copyright (C) 1999 - 2014, Digium, Inc. and others.\n", ast_get_version());
    
    Mark Spencer's avatar
    Mark Spencer committed
    	printf("Usage: asterisk [OPTIONS]\n");
    	printf("Valid Options:\n");
    
    Mark Spencer's avatar
    Mark Spencer committed
    	printf("   -V              Display version number and exit\n");
    
    	printf("   -C <configfile> Use an alternate configuration file\n");
    
    	printf("   -G <group>      Run as a group other than the caller\n");
    	printf("   -U <user>       Run as a user other than the caller\n");
    
    	printf("   -c              Provide console CLI\n");
    	printf("   -d              Enable extra debugging\n");
    
    	printf("   -f              Do not fork\n");
    
    	printf("   -g              Dump core in case of a crash\n");
    	printf("   -h              This help screen\n");
    
    	printf("   -i              Initialize crypto keys at startup\n");
    
    	printf("   -L <load>       Limit the maximum load average before rejecting new calls\n");
    	printf("   -M <value>      Limit the maximum number of calls to the specified value\n");
    
    	printf("   -m              Mute debugging and console output on the console\n");
    
    	printf("   -n              Disable console colorization\n");
    	printf("   -p              Run as pseudo-realtime thread\n");
    
    	printf("   -q              Quiet mode (suppress output)\n");
    
    	printf("   -r              Connect to Asterisk on this machine\n");
    
    	printf("   -R              Same as -r, except attempt to reconnect if disconnected\n");
    
    	printf("   -s <socket>     Connect to Asterisk via socket <socket> (only valid with -r)\n");
    
    	printf("   -t              Record soundfiles in /var/tmp and move them where they\n");
    	printf("                   belong after they are done\n");
    	printf("   -T              Display the time in [Mmm dd hh:mm:ss] format for each line\n");
    	printf("                   of output to the CLI\n");
    
    	printf("   -v              Increase verbosity (multiple v's = more verbose)\n");
    
    	printf("   -x <cmd>        Execute command <cmd> (implies -r)\n");
    
    	printf("   -X              Execute includes by default (allows #exec in asterisk.conf)\n");
    
    	printf("   -W              Adjust terminal colors to compensate for a light background\n");
    
    Mark Spencer's avatar
    Mark Spencer committed
    	printf("\n");
    	return 0;
    }
    
    
    static void ast_readconfig(void)
    
    Mark Spencer's avatar
    Mark Spencer committed
    	struct ast_config *cfg;
    	struct ast_variable *v;
    
    	char *config = DEFAULT_CONFIG_FILE;
    
    	char hostname[MAXHOSTNAMELEN] = "";
    
    	struct ast_flags config_flags = { CONFIG_FLAG_NOREALTIME };
    
    	struct {
    		unsigned int dbdir:1;
    		unsigned int keydir:1;
    	} found = { 0, 0 };
    
    	/* Default to false for security */
    	int live_dangerously = 0;
    
    	/* Set default value */
    	option_dtmfminduration = AST_MIN_DTMF_DURATION;
    
    	ast_option_rtpptdynamic = AST_RTP_PT_FIRST_DYNAMIC;
    
    		cfg = ast_config_load2(ast_config_AST_CONFIG_FILE, "" /* core, can't reload */, config_flags);
    
    		if (cfg == CONFIG_STATUS_FILEMISSING || cfg == CONFIG_STATUS_FILEUNCHANGED || cfg == CONFIG_STATUS_FILEINVALID) {
    			fprintf(stderr, "Unable to open specified master config file '%s', using built-in defaults\n", ast_config_AST_CONFIG_FILE);
    		}
    	} else {
    
    		cfg = ast_config_load2(config, "" /* core, can't reload */, config_flags);
    
    Mark Spencer's avatar
    Mark Spencer committed
    
    	/* init with buildtime config */
    
    	ast_copy_string(cfg_paths.config_dir, DEFAULT_CONFIG_DIR, sizeof(cfg_paths.config_dir));
    	ast_copy_string(cfg_paths.spool_dir, DEFAULT_SPOOL_DIR, sizeof(cfg_paths.spool_dir));
    	ast_copy_string(cfg_paths.module_dir, DEFAULT_MODULE_DIR, sizeof(cfg_paths.module_dir));
    
    	ast_copy_string(cfg_paths.monitor_dir, DEFAULT_MONITOR_DIR, sizeof(cfg_paths.monitor_dir));
    	ast_copy_string(cfg_paths.recording_dir, DEFAULT_RECORDING_DIR, sizeof(cfg_paths.recording_dir));
    
    	ast_copy_string(cfg_paths.var_dir, DEFAULT_VAR_DIR, sizeof(cfg_paths.var_dir));
    	ast_copy_string(cfg_paths.data_dir, DEFAULT_DATA_DIR, sizeof(cfg_paths.data_dir));
    	ast_copy_string(cfg_paths.log_dir, DEFAULT_LOG_DIR, sizeof(cfg_paths.log_dir));
    	ast_copy_string(cfg_paths.agi_dir, DEFAULT_AGI_DIR, sizeof(cfg_paths.agi_dir));
    	ast_copy_string(cfg_paths.db_path, DEFAULT_DB, sizeof(cfg_paths.db_path));
    
    	ast_copy_string(cfg_paths.sbin_dir, DEFAULT_SBIN_DIR, sizeof(cfg_paths.sbin_dir));
    
    	ast_copy_string(cfg_paths.key_dir, DEFAULT_KEY_DIR, sizeof(cfg_paths.key_dir));
    	ast_copy_string(cfg_paths.pid_path, DEFAULT_PID, sizeof(cfg_paths.pid_path));
    	ast_copy_string(cfg_paths.socket_path, DEFAULT_SOCKET, sizeof(cfg_paths.socket_path));
    	ast_copy_string(cfg_paths.run_dir, DEFAULT_RUN_DIR, sizeof(cfg_paths.run_dir));
    
    	ast_set_default_eid(&ast_eid_default);
    
    Mark Spencer's avatar
    Mark Spencer committed
    	/* no asterisk.conf? no problem, use buildtime config! */
    
    	if (cfg == CONFIG_STATUS_FILEMISSING || cfg == CONFIG_STATUS_FILEUNCHANGED || cfg == CONFIG_STATUS_FILEINVALID) {
    
    James Golovich's avatar
    James Golovich committed
    		return;
    
    Mark Spencer's avatar
    Mark Spencer committed
    	}
    
    
    	for (v = ast_variable_browse(cfg, "files"); v; v = v->next) {
    
    Olle Johansson's avatar
    Olle Johansson committed
    		if (!strcasecmp(v->name, "astctlpermissions"))
    
    			ast_copy_string(ast_config_AST_CTL_PERMISSIONS, v->value, sizeof(ast_config_AST_CTL_PERMISSIONS));
    
    Olle Johansson's avatar
    Olle Johansson committed
    		else if (!strcasecmp(v->name, "astctlowner"))
    
    			ast_copy_string(ast_config_AST_CTL_OWNER, v->value, sizeof(ast_config_AST_CTL_OWNER));
    
    Olle Johansson's avatar
    Olle Johansson committed
    		else if (!strcasecmp(v->name, "astctlgroup"))
    
    			ast_copy_string(ast_config_AST_CTL_GROUP, v->value, sizeof(ast_config_AST_CTL_GROUP));
    
    Olle Johansson's avatar
    Olle Johansson committed
    		else if (!strcasecmp(v->name, "astctl"))
    
    			ast_copy_string(ast_config_AST_CTL, v->value, sizeof(ast_config_AST_CTL));
    
    
    	for (v = ast_variable_browse(cfg, "directories"); v; v = v->next) {
    
    Mark Spencer's avatar
    Mark Spencer committed
    		if (!strcasecmp(v->name, "astetcdir")) {
    
    			ast_copy_string(cfg_paths.config_dir, v->value, sizeof(cfg_paths.config_dir));
    
    Mark Spencer's avatar
    Mark Spencer committed
    		} else if (!strcasecmp(v->name, "astspooldir")) {
    
    			ast_copy_string(cfg_paths.spool_dir, v->value, sizeof(cfg_paths.spool_dir));
    
    			snprintf(cfg_paths.monitor_dir, sizeof(cfg_paths.monitor_dir), "%s/monitor", v->value);
    
    			snprintf(cfg_paths.recording_dir, sizeof(cfg_paths.recording_dir), "%s/recording", v->value);
    
    Mark Spencer's avatar
    Mark Spencer committed
    		} else if (!strcasecmp(v->name, "astvarlibdir")) {
    
    			ast_copy_string(cfg_paths.var_dir, v->value, sizeof(cfg_paths.var_dir));
    
    				snprintf(cfg_paths.db_path, sizeof(cfg_paths.db_path), "%s/astdb", v->value);
    
    		} else if (!strcasecmp(v->name, "astdbdir")) {
    
    			snprintf(cfg_paths.db_path, sizeof(cfg_paths.db_path), "%s/astdb", v->value);
    
    			ast_copy_string(cfg_paths.data_dir, v->value, sizeof(cfg_paths.data_dir));
    
    				snprintf(cfg_paths.key_dir, sizeof(cfg_paths.key_dir), "%s/keys", v->value);
    
    		} else if (!strcasecmp(v->name, "astkeydir")) {
    
    			snprintf(cfg_paths.key_dir, sizeof(cfg_paths.key_dir), "%s/keys", v->value);
    
    Mark Spencer's avatar
    Mark Spencer committed
    		} else if (!strcasecmp(v->name, "astlogdir")) {
    
    			ast_copy_string(cfg_paths.log_dir, v->value, sizeof(cfg_paths.log_dir));
    
    Mark Spencer's avatar
    Mark Spencer committed
    		} else if (!strcasecmp(v->name, "astagidir")) {
    
    			ast_copy_string(cfg_paths.agi_dir, v->value, sizeof(cfg_paths.agi_dir));
    
    Mark Spencer's avatar
    Mark Spencer committed
    		} else if (!strcasecmp(v->name, "astrundir")) {
    
    			snprintf(cfg_paths.pid_path, sizeof(cfg_paths.pid_path), "%s/%s", v->value, "asterisk.pid");
    			ast_copy_string(cfg_paths.run_dir, v->value, sizeof(cfg_paths.run_dir));
    
    Mark Spencer's avatar
    Mark Spencer committed
    		} else if (!strcasecmp(v->name, "astmoddir")) {
    
    			ast_copy_string(cfg_paths.module_dir, v->value, sizeof(cfg_paths.module_dir));
    
    		} else if (!strcasecmp(v->name, "astsbindir")) {
    			ast_copy_string(cfg_paths.sbin_dir, v->value, sizeof(cfg_paths.sbin_dir));
    
    	/* Combine astrundir and astctl settings. */
    	snprintf(cfg_paths.socket_path, sizeof(cfg_paths.socket_path), "%s/%s",
    		ast_config_AST_RUN_DIR, ast_config_AST_CTL);
    
    
    	for (v = ast_variable_browse(cfg, "options"); v; v = v->next) {
    
    		/* verbose level (-v at startup) */
    
    		if (!strcasecmp(v->name, "verbose")) {
    
    		/* whether or not to force timestamping in CLI verbose output. (-T at startup) */
    
    		} else if (!strcasecmp(v->name, "timestamp")) {
    
    			ast_set2_flag(&ast_options, ast_true(v->value), AST_OPT_FLAG_TIMESTAMP);
    
    		/* whether or not to support #exec in config files */
    
    		} else if (!strcasecmp(v->name, "execincludes")) {
    
    			ast_set2_flag(&ast_options, ast_true(v->value), AST_OPT_FLAG_EXEC_INCLUDES);
    
    Mark Spencer's avatar
    Mark Spencer committed
    		/* debug level (-d at startup) */
    
    		} else if (!strcasecmp(v->name, "debug")) {
    
    Tilghman Lesher's avatar
    Tilghman Lesher committed
    			if (sscanf(v->value, "%30d", &option_debug) != 1) {
    
    				option_debug = ast_true(v->value) ? 1 : 0;
    
    		/* Disable forking (-f at startup) */
    
    		} else if (!strcasecmp(v->name, "nofork")) {
    
    			ast_set2_flag(&ast_options, ast_true(v->value), AST_OPT_FLAG_NO_FORK);
    
    		/* Always fork, even if verbose or debug are enabled (-F at startup) */
    		} else if (!strcasecmp(v->name, "alwaysfork")) {
    			ast_set2_flag(&ast_options, ast_true(v->value), AST_OPT_FLAG_ALWAYS_FORK);
    
    		/* Run quietly (-q at startup ) */
    
    		} else if (!strcasecmp(v->name, "quiet")) {
    
    			ast_set2_flag(&ast_options, ast_true(v->value), AST_OPT_FLAG_QUIET);
    
    		/* Run as console (-c at startup, implies nofork) */
    
    		} else if (!strcasecmp(v->name, "console")) {
    
    			ast_set2_flag(&ast_options, ast_true(v->value), AST_OPT_FLAG_NO_FORK | AST_OPT_FLAG_CONSOLE);
    
    		/* Run with high priority if the O/S permits (-p at startup) */
    
    		} else if (!strcasecmp(v->name, "highpriority")) {
    
    			ast_set2_flag(&ast_options, ast_true(v->value), AST_OPT_FLAG_HIGH_PRIORITY);
    
    		/* Initialize RSA auth keys (IAX2) (-i at startup) */
    
    		} else if (!strcasecmp(v->name, "initcrypto")) {
    
    			ast_set2_flag(&ast_options, ast_true(v->value), AST_OPT_FLAG_INIT_KEYS);
    
    		/* Disable ANSI colors for console (-c at startup) */
    
    		} else if (!strcasecmp(v->name, "nocolor")) {
    
    			ast_set2_flag(&ast_options, ast_true(v->value), AST_OPT_FLAG_NO_COLOR);
    
    		/* Disable some usage warnings for picky people :p */
    		} else if (!strcasecmp(v->name, "dontwarn")) {
    
    			ast_set2_flag(&ast_options, ast_true(v->value), AST_OPT_FLAG_DONT_WARN);
    
    		/* Dump core in case of crash (-g) */
    
    		} else if (!strcasecmp(v->name, "dumpcore")) {
    
    			ast_set2_flag(&ast_options, ast_true(v->value), AST_OPT_FLAG_DUMP_CORE);
    
    		/* Cache recorded sound files to another directory during recording */
    
    		} else if (!strcasecmp(v->name, "cache_record_files")) {
    
    			ast_set2_flag(&ast_options, ast_true(v->value), AST_OPT_FLAG_CACHE_RECORD_FILES);
    
    #if !defined(LOW_MEMORY)
    		/* Cache media frames for performance */
    		} else if (!strcasecmp(v->name, "cache_media_frames")) {
    			ast_set2_flag(&ast_options, ast_true(v->value), AST_OPT_FLAG_CACHE_MEDIA_FRAMES);
    #endif
    
    		/* Specify cache directory */
    
    		}  else if (!strcasecmp(v->name, "record_cache_dir")) {
    
    			ast_copy_string(record_cache_dir, v->value, AST_CACHE_DIR_LEN);
    
    		/* Build transcode paths via SLINEAR, instead of directly */
    		} else if (!strcasecmp(v->name, "transcode_via_sln")) {
    
    			ast_set2_flag(&ast_options, ast_true(v->value), AST_OPT_FLAG_TRANSCODE_VIA_SLIN);
    
    		/* Transmit SLINEAR silence while a channel is being recorded or DTMF is being generated on a channel */
    		} else if (!strcasecmp(v->name, "transmit_silence_during_record") || !strcasecmp(v->name, "transmit_silence")) {
    
    			ast_set2_flag(&ast_options, ast_true(v->value), AST_OPT_FLAG_TRANSMIT_SILENCE);
    
    		/* Enable internal timing */
    		} else if (!strcasecmp(v->name, "internal_timing")) {
    			if (!ast_opt_remote) {
    				fprintf(stderr,
    					"NOTICE: The internal_timing option is no longer needed.\n"
    					"  It will always be enabled if you have a timing module loaded.\n");
    			}
    
    		} else if (!strcasecmp(v->name, "mindtmfduration")) {
    			if (sscanf(v->value, "%30u", &option_dtmfminduration) != 1) {
    				option_dtmfminduration = AST_MIN_DTMF_DURATION;
    			}
    
    		/* http://www.iana.org/assignments/rtp-parameters
    		 * RTP dynamic payload types start at 96 normally; extend down to 0 */
    		} else if (!strcasecmp(v->name, "rtp_pt_dynamic")) {
    			ast_parse_arg(v->value, PARSE_UINT32|PARSE_IN_RANGE|PARSE_DEFAULT,
    			              &ast_option_rtpptdynamic, AST_RTP_PT_FIRST_DYNAMIC,
    			              0, AST_RTP_PT_LAST_REASSIGN);
    
    Mark Spencer's avatar
    Mark Spencer committed
    		} else if (!strcasecmp(v->name, "maxcalls")) {
    
    			if ((sscanf(v->value, "%30d", &ast_option_maxcalls) != 1) || (ast_option_maxcalls < 0)) {
    				ast_option_maxcalls = 0;
    
    		} else if (!strcasecmp(v->name, "maxload")) {
    
    			double test[1];
    
    			if (getloadavg(test, 1) == -1) {
    				ast_log(LOG_ERROR, "Cannot obtain load average on this system. 'maxload' option disabled.\n");
    
    				ast_option_maxload = 0.0;
    			} else if ((sscanf(v->value, "%30lf", &ast_option_maxload) != 1) || (ast_option_maxload < 0.0)) {
    				ast_option_maxload = 0.0;
    
    		/* Set the maximum amount of open files */
    		} else if (!strcasecmp(v->name, "maxfiles")) {
    
    			ast_option_maxfiles = atoi(v->value);
    
    			if (!ast_opt_remote) {
    				set_ulimit(ast_option_maxfiles);
    			}
    
    Kevin P. Fleming's avatar
    Kevin P. Fleming committed
    		/* What user to run as */
    		} else if (!strcasecmp(v->name, "runuser")) {
    
    			ast_copy_string(cfg_paths.run_user, v->value, sizeof(cfg_paths.run_user));
    
    Kevin P. Fleming's avatar
    Kevin P. Fleming committed
    		/* What group to run as */
    		} else if (!strcasecmp(v->name, "rungroup")) {
    
    			ast_copy_string(cfg_paths.run_group, v->value, sizeof(cfg_paths.run_group));
    
    		} else if (!strcasecmp(v->name, "systemname")) {
    
    			ast_copy_string(cfg_paths.system_name, v->value, sizeof(cfg_paths.system_name));
    
    		} else if (!strcasecmp(v->name, "autosystemname")) {
    			if (ast_true(v->value)) {
    				if (!gethostname(hostname, sizeof(hostname) - 1))
    
    					ast_copy_string(cfg_paths.system_name, hostname, sizeof(cfg_paths.system_name));
    
    					if (ast_strlen_zero(ast_config_AST_SYSTEM_NAME)){
    
    						ast_copy_string(cfg_paths.system_name, "localhost", sizeof(cfg_paths.system_name));
    
    					}
    					ast_log(LOG_ERROR, "Cannot obtain hostname for this system.  Using '%s' instead.\n", ast_config_AST_SYSTEM_NAME);
    
    		} else if (!strcasecmp(v->name, "languageprefix")) {
    			ast_language_is_prefix = ast_true(v->value);
    
    		} else if (!strcasecmp(v->name, "defaultlanguage")) {
    
    			ast_copy_string(ast_defaultlanguage, v->value, MAX_LANGUAGE);
    
    		} else if (!strcasecmp(v->name, "lockmode")) {
    			if (!strcasecmp(v->value, "lockfile")) {
    				ast_set_lock_type(AST_LOCK_TYPE_LOCKFILE);
    			} else if (!strcasecmp(v->value, "flock")) {
    				ast_set_lock_type(AST_LOCK_TYPE_FLOCK);
    			} else {
    
    Russell Bryant's avatar
    Russell Bryant committed
    				ast_log(LOG_WARNING, "'%s' is not a valid setting for the lockmode option, "
    					"defaulting to 'lockfile'\n", v->value);
    
    				ast_set_lock_type(AST_LOCK_TYPE_LOCKFILE);
    
    Russell Bryant's avatar
    Russell Bryant committed
    			}
    
    		} else if (!strcasecmp(v->name, "minmemfree")) {
    			/* specify the minimum amount of free memory to retain.  Asterisk should stop accepting new calls
    			 * if the amount of free memory falls below this watermark */
    
    Tilghman Lesher's avatar
    Tilghman Lesher committed
    			if ((sscanf(v->value, "%30ld", &option_minmemfree) != 1) || (option_minmemfree < 0)) {
    
    		} else if (!strcasecmp(v->name, "entityid")) {
    			struct ast_eid tmp_eid;
    			if (!ast_str_to_eid(&tmp_eid, v->value)) {
    
    				ast_eid_default = tmp_eid;
    
    			} else {
    				ast_log(LOG_WARNING, "Invalid Entity ID '%s' provided\n", v->value);
    			}
    
    		} else if (!strcasecmp(v->name, "lightbackground")) {
    			ast_set2_flag(&ast_options, ast_true(v->value), AST_OPT_FLAG_LIGHT_BACKGROUND);
    
    		} else if (!strcasecmp(v->name, "forceblackbackground")) {
    			ast_set2_flag(&ast_options, ast_true(v->value), AST_OPT_FLAG_FORCE_BLACK_BACKGROUND);
    
    		} else if (!strcasecmp(v->name, "hideconnect")) {
    			ast_set2_flag(&ast_options, ast_true(v->value), AST_OPT_FLAG_HIDE_CONSOLE_CONNECT);
    
    		} else if (!strcasecmp(v->name, "lockconfdir")) {
    			ast_set2_flag(&ast_options, ast_true(v->value),	AST_OPT_FLAG_LOCK_CONFIG_DIR);
    
    		} else if (!strcasecmp(v->name, "stdexten")) {
    			/* Choose how to invoke the extensions.conf stdexten */
    			if (!strcasecmp(v->value, "gosub")) {
    				ast_clear_flag(&ast_options, AST_OPT_FLAG_STDEXTEN_MACRO);
    			} else if (!strcasecmp(v->value, "macro")) {
    				ast_set_flag(&ast_options, AST_OPT_FLAG_STDEXTEN_MACRO);
    			} else {
    				ast_log(LOG_WARNING,
    					"'%s' is not a valid setting for the stdexten option, defaulting to 'gosub'\n",
    					v->value);
    				ast_clear_flag(&ast_options, AST_OPT_FLAG_STDEXTEN_MACRO);
    			}
    
    		} else if (!strcasecmp(v->name, "live_dangerously")) {
    			live_dangerously = ast_true(v->value);
    
    	if (!ast_opt_remote) {
    		pbx_live_dangerously(live_dangerously);
    	}
    
    	ast_config_destroy(cfg);
    
    static void read_pjproject_startup_options(void)
    {
    	struct ast_config *cfg;
    	struct ast_variable *v;
    	struct ast_flags config_flags = { CONFIG_FLAG_NOCACHE | CONFIG_FLAG_NOREALTIME };
    
    	ast_option_pjproject_log_level = DEFAULT_PJ_LOG_MAX_LEVEL;
    
    	cfg = ast_config_load2("pjproject.conf", "" /* core, can't reload */, config_flags);
    	if (!cfg
    		|| cfg == CONFIG_STATUS_FILEUNCHANGED
    		|| cfg == CONFIG_STATUS_FILEINVALID) {
    		/* We'll have to use defaults */
    		return;
    	}
    
    	for (v = ast_variable_browse(cfg, "startup"); v; v = v->next) {
    		if (!strcasecmp(v->name, "log_level")) {
    			if (sscanf(v->value, "%30d", &ast_option_pjproject_log_level) != 1) {
    				ast_option_pjproject_log_level = DEFAULT_PJ_LOG_MAX_LEVEL;
    			} else if (ast_option_pjproject_log_level < 0) {
    				ast_option_pjproject_log_level = 0;
    			} else if (MAX_PJ_LOG_MAX_LEVEL < ast_option_pjproject_log_level) {
    				ast_option_pjproject_log_level = MAX_PJ_LOG_MAX_LEVEL;
    			}
    		}
    	}
    
    	ast_config_destroy(cfg);
    }
    
    
    static void *monitor_sig_flags(void *unused)
    {
    	for (;;) {
    		struct pollfd p = { sig_alert_pipe[0], POLLIN, 0 };
    		int a;
    
    		ast_poll(&p, 1, -1);
    
    		if (sig_flags.need_reload) {
    			sig_flags.need_reload = 0;
    			ast_module_reload(NULL);
    		}
    		if (sig_flags.need_quit) {
    			sig_flags.need_quit = 0;
    
    			if ((consolethread != AST_PTHREADT_NULL) && (consolethread != pthread_self())) {
    
    				sig_flags.need_quit_handler = 1;
    				pthread_kill(consolethread, SIGURG);
    			} else {
    
    				quit_handler(0, SHUTDOWN_NORMAL, 0);
    
    		if (read(sig_alert_pipe[0], &a, sizeof(a)) != sizeof(a)) {
    		}
    
    static void *canary_thread(void *unused)
    {
    	struct stat canary_stat;
    
    		if (stat(canary_filename, &canary_stat) || now.tv_sec > canary_stat.st_mtime + 60) {
    
    			ast_log(LOG_WARNING,
    				"The canary is no more.  He has ceased to be!  "
    				"He's expired and gone to meet his maker!  "
    				"He's a stiff!  Bereft of life, he rests in peace.  "
    				"His metabolic processes are now history!  He's off the twig!  "
    				"He's kicked the bucket.  He's shuffled off his mortal coil, "
    				"run down the curtain, and joined the bleeding choir invisible!!  "
    				"THIS is an EX-CANARY.  (Reducing priority)\n");
    
    			pthread_exit(NULL);
    		}
    
    		/* Check the canary once a minute */
    		sleep(60);
    	}
    }
    
    /* Used by libc's atexit(3) function */
    static void canary_exit(void)
    {
    
    /* Execute CLI commands on startup.  Run by main() thread. */
    
    	struct ast_config *cfg;
    	struct ast_flags cfg_flags = { 0 };
    	struct ast_variable *v;
    
    	if (!(cfg = ast_config_load2("cli.conf", "" /* core, can't reload */, cfg_flags)))
    
    	if (cfg == CONFIG_STATUS_FILEMISSING || cfg == CONFIG_STATUS_FILEUNCHANGED || cfg == CONFIG_STATUS_FILEINVALID) {
    		return;
    	}
    
    	if (fd < 0) {
    		ast_config_destroy(cfg);
    
    	for (v = ast_variable_browse(cfg, "startup_commands"); v; v = v->next) {
    		if (ast_true(v->value))
    			ast_cli_command(fd, v->name);
    	}