Index: main/logger.c =================================================================== --- main/logger.c (revision 342577) +++ main/logger.c (working copy) @@ -62,6 +62,10 @@ # endif #endif +#ifdef HAVE_CAP +#include +#endif + #if defined(__linux__) && !defined(__NR_gettid) #include #endif @@ -240,6 +244,69 @@ return res; } +static FILE *ast_openlog(char *ident, int option, int facility) +{ + int res, fd[2], i; + sigset_t fullset, oldset; + char argv1[12]; +#ifdef HAVE_CAP + cap_t cap; +#endif + + if (pipe(fd)) { + fprintf(stderr, "Pipe failed: %s\n", strerror(errno)); + return NULL; + } + + sigfillset(&fullset); + pthread_sigmask(SIG_BLOCK, &fullset, &oldset); + if ((res = fork()) < 0) { + fprintf(stderr, "Fork failed: %s\n", strerror(errno)); + return NULL; + } + if (res) { + FILE *logger; + close(fd[0]); + pthread_sigmask(SIG_SETMASK, &oldset, NULL); + if (!(logger = fdopen(fd[1], "a"))) { + fprintf(stderr, "fdopen(3) failed: %s\n", strerror(errno)); + close(fd[1]); + return NULL; + } + return logger; + } + +#ifdef HAVE_CAP + 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) { + ast_set_priority(0); + } + signal(SIGPIPE, SIG_DFL); + + /* Close writer, close everything else */ + close(fd[1]); + if (dup2(fd[0], STDIN_FILENO)) { + fprintf(stderr, "Failed to duplicate file descriptor: %s\n", strerror(errno)); + close(fd[0]); + exit(1); + } + + for (i = STDIN_FILENO + 1; i < 4096; i++) { + fcntl(i, F_SETFD, FD_CLOEXEC | fcntl(i, F_GETFD)); + } + + snprintf(argv1, sizeof(argv1), "%d", facility); + execlp("astsyslogger", argv1, (char *) NULL); + exit(0); +} + static struct logchannel *make_logchannel(const char *channel, const char *components, int lineno) { struct logchannel *chan; @@ -273,7 +340,7 @@ chan->type = LOGTYPE_SYSLOG; ast_copy_string(chan->filename, channel, sizeof(chan->filename)); - openlog("asterisk", LOG_PID, chan->facility); + chan->fileptr = ast_openlog("asterisk", LOG_PID, chan->facility); } else { if (!ast_strlen_zero(hostname)) { snprintf(chan->filename, sizeof(chan->filename), "%s/%s.%s", @@ -317,6 +384,9 @@ AST_RWLIST_WRLOCK(&logchannels); } while ((chan = AST_RWLIST_REMOVE_HEAD(&logchannels, list))) { + if (chan->fileptr) { + fclose(chan->fileptr); + } ast_free(chan); } global_logmask = 0; @@ -325,8 +395,6 @@ } errno = 0; - /* close syslog */ - closelog(); /* If no config file, we're fine, set default options. */ if (!cfg) { @@ -945,7 +1013,7 @@ .sa_flags = SA_RESTART, }; -static void ast_log_vsyslog(struct logmsg *msg) +static void ast_log_vsyslog(FILE *logger, struct logmsg *msg) { char buf[BUFSIZ]; int syslog_level = ast_syslog_priority_from_loglevel(msg->level); @@ -960,7 +1028,7 @@ levels[msg->level], msg->process_id, msg->file, msg->line, msg->function, msg->message); term_strip(buf, buf, strlen(buf) + 1); - syslog(syslog_level, "%s", buf); + fprintf(logger, "%c%s", syslog_level, buf); } /*! \brief Print a normal log message to the channels */ @@ -989,7 +1057,7 @@ continue; /* Check syslog channels */ if (chan->type == LOGTYPE_SYSLOG && (chan->logmask & (1 << logmsg->level))) { - ast_log_vsyslog(logmsg); + ast_log_vsyslog(chan->fileptr, logmsg); /* Console channels */ } else if (chan->type == LOGTYPE_CONSOLE && (chan->logmask & (1 << logmsg->level))) { char linestr[128]; @@ -1176,8 +1244,6 @@ } } - closelog(); /* syslog */ - AST_RWLIST_UNLOCK(&logchannels); return; Index: utils/utils.xml =================================================================== --- utils/utils.xml (revision 342577) +++ utils/utils.xml (working copy) @@ -12,6 +12,10 @@ newt extended + + yes + core + no extended Index: utils/astsyslogger.c =================================================================== --- utils/astsyslogger.c (revision 0) +++ utils/astsyslogger.c (revision 0) @@ -0,0 +1,55 @@ +/* + * Asterisk -- An open source telephony toolkit. + * + * Copyright (C) 2010, Tilghman Lesher + * + * Tilghman Lesher + * + * See http://www.asterisk.org for more information about + * the Asterisk project. Please do not directly contact + * any of the maintainers of this project for assistance; + * the project provides a web site, mailing lists and IRC + * channels for your use. + * + * This program is free software, distributed under the terms of + * the GNU General Public License Version 2. See the LICENSE file + * at the top of the source tree. + */ + +#include +#include +#include +#include +#include + +/*\brief Rationale: + * The purpose of this file is to ensure that logging to the syslog + * may occur on multiple facilities. Unfortunately, the syslog + * API applies globally to the process and there is not a way to ensure + * that multiple facilities may be used at once. One call to openlog(3) + * supercedes all previous calls. While we could use locking to ensure + * that only one thread may access the syslog API at one time, because + * we are dealing with logging, contention for such a lock becomes a huge + * issue. + */ +int main(int argc, char *argv[]) +{ + char id[128], buf[4096]; + int facility; + + if (argc < 2 || sscanf(argv[1], "%d", &facility) < 1) { + fprintf(stderr, "Usage: %s \n", argv[0]); + exit(1); + } + + snprintf(id, sizeof(id), "asterisk[%d]", (int) getppid()); + openlog(id, 0, facility); + + while (fgets(buf, sizeof(buf), stdin)) { + syslog(buf[0], "%s", &buf[1]); + } + + closelog(); + return 0; +} +