So far, users/mgmt apps can use --log-file to specify log output.
This has a downside though - they have to set up permissions so
that passt/pasta can open the file. But we can do a bit better:
allow mgmt apps pass an pre-opened FD and write all log messages
into it.
This then allows the log file to be readable by very few users
(root:root even) or reside in a path which would be otherwise
inaccessible.
Signed-off-by: Michal Privoznik
---
conf.c | 29 +++++++++++++++++++++++++----
log.c | 17 ++++++++++++-----
log.h | 2 +-
passt.1 | 5 +++++
4 files changed, 43 insertions(+), 10 deletions(-)
diff --git a/conf.c b/conf.c
index ffff235..59d0a8e 100644
--- a/conf.c
+++ b/conf.c
@@ -744,6 +744,7 @@ static void usage(const char *name)
info( " -e, --stderr Log to stderr too");
info( " default: log to system logger only if started from a TTY");
info( " -l, --log-file PATH Log (only) to given file");
+ info( " --log-fd FD Log (only) to given file descriptor");
info( " --log-size BYTES Maximum size of log file");
info( " default: 1 MiB");
info( " --runas UID|UID:GID Run as given UID, GID, which can be");
@@ -1181,6 +1182,7 @@ void conf(struct ctx *c, int argc, char **argv)
{"config-net", no_argument, NULL, 17 },
{"no-copy-routes", no_argument, NULL, 18 },
{"no-copy-addrs", no_argument, NULL, 19 },
+ {"log-fd", required_argument, NULL, 20 },
{ 0 },
};
struct get_bound_ports_ns_arg ns_ports_arg = { .c = c };
@@ -1192,7 +1194,7 @@ void conf(struct ctx *c, int argc, char **argv)
struct in_addr *dns4 = c->ip4.dns;
unsigned int ifi4 = 0, ifi6 = 0;
const char *optstring;
- int name, ret, b, i;
+ int name, ret, b, i, logfd = -1;
size_t logsize = 0;
uid_t uid;
gid_t gid;
@@ -1358,6 +1360,22 @@ void conf(struct ctx *c, int argc, char **argv)
warn("--no-copy-addrs will be dropped soon");
c->no_copy_addrs = 1;
+ break;
+ case 20:
+ if (logfile)
+ die("Either --log-file or --log-fd");
+
+ if (c->force_stderr)
+ die("Can't log to both stderr and file");
+
+ if (logfd >= 0)
+ die("Multiple --log-fd options given");
+
+ errno = 0;
+ logfd = strtol(optarg, NULL, 0);
+ if (logfd < 0 || errno)
+ die("Invalid --log-fd: %s", optarg);
+
break;
case 'd':
if (c->debug)
@@ -1369,7 +1387,7 @@ void conf(struct ctx *c, int argc, char **argv)
c->debug = 1;
break;
case 'e':
- if (logfile)
+ if (logfile || logfd >= 0)
die("Can't log to both file and stderr");
if (c->force_stderr)
@@ -1381,6 +1399,9 @@ void conf(struct ctx *c, int argc, char **argv)
if (c->force_stderr)
die("Can't log to both stderr and file");
+ if (logfd >= 0)
+ die("Either --log-file or --log-fd");
+
if (logfile)
die("Multiple --log-file options given");
@@ -1659,9 +1680,9 @@ void conf(struct ctx *c, int argc, char **argv)
conf_ugid(runas, &uid, &gid);
- if (logfile) {
+ if (logfile || logfd >= 0) {
logfile_init(c->mode == MODE_PASST ? "passt" : "pasta",
- logfile, logsize);
+ logfile, logfd, logsize);
}
nl_sock_init(c, false);
diff --git a/log.c b/log.c
index 3a3d101..28929a7 100644
--- a/log.c
+++ b/log.c
@@ -174,9 +174,10 @@ void passt_vsyslog(int pri, const char *format, va_list ap)
* logfile_init() - Open log file and write header with PID, version, path
* @name: Identifier for header: passt or pasta
* @path: Path to log file
+ * @logfd: Pre-opened log file descriptor (if >= 0)
* @size: Maximum size of log file: log_cut_size is calculatd here
*/
-void logfile_init(const char *name, const char *path, size_t size)
+void logfile_init(const char *name, const char *path, int logfd, size_t size)
{
char nl = '\n', exe[PATH_MAX] = { 0 };
int n;
@@ -186,10 +187,16 @@ void logfile_init(const char *name, const char *path, size_t size)
exit(EXIT_FAILURE);
}
- log_file = open(path, O_CREAT | O_TRUNC | O_APPEND | O_RDWR | O_CLOEXEC,
- S_IRUSR | S_IWUSR);
- if (log_file == -1)
- die("Couldn't open log file %s: %s", path, strerror(errno));
+ if (logfd >= 0) {
+ if (set_cloexec(logfd) < 0)
+ die("Could not set CLOEXEC flag on logfd", strerror(errno));
+ log_file = logfd;
+ } else {
+ log_file = open(path, O_CREAT | O_TRUNC | O_APPEND | O_RDWR | O_CLOEXEC,
+ S_IRUSR | S_IWUSR);
+ if (log_file == -1)
+ die("Couldn't open log file %s: %s", path, strerror(errno));
+ }
log_size = size ? size : LOGFILE_SIZE_DEFAULT;
diff --git a/log.h b/log.h
index 3aab29d..d96359a 100644
--- a/log.h
+++ b/log.h
@@ -30,7 +30,7 @@ void trace_init(int enable);
} while (0)
void __openlog(const char *ident, int option, int facility);
-void logfile_init(const char *name, const char *path, size_t size);
+void logfile_init(const char *name, const char *path, int logfd, size_t size);
void passt_vsyslog(int pri, const char *format, va_list ap);
void logfile_write(int pri, const char *format, va_list ap);
void __setlogmask(int mask);
diff --git a/passt.1 b/passt.1
index 1ad4276..ee5abbb 100644
--- a/passt.1
+++ b/passt.1
@@ -101,6 +101,11 @@ terminal, and to both system logger and standard error otherwise.
.BR \-l ", " \-\-log-file " " \fIPATH\fR
Log to file \fIPATH\fR, not to standard error, and not to the system logger.
+.TP
+.BR \-l ", " \-\-log-fd " " \fIFD\fR
+Log to pre-opened file descriptor \fIFD\fR, not to standard error, and not to
+the system logger.
+
.TP
.BR \-\-log-size " " \fISIZE\fR
Limit log file size to \fISIZE\fR bytes. When the log file is full, make room
--
2.39.3