Newer
Older
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)
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);
return CLI_SUCCESS;
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;
1049
1050
1051
1052
1053
1054
1055
1056
1057
1058
1059
1060
1061
1062
1063
1064
1065
1066
1067
1068
1069
1070
1071
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
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;
Kevin P. Fleming
committed
regex_t regexbuf;
int havepattern = 0;
Kevin P. Fleming
committed
int count_files = 0;
char *ret = NULL;
switch (cmd) {
case CLI_INIT:
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:
if (a->pos != 4) {
return NULL;
}
ret = ast_cli_complete(a->word, completions, a->n);
if (!ret) {
ret = ast_complete_source_filename(a->word, a->n - 1);
}
return ret;
}
Kevin P. Fleming
committed
switch (a->argc) {
if (!strcasecmp(a->argv[4], "like")) {
if (regcomp(®exbuf, a->argv[5], REG_EXTENDED | REG_NOSUB))
return CLI_SHOWUSAGE;
Kevin P. Fleming
committed
havepattern = 1;
} else
return CLI_SHOWUSAGE;
Kevin P. Fleming
committed
break;
if (!strcasecmp(a->argv[4], "like")) {
return CLI_SHOWUSAGE;
}
Kevin P. Fleming
committed
break;
default:
return CLI_SHOWUSAGE;
Kevin P. Fleming
committed
}
ast_cli(a->fd, FORMAT, "File", "Revision");
ast_cli(a->fd, FORMAT, "----", "--------");
AST_RWLIST_RDLOCK(®istered_files);
AST_RWLIST_TRAVERSE(®istered_files, iterator, list) {
if (havename && strcasecmp(iterator->file, a->argv[4]))
Kevin P. Fleming
committed
if (havepattern && regexec(®exbuf, iterator->file, 0, NULL, 0))
continue;
ast_cli(a->fd, FORMAT, iterator->file, ast_get_version());
Kevin P. Fleming
committed
count_files++;
AST_RWLIST_UNLOCK(®istered_files);
Kevin P. Fleming
committed
if (!havename) {
ast_cli(a->fd, "%d files listed.\n", count_files);
Kevin P. Fleming
committed
}
Kevin P. Fleming
committed
if (havepattern)
regfree(®exbuf);
return CLI_SUCCESS;
Kevin P. Fleming
committed
#undef FORMAT
#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)) {
1176
1177
1178
1179
1180
1181
1182
1183
1184
1185
1186
1187
1188
1189
1190
1191
1192
1193
1194
1195
1196
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)
{
struct ast_atexit *ae;
ae = ast_calloc(1, sizeof(*ae));
if (!ae) {
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)
{
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));
}
/*! \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,
};
static struct sigaction ignore_sig_handler = {
.sa_handler = SIG_IGN,
};
AST_MUTEX_DEFINE_STATIC(safe_system_lock);
/*! \brief Keep track of how many threads are currently trying to wait*() on
static unsigned int safe_system_level = 0;
static struct sigaction safe_system_prev_handler;
Russell Bryant
committed
void ast_replace_sigchld(void)
Mark Spencer
committed
{
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);
Russell Bryant
committed
}
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);
}
Russell Bryant
committed
ast_mutex_unlock(&safe_system_lock);
}
/*! \brief fork and perform other preparations for spawning applications */
static pid_t safe_exec_prep(int dualfork)
Russell Bryant
committed
{
pid_t pid;
#if defined(HAVE_WORKING_FORK) || defined(HAVE_WORKING_VFORK)
ast_replace_sigchld();
Mark Spencer
committed
pid = fork();
Mark Spencer
committed
if (pid == 0) {
#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
if (ast_opt_high_priority) {
}
Mark Spencer
committed
/* Close file descriptors and launch system command */
Tilghman Lesher
committed
ast_close_fds_above_n(STDERR_FILENO);
1327
1328
1329
1330
1331
1332
1333
1334
1335
1336
1337
1338
1339
1340
1341
1342
1343
1344
1345
1346
1347
1348
1349
1350
1351
1352
1353
1354
1355
1356
1357
1358
1359
1360
1361
1362
1363
1364
1365
1366
1367
1368
1369
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) {
Joshua Colp
committed
for (;;) {
int status;
res = waitpid(pid, &status, 0);
Mark Spencer
committed
if (res > -1) {
res = WIFEXITED(status) ? WEXITSTATUS(status) : -1;
break;
}
if (errno != EINTR) {
}
Mark Spencer
committed
}
}
Russell Bryant
committed
ast_unreplace_sigchld();
Kevin P. Fleming
committed
#endif
Mark Spencer
committed
return res;
}
1390
1391
1392
1393
1394
1395
1396
1397
1398
1399
1400
1401
1402
1403
1404
1405
1406
1407
1408
1409
1410
1411
1412
1413
1414
1415
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;
return;
}
}
}
Joshua Colp
committed
/*!
Joshua Colp
committed
*/
void ast_console_toggle_mute(int fd, int silent)
{
Joshua Colp
committed
int x;
for (x = 0;x < AST_MAX_CONNECTS; x++) {
Joshua Colp
committed
if (fd == consoles[x].fd) {
if (consoles[x].mute) {
consoles[x].mute = 0;
if (!silent)
ast_cli(fd, "Console is not muted anymore.\n");
Joshua Colp
committed
} else {
consoles[x].mute = 1;
if (!silent)
ast_cli(fd, "Console is muted.\n");
Joshua Colp
committed
}
return;
}
}
ast_cli(fd, "Couldn't find remote console.\n");
}
/*!
* \brief log the string to all attached network console clients
Joshua Colp
committed
*/
static void ast_network_puts_mutable(const char *string, int level)
Joshua Colp
committed
{
int x;
for (x = 0; x < AST_MAX_CONNECTS; ++x) {
if (consoles[x].fd < 0
|| consoles[x].mute
|| consoles[x].levels[level]) {
continue;
fdprint(consoles[x].p[1], string);
Joshua Colp
committed
}
}
/*!
* \brief log the string to the root console, and all attached
* network console clients
Joshua Colp
committed
*/
void ast_console_puts_mutable(const char *string, int level)
Joshua Colp
committed
{
/* Send to the root console */
Joshua Colp
committed
fputs(string, stdout);
fflush(stdout);
/* Send to any network console clients */
ast_network_puts_mutable(string, level);
Joshua Colp
committed
}
* \brief write the string to all attached console clients
*/
static void ast_network_puts(const char *string)
{
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 */
/* Send to any network console clients */
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);
}
/*!
* \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
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)
#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. */
static void *netconsole(void *vconsole)
{
struct console *con = vconsole;
Olle Johansson
committed
char hostname[MAXHOSTNAMELEN] = "";
char inbuf[512];
char outbuf[512];
const char * const end_buf = inbuf + sizeof(inbuf);
char *start_read = inbuf;
struct pollfd fds[2];
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);
Joshua Colp
committed
for (;;) {
fds[0].fd = con->fd;
fds[0].events = POLLIN;
fds[0].revents = 0;
fds[1].fd = con->p[0];
fds[1].events = POLLIN;
fds[1].revents = 0;
if (errno != EINTR)
ast_log(LOG_WARNING, "poll returned < 0: %s\n", strerror(errno));
if (fds[0].revents) {
int cmds_read, bytes_read;
if ((bytes_read = read_credentials(con->fd, start_read, end_buf - start_read, con)) < 1) {
/* 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);
1642
1643
1644
1645
1646
1647
1648
1649
1650
1651
1652
1653
1654
1655
1656
1657
1658
1659
1660
1661
1662
/* 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;
if (fds[1].revents) {
res = read_credentials(con->p[0], outbuf, sizeof(outbuf), con);
if (res < 1) {
ast_log(LOG_ERROR, "read returned %d\n", res);
break;
}
res = write(con->fd, outbuf, res);
ast_verb_console_unregister();
if (!ast_opt_hide_connect) {
ast_verb(3, "Remote UNIX connection disconnected\n");
}
close(con->fd);
close(con->p[0]);
close(con->p[1]);
con->fd = -1;
return NULL;
}
static void *listener(void *unused)
{
struct sockaddr_un sunaddr;
socklen_t len;
struct pollfd fds[1];
Olle Johansson
committed
for (;;) {
fds[0].fd = ast_socket;
Olle Johansson
committed
fds[0].events = POLLIN;
ast_log(LOG_WARNING, "poll returned error: %s\n", strerror(errno));
len = sizeof(sunaddr);
s = accept(ast_socket, (struct sockaddr *)&sunaddr, &len);
ast_log(LOG_WARNING, "Accept returned %d: %s\n", s, strerror(errno));
#if defined(SO_PASSCRED)
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");
} else
{
for (x = 0; x < AST_MAX_CONNECTS; x++) {
if (consoles[x].fd >= 0) {
continue;
}
if (socketpair(AF_LOCAL, SOCK_STREAM, 0, consoles[x].p)) {
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;
Russell Bryant
committed
if (ast_pthread_create_detached_background(&consoles[x].t, NULL, netconsole, &consoles[x])) {
consoles[x].fd = -1;
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]);
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");
}
}
}
return NULL;
}
static int ast_makesocket(void)
{
struct sockaddr_un sunaddr;
uid_t uid = -1;
gid_t gid = -1;
for (x = 0; x < AST_MAX_CONNECTS; x++)
unlink(ast_config_AST_SOCKET);
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));
ast_log(LOG_WARNING, "Unable to bind socket to %s: %s\n", ast_config_AST_SOCKET, strerror(errno));
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));
close(ast_socket);
ast_socket = -1;
return -1;
}
Tilghman Lesher
committed
if (ast_register_verbose(network_verboser)) {
ast_log(LOG_WARNING, "Unable to register network verboser?\n");
}
if (ast_pthread_create_background(<hread, 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)) {
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);
uid = pw->pw_uid;
if (!ast_strlen_zero(ast_config_AST_CTL_GROUP)) {
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);
gid = grp->gr_gid;
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)) {
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));
return 0;
}
static int ast_tryconnect(void)
{
struct sockaddr_un sunaddr;
int res;
ast_consock = socket(PF_LOCAL, SOCK_STREAM, 0);
if (ast_consock < 0) {
Matthew Jordan
committed
fprintf(stderr, "Unable to create socket: %s\n", strerror(errno));
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));
if (res) {
close(ast_consock);
ast_consock = -1;
return 0;
} else
return 1;
}
*
* 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)
int a = 0, save_errno = errno;
printf("Received HUP signal -- Reloading configs\n");
if (restartnow)
execvp(_argv[0], _argv);
Kevin P. Fleming
committed
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));
}
}
static struct sigaction hup_handler = {
.sa_handler = _hup_handler,
};
static void _child_handler(int sig)
/* 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++)
printf("Huh? Child handler, but nobody there?\n");
static struct sigaction child_handler = {
.sa_handler = _child_handler,
Joshua Colp
committed
/*! \brief Set maximum open files */
static void set_ulimit(int value)
{
struct rlimit l = {0, 0};
Joshua Colp
committed
if (value <= 0) {
ast_log(LOG_WARNING, "Unable to change max files open to invalid value %i\n",value);
return;
}
Joshua Colp
committed
l.rlim_cur = value;
l.rlim_max = value;
Joshua Colp
committed
if (setrlimit(RLIMIT_NOFILE, &l)) {
ast_log(LOG_WARNING, "Unable to disable core size resource limit: %s\n",strerror(errno));
return;
}
Joshua Colp
committed
ast_log(LOG_NOTICE, "Setting max files open to %d\n",value);
Joshua Colp
committed
return;
}
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
}
1973
1974
1975
1976
1977
1978
1979
1980
1981
1982
1983
1984
1985
1986
1987
1988
1989
1990
1991
1992
1993
1994
1995
1996
1997
1998
1999
2000
/*! \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;