Skip to content
Snippets Groups Projects
asterisk.c 136 KiB
Newer Older
  • Learn to ignore specific revisions
  • 			min = atoi(a->argv[3]); \
    			if (a->argc == 5 && strcmp(a->argv[4], "-")) \
    				max = atoi(a->argv[4]); \
    		} else \
    			search = a->argv[3]; \
    	} \
    	if (max > prof_data->entries) \
    		max = prof_data->entries;
    
    static char *handle_show_profile(struct ast_cli_entry *e, int cmd, struct ast_cli_args *a)
    
    {
    	int i, min, max;
    
    	const char *search = NULL;
    
    	switch (cmd) {
    	case CLI_INIT:
    		e->command = "core show profile";
    		e->usage = "Usage: core show profile\n"
    			   "       show profile information";
    		return NULL;
    	case CLI_GENERATE:
    		return NULL;
    	}
    
    
    	if (prof_data == NULL)
    		return 0;
    
    
    	DEFINE_PROFILE_MIN_MAX_VALUES;
    	ast_cli(a->fd, "profile values (%d, allocated %d)\n-------------------\n",
    
    		prof_data->entries, prof_data->max_size);
    
    	ast_cli(a->fd, "%6s   %8s  %10s %12s %12s  %s\n", "ID", "Scale", "Events",
    
    			"Value", "Average", "Name");
    	for (i = min; i < max; i++) {
    
    		struct profile_entry *entry = &prof_data->e[i];
    
    		if (!search || strstr(entry->name, search))
    
    		    ast_cli(a->fd, "%6d: [%8ld] %10ld %12lld %12lld  %s\n",
    
    			(long)entry->scale,
    			(long)entry->events, (long long)entry->value,
    			(long long)(entry->events ? entry->value / entry->events : entry->value),
    			entry->name);
    
    static char *handle_clear_profile(struct ast_cli_entry *e, int cmd, struct ast_cli_args *a)
    {
    	int i, min, max;
    
    	const char *search = NULL;
    
    	switch (cmd) {
    	case CLI_INIT:
    		e->command = "core clear profile";
    		e->usage = "Usage: core clear profile\n"
    			   "       clear profile information";
    		return NULL;
    	case CLI_GENERATE:
    		return NULL;
    	}
    
    	if (prof_data == NULL)
    		return 0;
    
    	DEFINE_PROFILE_MIN_MAX_VALUES;
    	for (i= min; i < max; i++) {
    		if (!search || strstr(prof_data->e[i].name, search)) {
    			prof_data->e[i].value = 0;
    			prof_data->e[i].events = 0;
    		}
    	}
    	return CLI_SUCCESS;
    }
    #undef DEFINE_PROFILE_MIN_MAX_VALUES
    
    Olle Johansson's avatar
    Olle Johansson committed
    /*! \brief CLI command to list module versions */
    
    static char *handle_show_version_files(struct ast_cli_entry *e, int cmd, struct ast_cli_args *a)
    
    #define FORMAT "%-25.25s %-40.40s\n"
    
    	static const char * const completions[] = { "like", NULL };
    
    	struct registered_file *iterator;
    
    	int havename = 0;
    
    		e->command = "core show file version";
    
    			"Usage: core show file version [<filename>|like <pattern>]\n"
    
    			"       Lists the files along with the Asterisk version.\n"
    
    			"       Optional regular expression pattern is used to filter the file list.\n";
    		return NULL;
    	case CLI_GENERATE:
    
    		ret = ast_cli_complete(a->word, completions, a->n);
    		if (!ret) {
    			ret = ast_complete_source_filename(a->word, a->n - 1);
    		}
    
    		if (!strcasecmp(a->argv[4], "like")) {
    			if (regcomp(&regexbuf, a->argv[5], REG_EXTENDED | REG_NOSUB))
    				return CLI_SHOWUSAGE;
    
    		if (!strcasecmp(a->argv[4], "like")) {
    			return CLI_SHOWUSAGE;
    		}
    
    		havename = 1;
    		break;
    
    	ast_cli(a->fd, FORMAT, "File", "Revision");
    	ast_cli(a->fd, FORMAT, "----", "--------");
    
    	AST_RWLIST_RDLOCK(&registered_files);
    	AST_RWLIST_TRAVERSE(&registered_files, iterator, list) {
    
    		if (havename && strcasecmp(iterator->file, a->argv[4]))
    
    		if (havepattern && regexec(&regexbuf, iterator->file, 0, NULL, 0))
    			continue;
    
    
    		ast_cli(a->fd, FORMAT, iterator->file, ast_get_version());
    
    		if (havename)
    			break;
    
    	AST_RWLIST_UNLOCK(&registered_files);
    
    		ast_cli(a->fd, "%d files listed.\n", count_files);
    
    #endif /* ! LOW_MEMORY */
    
    int ast_pbx_uuid_get(char *pbx_uuid, int length)
    {
    	return ast_db_get("pbx", "UUID", pbx_uuid, length);
    }
    
    
    static void publish_fully_booted(void)
    {
    	RAII_VAR(struct ast_json *, json_object, NULL, ast_json_unref);
    
    	json_object = ast_json_pack("{s: s}",
    			"Status", "Fully Booted");
    
    	ast_manager_publish_event("FullyBooted", EVENT_FLAG_SYSTEM, json_object);
    
    static void ast_run_atexits(int run_cleanups)
    
    {
    	struct ast_atexit *ae;
    
    	AST_LIST_LOCK(&atexits);
    	while ((ae = AST_LIST_REMOVE_HEAD(&atexits, list))) {
    
    		if (ae->func && (!ae->is_cleanup || run_cleanups)) {
    
    			ae->func();
    		}
    		ast_free(ae);
    	}
    	AST_LIST_UNLOCK(&atexits);
    }
    
    static void __ast_unregister_atexit(void (*func)(void))
    {
    	struct ast_atexit *ae;
    
    	AST_LIST_TRAVERSE_SAFE_BEGIN(&atexits, ae, list) {
    		if (ae->func == func) {
    			AST_LIST_REMOVE_CURRENT(list);
    			ast_free(ae);
    			break;
    		}
    	}
    	AST_LIST_TRAVERSE_SAFE_END;
    }
    
    
    static int register_atexit(void (*func)(void), int is_cleanup)
    
    	ae = ast_calloc(1, sizeof(*ae));
    	if (!ae) {
    
    	ae->func = func;
    
    	ae->is_cleanup = is_cleanup;
    
    	AST_LIST_LOCK(&atexits);
    	__ast_unregister_atexit(func);
    	AST_LIST_INSERT_HEAD(&atexits, ae, list);
    	AST_LIST_UNLOCK(&atexits);
    
    int ast_register_atexit(void (*func)(void))
    {
    	return register_atexit(func, 0);
    }
    
    int ast_register_cleanup(void (*func)(void))
    {
    	return register_atexit(func, 1);
    }
    
    
    void ast_unregister_atexit(void (*func)(void))
    {
    
    	AST_LIST_LOCK(&atexits);
    	__ast_unregister_atexit(func);
    	AST_LIST_UNLOCK(&atexits);
    
    /* Sending commands from consoles back to the daemon requires a terminating NULL */
    static int fdsend(int fd, const char *s)
    
    Mark Spencer's avatar
    Mark Spencer committed
    {
    	return write(fd, s, strlen(s) + 1);
    }
    
    
    /* Sending messages from the daemon back to the display requires _excluding_ the terminating NULL */
    static int fdprint(int fd, const char *s)
    {
    	return write(fd, s, strlen(s));
    }
    
    
    Olle Johansson's avatar
    Olle Johansson committed
    /*! \brief NULL handler so we can collect the child exit status */
    
    static void _null_sig_handler(int sig)
    
    static struct sigaction null_sig_handler = {
    	.sa_handler = _null_sig_handler,
    
    	.sa_flags = SA_RESTART,
    
    };
    
    static struct sigaction ignore_sig_handler = {
    	.sa_handler = SIG_IGN,
    };
    
    
    AST_MUTEX_DEFINE_STATIC(safe_system_lock);
    
    Olle Johansson's avatar
    Olle Johansson committed
    /*! \brief Keep track of how many threads are currently trying to wait*() on
    
     *  a child process
     */
    
    static unsigned int safe_system_level = 0;
    
    static struct sigaction safe_system_prev_handler;
    
    	unsigned int level;
    
    	ast_mutex_lock(&safe_system_lock);
    	level = safe_system_level++;
    
    	/* only replace the handler if it has not already been done */
    
    	if (level == 0) {
    		sigaction(SIGCHLD, &null_sig_handler, &safe_system_prev_handler);
    	}
    
    
    	ast_mutex_unlock(&safe_system_lock);
    
    }
    
    void ast_unreplace_sigchld(void)
    {
    	unsigned int level;
    
    	ast_mutex_lock(&safe_system_lock);
    	level = --safe_system_level;
    
    	/* only restore the handler if we are the last one */
    
    	if (level == 0) {
    		sigaction(SIGCHLD, &safe_system_prev_handler, NULL);
    	}
    
    /*! \brief fork and perform other preparations for spawning applications */
    static pid_t safe_exec_prep(int dualfork)
    
    #if defined(HAVE_WORKING_FORK) || defined(HAVE_WORKING_VFORK)
    	ast_replace_sigchld();
    
    #ifdef HAVE_WORKING_FORK
    
    #else
    	pid = vfork();
    
    #ifdef HAVE_CAP
    		cap_t cap = cap_from_text("cap_net_admin-eip");
    
    		if (cap_set_proc(cap)) {
    			/* Careful with order! Logging cannot happen after we close FDs */
    			ast_log(LOG_WARNING, "Unable to remove capabilities.\n");
    		}
    		cap_free(cap);
    #endif
    
    #ifdef HAVE_WORKING_FORK
    
    			ast_set_priority(0);
    
    		/* Close file descriptors and launch system command */
    
    		if (dualfork) {
    #ifdef HAVE_WORKING_FORK
    			pid = fork();
    #else
    			pid = vfork();
    #endif
    			if (pid < 0) {
    				/* Second fork failed. */
    				/* No logger available. */
    				_exit(1);
    			}
    
    			if (pid > 0) {
    				/* This is the first fork, exit so the reaper finishes right away. */
    				_exit(0);
    			}
    
    			/* This is the second fork.  The first fork will exit immediately so
    			 * Asterisk doesn't have to wait for completion.
    			 * ast_safe_system("cmd &") would run in the background, but the '&'
    			 * cannot be added with ast_safe_execvp, so we have to double fork.
    			 */
    		}
    	}
    
    	if (pid < 0) {
    		ast_log(LOG_WARNING, "Fork failed: %s\n", strerror(errno));
    	}
    #else
    	ast_log(LOG_WARNING, "Fork failed: %s\n", strerror(ENOTSUP));
    	pid = -1;
    #endif
    
    	return pid;
    }
    
    /*! \brief wait for spawned application to complete and unreplace sigchld */
    static int safe_exec_wait(pid_t pid)
    {
    	int res = -1;
    
    #if defined(HAVE_WORKING_FORK) || defined(HAVE_WORKING_VFORK)
    	if (pid > 0) {
    
    			res = waitpid(pid, &status, 0);
    
    				res = WIFEXITED(status) ? WEXITSTATUS(status) : -1;
    				break;
    
    Mark Spencer's avatar
    Mark Spencer committed
    				break;
    
    int ast_safe_execvp(int dualfork, const char *file, char *const argv[])
    {
    	pid_t pid = safe_exec_prep(dualfork);
    
    	if (pid == 0) {
    		execvp(file, argv);
    		_exit(1);
    		/* noreturn from _exit */
    	}
    
    	return safe_exec_wait(pid);
    }
    
    int ast_safe_system(const char *s)
    {
    	pid_t pid = safe_exec_prep(0);
    
    	if (pid == 0) {
    		execl("/bin/sh", "/bin/sh", "-c", s, (char *) NULL);
    		_exit(1);
    		/* noreturn from _exit */
    	}
    
    	return safe_exec_wait(pid);
    }
    
    
    /*!
     * \brief enable or disable a logging level to a specified console
     */
    
    void ast_console_toggle_loglevel(int fd, int level, int state)
    {
    	int x;
    
    
    	if (level >= NUMLOGLEVELS) {
    		level = NUMLOGLEVELS - 1;
    	}
    
    
    	for (x = 0;x < AST_MAX_CONNECTS; x++) {
    		if (fd == consoles[x].fd) {
    
    			/*
    			 * Since the logging occurs when levels are false, set to
    			 * flipped iinput because this function accepts 0 as off and 1 as on
    			 */
    			consoles[x].levels[level] = state ? 0 : 1;
    
    Olle Johansson's avatar
    Olle Johansson committed
     * \brief mute or unmute a console from logging
    
    void ast_console_toggle_mute(int fd, int silent)
    {
    
    	for (x = 0;x < AST_MAX_CONNECTS; x++) {
    
    				if (!silent)
    					ast_cli(fd, "Console is not muted anymore.\n");
    
    				if (!silent)
    					ast_cli(fd, "Console is muted.\n");
    
     * \brief log the string to all attached network console clients
    
    static void ast_network_puts_mutable(const char *string, int level)
    
    
    	for (x = 0; x < AST_MAX_CONNECTS; ++x) {
    		if (consoles[x].fd < 0
    			|| consoles[x].mute
    			|| consoles[x].levels[level]) {
    
    		fdprint(consoles[x].p[1], string);
    
     * \brief log the string to the root console, and all attached
     * network console clients
    
    void ast_console_puts_mutable(const char *string, int level)
    
    	/* Send to the root console */
    
    
    	/* Send to any network console clients */
    
    	ast_network_puts_mutable(string, level);
    
    Olle Johansson's avatar
    Olle Johansson committed
     * \brief write the string to all attached console clients
    
     */
    static void ast_network_puts(const char *string)
    {
    
    	int x;
    
    
    	for (x = 0; x < AST_MAX_CONNECTS; ++x) {
    		if (consoles[x].fd < 0) {
    			continue;
    		}
    		fdprint(consoles[x].p[1], string);
    
     * \brief write the string to the root console, and all attached
     * network console clients
    
     */
    void ast_console_puts(const char *string)
    {
    
    	/* Send to the root console */
    
    	fputs(string, stdout);
    	fflush(stdout);
    
    
    	/* Send to any network console clients */
    
    	ast_network_puts(string);
    
    static void network_verboser(const char *string)
    
    	int x;
    	int verb_level;
    
    	/* Send to any network console clients if client verbocity allows. */
    	verb_level = VERBOSE_MAGIC2LEVEL(string);
    	for (x = 0; x < AST_MAX_CONNECTS; ++x) {
    		if (consoles[x].fd < 0
    			|| consoles[x].mute
    			|| consoles[x].levels[__LOG_VERBOSE]
    			|| consoles[x].option_verbose < verb_level) {
    			continue;
    		}
    		fdprint(consoles[x].p[1], string);
    	}
    
    Mark Spencer's avatar
    Mark Spencer committed
    }
    
    static pthread_t lthread;
    
    
    /*!
     * \brief read() function supporting the reception of user credentials.
     *
     * \param fd Socket file descriptor.
     * \param buffer Receive buffer.
     * \param size 'buffer' size.
     * \param con Console structure to set received credentials
     * \retval -1 on error
     * \retval the number of bytes received on success.
     */
    static int read_credentials(int fd, char *buffer, size_t size, struct console *con)
    {
    #if defined(SO_PEERCRED)
    
    #ifdef HAVE_STRUCT_SOCKPEERCRED_UID
    #define HAVE_STRUCT_UCRED_UID
    	struct sockpeercred cred;
    #else
    
    	struct ucred cred;
    
    	socklen_t len = sizeof(cred);
    #endif
    
    #if defined(HAVE_GETPEEREID)
    	uid_t uid;
    	gid_t gid;
    #else
    	int uid, gid;
    #endif
    	int result;
    
    
    	result = read(fd, buffer, size);
    	if (result < 0) {
    		return result;
    	}
    
    
    #if defined(SO_PEERCRED) && (defined(HAVE_STRUCT_UCRED_UID) || defined(HAVE_STRUCT_UCRED_CR_UID))
    
    	if (getsockopt(fd, SOL_SOCKET, SO_PEERCRED, &cred, &len)) {
    		return result;
    	}
    
    #if defined(HAVE_STRUCT_UCRED_UID)
    
    	uid = cred.uid;
    	gid = cred.gid;
    
    #else /* defined(HAVE_STRUCT_UCRED_CR_UID) */
    	uid = cred.cr_uid;
    	gid = cred.cr_gid;
    #endif /* defined(HAVE_STRUCT_UCRED_UID) */
    
    
    #elif defined(HAVE_GETPEEREID)
    	if (getpeereid(fd, &uid, &gid)) {
    		return result;
    	}
    #else
    	return result;
    #endif
    	con->uid = uid;
    	con->gid = gid;
    
    	return result;
    }
    
    
    /* This is the thread running the remote console on the main process. */
    
    Mark Spencer's avatar
    Mark Spencer committed
    static void *netconsole(void *vconsole)
    {
    	struct console *con = vconsole;
    
    	char inbuf[512];
    	char outbuf[512];
    
    	const char * const end_buf = inbuf + sizeof(inbuf);
    
    	char *start_read = inbuf;
    
    Mark Spencer's avatar
    Mark Spencer committed
    	int res;
    
    	if (gethostname(hostname, sizeof(hostname)-1))
    
    		ast_copy_string(hostname, "<Unknown>", sizeof(hostname));
    
    	snprintf(outbuf, sizeof(outbuf), "%s/%ld/%s\n", hostname, (long)ast_mainpid, ast_get_version());
    	fdprint(con->fd, outbuf);
    
    	ast_verb_console_register(&con->option_verbose);
    
    		fds[0].fd = con->fd;
    		fds[0].events = POLLIN;
    
    		fds[1].fd = con->p[0];
    		fds[1].events = POLLIN;
    
    		res = ast_poll(fds, 2, -1);
    
    Mark Spencer's avatar
    Mark Spencer committed
    		if (res < 0) {
    
    Mark Spencer's avatar
    Mark Spencer committed
    			if (errno != EINTR)
    				ast_log(LOG_WARNING, "poll returned < 0: %s\n", strerror(errno));
    
    Mark Spencer's avatar
    Mark Spencer committed
    			continue;
    		}
    
    			int cmds_read, bytes_read;
    			if ((bytes_read = read_credentials(con->fd, start_read, end_buf - start_read, con)) < 1) {
    
    Mark Spencer's avatar
    Mark Spencer committed
    				break;
    
    Mark Spencer's avatar
    Mark Spencer committed
    			}
    
    			/* XXX This will only work if it is the first command, and I'm not sure fixing it is worth the effort. */
    			if (strncmp(inbuf, "cli quit after ", 15) == 0) {
    				ast_cli_command_multiple_full(con->uid, con->gid, con->fd, bytes_read - 15, inbuf + 15);
    
    			/* ast_cli_command_multiple_full will only process individual commands terminated by a
    			 * NULL and not trailing partial commands. */
    			if (!(cmds_read = ast_cli_command_multiple_full(con->uid, con->gid, con->fd, bytes_read + start_read - inbuf, inbuf))) {
    				/* No commands were read. We either have a short read on the first command
    				 * with space left, or a command that is too long */
    				if (start_read + bytes_read < end_buf) {
    					start_read += bytes_read;
    				} else {
    					ast_log(LOG_ERROR, "Command too long! Skipping\n");
    					start_read = inbuf;
    				}
    				continue;
    			}
    			if (start_read[bytes_read - 1] == '\0') {
    				/* The read ended on a command boundary, start reading again at the head of inbuf */
    				start_read = inbuf;
    				continue;
    			}
    			/* If we get this far, we have left over characters that have not been processed.
    			 * Advance to the character after the last command read by ast_cli_command_multiple_full.
    			 * We are guaranteed to have at least cmds_read NULLs */
    
    			while (cmds_read-- && (start_read = strchr(start_read, '\0'))) {
    
    				start_read++;
    			}
    			memmove(inbuf, start_read, end_buf - start_read);
    			start_read = end_buf - start_read + inbuf;
    
    Mark Spencer's avatar
    Mark Spencer committed
    		}
    
    			res = read_credentials(con->p[0], outbuf, sizeof(outbuf), con);
    
    Mark Spencer's avatar
    Mark Spencer committed
    			if (res < 1) {
    				ast_log(LOG_ERROR, "read returned %d\n", res);
    				break;
    			}
    
    			res = write(con->fd, outbuf, res);
    
    Mark Spencer's avatar
    Mark Spencer committed
    			if (res < 1)
    				break;
    		}
    	}
    
    	ast_verb_console_unregister();
    
    	if (!ast_opt_hide_connect) {
    		ast_verb(3, "Remote UNIX connection disconnected\n");
    	}
    
    Mark Spencer's avatar
    Mark Spencer committed
    	close(con->fd);
    	close(con->p[0]);
    	close(con->p[1]);
    	con->fd = -1;
    
    Mark Spencer's avatar
    Mark Spencer committed
    	return NULL;
    }
    
    static void *listener(void *unused)
    {
    
    Mark Spencer's avatar
    Mark Spencer committed
    	int s;
    
    Mark Spencer's avatar
    Mark Spencer committed
    	int x;
    
    Mark Spencer's avatar
    Mark Spencer committed
    		if (ast_socket < 0)
    			return NULL;
    
    		fds[0].fd = ast_socket;
    
    		s = ast_poll(fds, 1, -1);
    
    		pthread_testcancel();
    
    			if (errno != EINTR)
    
    				ast_log(LOG_WARNING, "poll returned error: %s\n", strerror(errno));
    
    		len = sizeof(sunaddr);
    		s = accept(ast_socket, (struct sockaddr *)&sunaddr, &len);
    
    Mark Spencer's avatar
    Mark Spencer committed
    		if (s < 0) {
    
    			if (errno != EINTR)
    
    James Golovich's avatar
    James Golovich committed
    				ast_log(LOG_WARNING, "Accept returned %d: %s\n", s, strerror(errno));
    
    Mark Spencer's avatar
    Mark Spencer committed
    		} else {
    
    			int sckopt = 1;
    			/* turn on socket credentials passing. */
    			if (setsockopt(s, SOL_SOCKET, SO_PASSCRED, &sckopt, sizeof(sckopt)) < 0) {
    				ast_log(LOG_WARNING, "Unable to turn on socket credentials passing\n");
    
    				for (x = 0; x < AST_MAX_CONNECTS; x++) {
    					if (consoles[x].fd >= 0) {
    						continue;
    					}
    
    Mark Spencer's avatar
    Mark Spencer committed
    					if (socketpair(AF_LOCAL, SOCK_STREAM, 0, consoles[x].p)) {
    
    Mark Spencer's avatar
    Mark Spencer committed
    						ast_log(LOG_ERROR, "Unable to create pipe: %s\n", strerror(errno));
    						fdprint(s, "Server failed to create pipe\n");
    						close(s);
    						break;
    					}
    
    					ast_fd_set_flags(consoles[x].p[1], O_NONBLOCK);
    
    					consoles[x].mute = 1; /* Default is muted, we will un-mute if necessary */
    
    					/* Default uid and gid to -2, so then in cli.c/cli_has_permissions() we will be able
    					   to know if the user didn't send the credentials. */
    					consoles[x].uid = -2;
    					consoles[x].gid = -2;
    
    					/* Server default of remote console verbosity level is OFF. */
    					consoles[x].option_verbose = 0;
    					consoles[x].fd = s;
    
    					if (ast_pthread_create_detached_background(&consoles[x].t, NULL, netconsole, &consoles[x])) {
    
    Mark Spencer's avatar
    Mark Spencer committed
    						ast_log(LOG_ERROR, "Unable to spawn thread to handle connection: %s\n", strerror(errno));
    
    						close(consoles[x].p[0]);
    						close(consoles[x].p[1]);
    
    Mark Spencer's avatar
    Mark Spencer committed
    						fdprint(s, "Server failed to spawn thread\n");
    						close(s);
    					}
    					break;
    				}
    
    				if (x >= AST_MAX_CONNECTS) {
    					fdprint(s, "No more connections allowed\n");
    					ast_log(LOG_WARNING, "No more connections allowed\n");
    					close(s);
    
    				} else if ((consoles[x].fd > -1) && (!ast_opt_hide_connect)) {
    
    					ast_verb(3, "Remote UNIX connection\n");
    
    Mark Spencer's avatar
    Mark Spencer committed
    			}
    		}
    	}
    	return NULL;
    }
    
    static int ast_makesocket(void)
    {
    
    Mark Spencer's avatar
    Mark Spencer committed
    	int res;
    	int x;
    
    	for (x = 0; x < AST_MAX_CONNECTS; x++)
    
    Mark Spencer's avatar
    Mark Spencer committed
    		consoles[x].fd = -1;
    
    Mark Spencer's avatar
    Mark Spencer committed
    	ast_socket = socket(PF_LOCAL, SOCK_STREAM, 0);
    	if (ast_socket < 0) {
    		ast_log(LOG_WARNING, "Unable to create control socket: %s\n", strerror(errno));
    		return -1;
    
    	memset(&sunaddr, 0, sizeof(sunaddr));
    	sunaddr.sun_family = AF_LOCAL;
    
    	ast_copy_string(sunaddr.sun_path, ast_config_AST_SOCKET, sizeof(sunaddr.sun_path));
    
    	res = bind(ast_socket, (struct sockaddr *)&sunaddr, sizeof(sunaddr));
    
    Mark Spencer's avatar
    Mark Spencer committed
    	if (res) {
    
    		ast_log(LOG_WARNING, "Unable to bind socket to %s: %s\n", ast_config_AST_SOCKET, strerror(errno));
    
    Mark Spencer's avatar
    Mark Spencer committed
    		close(ast_socket);
    		ast_socket = -1;
    		return -1;
    	}
    	res = listen(ast_socket, 2);
    	if (res < 0) {
    
    		ast_log(LOG_WARNING, "Unable to listen on socket %s: %s\n", ast_config_AST_SOCKET, strerror(errno));
    
    Mark Spencer's avatar
    Mark Spencer committed
    		close(ast_socket);
    		ast_socket = -1;
    		return -1;
    	}
    
    	if (ast_register_verbose(network_verboser)) {
    		ast_log(LOG_WARNING, "Unable to register network verboser?\n");
    	}
    
    
    	if (ast_pthread_create_background(&lthread, NULL, listener, NULL)) {
    		ast_log(LOG_WARNING, "Unable to create listener thread.\n");
    		close(ast_socket);
    		return -1;
    	}
    
    	if (!ast_strlen_zero(ast_config_AST_CTL_OWNER)) {
    
    Mark Spencer's avatar
    Mark Spencer committed
    		struct passwd *pw;
    
    Olle Johansson's avatar
    Olle Johansson committed
    		if ((pw = getpwnam(ast_config_AST_CTL_OWNER)) == NULL)
    
    			ast_log(LOG_WARNING, "Unable to find uid of user %s\n", ast_config_AST_CTL_OWNER);
    
    Olle Johansson's avatar
    Olle Johansson committed
    		else
    
    	if (!ast_strlen_zero(ast_config_AST_CTL_GROUP)) {
    
    Mark Spencer's avatar
    Mark Spencer committed
    		struct group *grp;
    
    Olle Johansson's avatar
    Olle Johansson committed
    		if ((grp = getgrnam(ast_config_AST_CTL_GROUP)) == NULL)
    
    			ast_log(LOG_WARNING, "Unable to find gid of group %s\n", ast_config_AST_CTL_GROUP);
    
    Olle Johansson's avatar
    Olle Johansson committed
    		else
    
    	if (chown(ast_config_AST_SOCKET, uid, gid) < 0)
    		ast_log(LOG_WARNING, "Unable to change ownership of %s: %s\n", ast_config_AST_SOCKET, strerror(errno));
    
    	if (!ast_strlen_zero(ast_config_AST_CTL_PERMISSIONS)) {
    
    		unsigned int p1;
    
    Mark Spencer's avatar
    Mark Spencer committed
    		mode_t p;
    
    Tilghman Lesher's avatar
    Tilghman Lesher committed
    		sscanf(ast_config_AST_CTL_PERMISSIONS, "%30o", &p1);
    
    		if ((chmod(ast_config_AST_SOCKET, p)) < 0)
    			ast_log(LOG_WARNING, "Unable to change file permissions of %s: %s\n", ast_config_AST_SOCKET, strerror(errno));
    
    Mark Spencer's avatar
    Mark Spencer committed
    	return 0;
    }
    
    static int ast_tryconnect(void)
    {
    
    Mark Spencer's avatar
    Mark Spencer committed
    	int res;
    	ast_consock = socket(PF_LOCAL, SOCK_STREAM, 0);
    	if (ast_consock < 0) {
    
    		fprintf(stderr, "Unable to create socket: %s\n", strerror(errno));
    
    Mark Spencer's avatar
    Mark Spencer committed
    		return 0;
    	}
    
    	memset(&sunaddr, 0, sizeof(sunaddr));
    	sunaddr.sun_family = AF_LOCAL;
    
    	ast_copy_string(sunaddr.sun_path, ast_config_AST_SOCKET, sizeof(sunaddr.sun_path));
    
    	res = connect(ast_consock, (struct sockaddr *)&sunaddr, sizeof(sunaddr));
    
    Mark Spencer's avatar
    Mark Spencer committed
    	if (res) {
    		close(ast_consock);
    		ast_consock = -1;
    		return 0;
    	} else
    		return 1;
    }
    
    
    Olle Johansson's avatar
    Olle Johansson committed
    /*! \brief Urgent handler
    
     *
     * Called by soft_hangup to interrupt the poll, read, or other
     * system call.  We don't actually need to do anything though.
     * Remember: Cannot EVER ast_log from within a signal handler
    
    static void _urg_handler(int num)
    
    static struct sigaction urg_handler = {
    	.sa_handler = _urg_handler,
    };
    
    static void _hup_handler(int num)
    
    Mark Spencer's avatar
    Mark Spencer committed
    {
    
    	int a = 0, save_errno = errno;
    
    	printf("Received HUP signal -- Reloading configs\n");
    
    	sig_flags.need_reload = 1;
    
    	if (sig_alert_pipe[1] != -1) {
    		if (write(sig_alert_pipe[1], &a, sizeof(a)) < 0) {
    			fprintf(stderr, "hup_handler: write() failed: %s\n", strerror(errno));
    		}
    	}
    
    	errno = save_errno;
    
    static struct sigaction hup_handler = {
    	.sa_handler = _hup_handler,
    
    	.sa_flags = SA_RESTART,
    
    };
    
    static void _child_handler(int sig)
    
    Mark Spencer's avatar
    Mark Spencer committed
    {
    
    	/* Must not ever ast_log or ast_verbose within signal handler */
    
    	int n, status, save_errno = errno;
    
    
    	/*
    	 * Reap all dead children -- not just one
    	 */
    
    	for (n = 0; waitpid(-1, &status, WNOHANG) > 0; n++)
    
    	if (n == 0 && option_debug)
    
    		printf("Huh?  Child handler, but nobody there?\n");
    
    	errno = save_errno;
    
    Mark Spencer's avatar
    Mark Spencer committed
    }
    
    static struct sigaction child_handler = {
    	.sa_handler = _child_handler,
    
    	.sa_flags = SA_RESTART,
    
    /*! \brief Set maximum open files */
    static void set_ulimit(int value)
    {
    	struct rlimit l = {0, 0};
    
    	if (value <= 0) {
    		ast_log(LOG_WARNING, "Unable to change max files open to invalid value %i\n",value);
    		return;
    	}
    
    	if (setrlimit(RLIMIT_NOFILE, &l)) {
    		ast_log(LOG_WARNING, "Unable to disable core size resource limit: %s\n",strerror(errno));
    		return;
    	}
    
    	ast_log(LOG_NOTICE, "Setting max files open to %d\n",value);
    
    Olle Johansson's avatar
    Olle Johansson committed
    /*! \brief Set an X-term or screen title */
    
    Mark Spencer's avatar
    Mark Spencer committed
    static void set_title(char *text)
    {
    	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);
    }
    
    
    /*! \brief Check whether we were set to high(er) priority. */
    static int has_priority(void)
    {
    	/* Neither of these calls should fail with these arguments. */
    #ifdef __linux__
    	/* For SCHED_OTHER, SCHED_BATCH and SCHED_IDLE, this will return
    	 * 0. For the realtime priorities SCHED_RR and SCHED_FIFO, it
    	 * will return something >= 1. */
    	return sched_getscheduler(0);
    #else
    	/* getpriority() can return a value in -20..19 (or even -INF..20)
    	 * where negative numbers are high priority. We don't bother
    	 * checking errno. If the query fails and it returns -1, we'll
    	 * assume that we're running at high prio; a safe assumption
    	 * that will enable the resource starvation monitor (canary)
    	 * just in case. */
    	return (getpriority(PRIO_PROCESS, 0) < 0);
    #endif
    }
    
    
    /*! \brief Set priority on all known threads. */
    static int set_priority_all(int pri)
    {
    #if !defined(__linux__)
    	/* The non-linux version updates the entire process prio. */
    	return ast_set_priority(pri);
    #elif defined(LOW_MEMORY)
    	ast_log(LOG_WARNING, "Unable to enumerate all threads to update priority\n");
    	return ast_set_priority(pri);
    #else
    	struct thread_list_t *cur;
    	struct sched_param sched;
    	char const *policy_str;
    	int policy;
    
    	memset(&sched, 0, sizeof(sched));
    	if (pri) {
    		policy = SCHED_RR;
    		policy_str = "realtime";
    		sched.sched_priority = 10;
    	} else {
    		policy = SCHED_OTHER;
    		policy_str = "regular";
    		sched.sched_priority = 0;
    	}
    	if (sched_setscheduler(getpid(), policy, &sched)) {
    		ast_log(LOG_WARNING, "Unable to set %s thread priority on main thread\n", policy_str);
    		return -1;