summaryrefslogtreecommitdiff
path: root/src/journal
diff options
context:
space:
mode:
Diffstat (limited to 'src/journal')
-rw-r--r--src/journal/journal-file.c2
-rw-r--r--src/journal/journal-internal.h2
-rw-r--r--src/journal/journalctl.c32
-rw-r--r--src/journal/journald-server.c130
-rw-r--r--src/journal/journald-server.h13
-rw-r--r--src/journal/journald-stream.c68
-rw-r--r--src/journal/journald-stream.h4
-rw-r--r--src/journal/journald.c8
-rw-r--r--src/journal/sd-journal.c317
9 files changed, 388 insertions, 188 deletions
diff --git a/src/journal/journal-file.c b/src/journal/journal-file.c
index 12b39dbb27..e00a0d711d 100644
--- a/src/journal/journal-file.c
+++ b/src/journal/journal-file.c
@@ -2705,7 +2705,7 @@ int journal_file_open(
}
if (f->last_stat.st_size < (off_t) HEADER_SIZE_MIN) {
- r = -EIO;
+ r = -ENODATA;
goto fail;
}
diff --git a/src/journal/journal-internal.h b/src/journal/journal-internal.h
index 1221799c1d..06847402e0 100644
--- a/src/journal/journal-internal.h
+++ b/src/journal/journal-internal.h
@@ -121,7 +121,7 @@ struct sd_journal {
Hashmap *directories_by_path;
Hashmap *directories_by_wd;
- Set *errors;
+ Hashmap *errors;
};
char *journal_make_match_string(sd_journal *j);
diff --git a/src/journal/journalctl.c b/src/journal/journalctl.c
index a35783e3ff..98a852cb50 100644
--- a/src/journal/journalctl.c
+++ b/src/journal/journalctl.c
@@ -1708,36 +1708,50 @@ static int access_check_var_log_journal(sd_journal *j) {
static int access_check(sd_journal *j) {
Iterator it;
void *code;
+ char *path;
int r = 0;
assert(j);
- if (set_isempty(j->errors)) {
+ if (hashmap_isempty(j->errors)) {
if (ordered_hashmap_isempty(j->files))
log_notice("No journal files were found.");
return 0;
}
- if (set_contains(j->errors, INT_TO_PTR(-EACCES))) {
+ if (hashmap_contains(j->errors, INT_TO_PTR(-EACCES))) {
(void) access_check_var_log_journal(j);
if (ordered_hashmap_isempty(j->files))
r = log_error_errno(EACCES, "No journal files were opened due to insufficient permissions.");
}
- SET_FOREACH(code, j->errors, it) {
+ HASHMAP_FOREACH_KEY(path, code, j->errors, it) {
int err;
- err = -PTR_TO_INT(code);
- assert(err > 0);
+ err = abs(PTR_TO_INT(code));
- if (err == EACCES)
+ switch (err) {
+ case EACCES:
continue;
- log_warning_errno(err, "Error was encountered while opening journal files: %m");
- if (r == 0)
- r = -err;
+ case ENODATA:
+ log_warning_errno(err, "Journal file %s is truncated, ignoring file.", path);
+ break;
+
+ case EPROTONOSUPPORT:
+ log_warning_errno(err, "Journal file %s uses an unsupported feature, ignoring file.", path);
+ break;
+
+ case EBADMSG:
+ log_warning_errno(err, "Journal file %s corrupted, ignoring file.", path);
+ break;
+
+ default:
+ log_warning_errno(err, "An error was encountered while opening journal file %s, ignoring file.", path);
+ break;
+ }
}
return r;
diff --git a/src/journal/journald-server.c b/src/journal/journald-server.c
index ecf7b7a476..299b0a848f 100644
--- a/src/journal/journald-server.c
+++ b/src/journal/journald-server.c
@@ -78,6 +78,8 @@
#define RECHECK_SPACE_USEC (30*USEC_PER_SEC)
+#define NOTIFY_SNDBUF_SIZE (8*1024*1024)
+
static int determine_space_for(
Server *s,
JournalMetrics *metrics,
@@ -1457,6 +1459,126 @@ static int server_open_hostname(Server *s) {
return 0;
}
+static int dispatch_notify_event(sd_event_source *es, int fd, uint32_t revents, void *userdata) {
+ Server *s = userdata;
+ int r;
+
+ assert(s);
+ assert(s->notify_event_source == es);
+ assert(s->notify_fd == fd);
+
+ if (revents != EPOLLOUT) {
+ log_error("Invalid events on notify file descriptor.");
+ return -EINVAL;
+ }
+
+ /* The $NOTIFY_SOCKET is writable again, now send exactly one
+ * message on it. Either it's the initial READY=1 event or an
+ * stdout stream event. If there's nothing to write anymore,
+ * turn our event source off. The next time there's something
+ * to send it will be turned on again. */
+
+ if (!s->sent_notify_ready) {
+ static const char p[] =
+ "READY=1\n"
+ "STATUS=Processing requests...";
+ ssize_t l;
+
+ l = send(s->notify_fd, p, strlen(p), MSG_DONTWAIT);
+ if (l < 0) {
+ if (errno == EAGAIN)
+ return 0;
+
+ return log_error_errno(errno, "Failed to send READY=1 notification message: %m");
+ }
+
+ s->sent_notify_ready = true;
+ log_debug("Sent READY=1 notification.");
+
+ } else if (s->stdout_streams_notify_queue)
+ /* Dispatch one stream notification event */
+ stdout_stream_send_notify(s->stdout_streams_notify_queue);
+
+ /* Leave us enabled if there's still more to to do. */
+ if (s->stdout_streams_notify_queue)
+ return 0;
+
+ /* There was nothing to do anymore, let's turn ourselves off. */
+ r = sd_event_source_set_enabled(es, SD_EVENT_OFF);
+ if (r < 0)
+ return log_error_errno(r, "Failed to turn off notify event source: %m");
+
+ return 0;
+}
+
+static int server_connect_notify(Server *s) {
+ union sockaddr_union sa = {
+ .un.sun_family = AF_UNIX,
+ };
+ const char *e;
+ int r;
+
+ assert(s);
+ assert(s->notify_fd < 0);
+ assert(!s->notify_event_source);
+
+ /*
+ So here's the problem: we'd like to send notification
+ messages to PID 1, but we cannot do that via sd_notify(),
+ since that's synchronous, and we might end up blocking on
+ it. Specifically: given that PID 1 might block on
+ dbus-daemon during IPC, and dbus-daemon is logging to us,
+ and might hence block on us, we might end up in a deadlock
+ if we block on sending PID 1 notification messages -- by
+ generating a full blocking circle. To avoid this, let's
+ create a non-blocking socket, and connect it to the
+ notification socket, and then wait for POLLOUT before we
+ send anything. This should efficiently avoid any deadlocks,
+ as we'll never block on PID 1, hence PID 1 can safely block
+ on dbus-daemon which can safely block on us again.
+
+ Don't think that this issue is real? It is, see:
+ https://github.com/systemd/systemd/issues/1505
+ */
+
+ e = getenv("NOTIFY_SOCKET");
+ if (!e)
+ return 0;
+
+ if ((e[0] != '@' && e[0] != '/') || e[1] == 0) {
+ log_error("NOTIFY_SOCKET set to an invalid value: %s", e);
+ return -EINVAL;
+ }
+
+ if (strlen(e) > sizeof(sa.un.sun_path)) {
+ log_error("NOTIFY_SOCKET path too long: %s", e);
+ return -EINVAL;
+ }
+
+ s->notify_fd = socket(AF_UNIX, SOCK_DGRAM|SOCK_CLOEXEC|SOCK_NONBLOCK, 0);
+ if (s->notify_fd < 0)
+ return log_error_errno(errno, "Failed to create notify socket: %m");
+
+ (void) fd_inc_sndbuf(s->notify_fd, NOTIFY_SNDBUF_SIZE);
+
+ strncpy(sa.un.sun_path, e, sizeof(sa.un.sun_path));
+ if (sa.un.sun_path[0] == '@')
+ sa.un.sun_path[0] = 0;
+
+ r = connect(s->notify_fd, &sa.sa, offsetof(struct sockaddr_un, sun_path) + strlen(e));
+ if (r < 0)
+ return log_error_errno(errno, "Failed to connect to notify socket: %m");
+
+ r = sd_event_add_io(s->event, &s->notify_event_source, s->notify_fd, EPOLLOUT, dispatch_notify_event, s);
+ if (r < 0)
+ return log_error_errno(r, "Failed to watch notification socket: %m");
+
+ /* This should fire pretty soon, which we'll use to send the
+ * READY=1 event. */
+
+ return 0;
+}
+
int server_init(Server *s) {
_cleanup_fdset_free_ FDSet *fds = NULL;
int n, r, fd;
@@ -1465,7 +1587,7 @@ int server_init(Server *s) {
assert(s);
zero(*s);
- s->syslog_fd = s->native_fd = s->stdout_fd = s->dev_kmsg_fd = s->audit_fd = s->hostname_fd = -1;
+ s->syslog_fd = s->native_fd = s->stdout_fd = s->dev_kmsg_fd = s->audit_fd = s->hostname_fd = s->notify_fd = -1;
s->compress = true;
s->seal = true;
@@ -1511,8 +1633,6 @@ int server_init(Server *s) {
if (r < 0)
return log_error_errno(r, "Failed to create event loop: %m");
- sd_event_set_watchdog(s->event, true);
-
n = sd_listen_fds(true);
if (n < 0)
return log_error_errno(n, "Failed to read listening file descriptors from environment: %m");
@@ -1637,6 +1757,8 @@ int server_init(Server *s) {
server_cache_boot_id(s);
server_cache_machine_id(s);
+ (void) server_connect_notify(s);
+
return system_journal_open(s, false);
}
@@ -1685,6 +1807,7 @@ void server_done(Server *s) {
sd_event_source_unref(s->sigterm_event_source);
sd_event_source_unref(s->sigint_event_source);
sd_event_source_unref(s->hostname_event_source);
+ sd_event_source_unref(s->notify_event_source);
sd_event_unref(s->event);
safe_close(s->syslog_fd);
@@ -1693,6 +1816,7 @@ void server_done(Server *s) {
safe_close(s->dev_kmsg_fd);
safe_close(s->audit_fd);
safe_close(s->hostname_fd);
+ safe_close(s->notify_fd);
if (s->rate_limit)
journal_rate_limit_free(s->rate_limit);
diff --git a/src/journal/journald-server.h b/src/journal/journald-server.h
index a2631c6017..170602ea16 100644
--- a/src/journal/journald-server.h
+++ b/src/journal/journald-server.h
@@ -26,9 +26,12 @@
#include "sd-event.h"
+typedef struct Server Server;
+
#include "hashmap.h"
#include "journal-file.h"
#include "journald-rate-limit.h"
+#include "journald-stream.h"
#include "list.h"
typedef enum Storage {
@@ -48,15 +51,14 @@ typedef enum SplitMode {
_SPLIT_INVALID = -1
} SplitMode;
-typedef struct StdoutStream StdoutStream;
-
-typedef struct Server {
+struct Server {
int syslog_fd;
int native_fd;
int stdout_fd;
int dev_kmsg_fd;
int audit_fd;
int hostname_fd;
+ int notify_fd;
sd_event *event;
@@ -71,6 +73,7 @@ typedef struct Server {
sd_event_source *sigterm_event_source;
sd_event_source *sigint_event_source;
sd_event_source *hostname_event_source;
+ sd_event_source *notify_event_source;
JournalFile *runtime_journal;
JournalFile *system_journal;
@@ -111,6 +114,7 @@ typedef struct Server {
usec_t oldest_file_usec;
LIST_HEAD(StdoutStream, stdout_streams);
+ LIST_HEAD(StdoutStream, stdout_streams_notify_queue);
unsigned n_stdout_streams;
char *tty_path;
@@ -132,6 +136,7 @@ typedef struct Server {
struct udev *udev;
+ bool sent_notify_ready;
bool sync_scheduled;
char machine_id_field[sizeof("_MACHINE_ID=") + 32];
@@ -140,7 +145,7 @@ typedef struct Server {
/* Cached cgroup root, so that we don't have to query that all the time */
char *cgroup_root;
-} Server;
+};
#define SERVER_MACHINE_ID(s) ((s)->machine_id_field + strlen("_MACHINE_ID="))
diff --git a/src/journal/journald-stream.c b/src/journal/journald-stream.c
index 5300c61c02..fb6afee171 100644
--- a/src/journal/journald-stream.c
+++ b/src/journal/journald-stream.c
@@ -79,6 +79,7 @@ struct StdoutStream {
bool forward_to_console:1;
bool fdstore:1;
+ bool in_notify_queue:1;
char buffer[LINE_MAX+1];
size_t length;
@@ -88,6 +89,7 @@ struct StdoutStream {
char *state_file;
LIST_FIELDS(StdoutStream, stdout_stream);
+ LIST_FIELDS(StdoutStream, stdout_stream_notify_queue);
};
void stdout_stream_free(StdoutStream *s) {
@@ -98,6 +100,9 @@ void stdout_stream_free(StdoutStream *s) {
assert(s->server->n_stdout_streams > 0);
s->server->n_stdout_streams --;
LIST_REMOVE(stdout_stream, s->server->stdout_streams, s);
+
+ if (s->in_notify_queue)
+ LIST_REMOVE(stdout_stream_notify_queue, s->server->stdout_streams_notify_queue, s);
}
if (s->event_source) {
@@ -121,7 +126,7 @@ static void stdout_stream_destroy(StdoutStream *s) {
return;
if (s->state_file)
- unlink(s->state_file);
+ (void) unlink(s->state_file);
stdout_stream_free(s);
}
@@ -200,11 +205,15 @@ static int stdout_stream_save(StdoutStream *s) {
goto fail;
}
- /* Store the connection fd in PID 1, so that we get it passed
- * in again on next start */
- if (!s->fdstore) {
- sd_pid_notify_with_fds(0, false, "FDSTORE=1", &s->fd, 1);
- s->fdstore = true;
+ if (!s->fdstore && !s->in_notify_queue) {
+ LIST_PREPEND(stdout_stream_notify_queue, s->server->stdout_streams_notify_queue, s);
+ s->in_notify_queue = true;
+
+ if (s->server->notify_event_source) {
+ r = sd_event_source_set_enabled(s->server->notify_event_source, SD_EVENT_ON);
+ if (r < 0)
+ log_warning_errno(r, "Failed to enable notify event source: %m");
+ }
}
return 0;
@@ -729,3 +738,50 @@ int server_open_stdout_socket(Server *s) {
return 0;
}
+
+void stdout_stream_send_notify(StdoutStream *s) {
+ struct iovec iovec = {
+ .iov_base = (char*) "FDSTORE=1",
+ .iov_len = strlen("FDSTORE=1"),
+ };
+ struct msghdr msghdr = {
+ .msg_iov = &iovec,
+ .msg_iovlen = 1,
+ };
+ struct cmsghdr *cmsg;
+ ssize_t l;
+
+ assert(s);
+ assert(!s->fdstore);
+ assert(s->in_notify_queue);
+ assert(s->server);
+ assert(s->server->notify_fd >= 0);
+
+ /* Store the connection fd in PID 1, so that we get it passed
+ * in again on next start */
+
+ msghdr.msg_controllen = CMSG_SPACE(sizeof(int));
+ msghdr.msg_control = alloca0(msghdr.msg_controllen);
+
+ cmsg = CMSG_FIRSTHDR(&msghdr);
+ cmsg->cmsg_level = SOL_SOCKET;
+ cmsg->cmsg_type = SCM_RIGHTS;
+ cmsg->cmsg_len = CMSG_LEN(sizeof(int));
+
+ memcpy(CMSG_DATA(cmsg), &s->fd, sizeof(int));
+
+ l = sendmsg(s->server->notify_fd, &msghdr, MSG_DONTWAIT|MSG_NOSIGNAL);
+ if (l < 0) {
+ if (errno == EAGAIN)
+ return;
+
+ log_error_errno(errno, "Failed to send stream file descriptor to service manager: %m");
+ } else {
+ log_debug("Successfully sent stream file descriptor to service manager.");
+ s->fdstore = 1;
+ }
+
+ LIST_REMOVE(stdout_stream_notify_queue, s->server->stdout_streams_notify_queue, s);
+ s->in_notify_queue = false;
+
+}
diff --git a/src/journal/journald-stream.h b/src/journal/journald-stream.h
index 257dce45df..e3497f0ded 100644
--- a/src/journal/journald-stream.h
+++ b/src/journal/journald-stream.h
@@ -21,9 +21,13 @@
along with systemd; If not, see <http://www.gnu.org/licenses/>.
***/
+typedef struct StdoutStream StdoutStream;
+
#include "fdset.h"
#include "journald-server.h"
int server_open_stdout_socket(Server *s);
int server_restore_streams(Server *s, FDSet *fds);
+
void stdout_stream_free(StdoutStream *s);
+void stdout_stream_send_notify(StdoutStream *s);
diff --git a/src/journal/journald.c b/src/journal/journald.c
index 83236ceba9..b137e3c7be 100644
--- a/src/journal/journald.c
+++ b/src/journal/journald.c
@@ -61,10 +61,6 @@ int main(int argc, char *argv[]) {
log_debug("systemd-journald running as pid "PID_FMT, getpid());
server_driver_message(&server, SD_MESSAGE_JOURNAL_START, "Journal started");
- sd_notify(false,
- "READY=1\n"
- "STATUS=Processing requests...");
-
for (;;) {
usec_t t = USEC_INFINITY, n;
@@ -117,10 +113,6 @@ int main(int argc, char *argv[]) {
server_driver_message(&server, SD_MESSAGE_JOURNAL_STOP, "Journal stopped");
finish:
- sd_notify(false,
- "STOPPING=1\n"
- "STATUS=Shutting down...");
-
server_done(&server);
return r < 0 ? EXIT_FAILURE : EXIT_SUCCESS;
diff --git a/src/journal/sd-journal.c b/src/journal/sd-journal.c
index 043087485b..5cde7f17f7 100644
--- a/src/journal/sd-journal.c
+++ b/src/journal/sd-journal.c
@@ -73,19 +73,46 @@ static bool journal_pid_changed(sd_journal *j) {
return j->original_pid != getpid();
}
-/* We return an error here only if we didn't manage to
- memorize the real error. */
-static int set_put_error(sd_journal *j, int r) {
+static int journal_put_error(sd_journal *j, int r, const char *path) {
+ char *copy;
int k;
+ /* Memorize an error we encountered, and store which
+ * file/directory it was generated from. Note that we store
+ * only *one* path per error code, as the error code is the
+ * key into the hashmap, and the path is the value. This means
+ * we keep track only of all error kinds, but not of all error
+ * locations. This has the benefit that the hashmap cannot
+ * grow beyond bounds.
+ *
+ * We return an error here only if we didn't manage to
+ * memorize the real error. */
+
if (r >= 0)
return r;
- k = set_ensure_allocated(&j->errors, NULL);
+ k = hashmap_ensure_allocated(&j->errors, NULL);
if (k < 0)
return k;
- return set_put(j->errors, INT_TO_PTR(r));
+ if (path) {
+ copy = strdup(path);
+ if (!copy)
+ return -ENOMEM;
+ } else
+ copy = NULL;
+
+ k = hashmap_put(j->errors, INT_TO_PTR(r), copy);
+ if (k < 0) {
+ free(copy);
+
+ if (k == -EEXIST)
+ return 0;
+
+ return k;
+ }
+
+ return 0;
}
static void detach_location(sd_journal *j) {
@@ -1025,8 +1052,6 @@ _public_ int sd_journal_seek_cursor(sd_journal *j, const char *cursor) {
_public_ int sd_journal_test_cursor(sd_journal *j, const char *cursor) {
int r;
- const char *word, *state;
- size_t l;
Object *o;
assert_return(j, -EINVAL);
@@ -1040,20 +1065,23 @@ _public_ int sd_journal_test_cursor(sd_journal *j, const char *cursor) {
if (r < 0)
return r;
- FOREACH_WORD_SEPARATOR(word, l, cursor, ";", state) {
+ for(;;) {
_cleanup_free_ char *item = NULL;
- sd_id128_t id;
unsigned long long ll;
+ sd_id128_t id;
int k = 0;
- if (l < 2 || word[1] != '=')
- return -EINVAL;
+ r = extract_first_word(&cursor, &item, ";", EXTRACT_DONT_COALESCE_SEPARATORS);
+ if (r < 0)
+ return r;
- item = strndup(word, l);
- if (!item)
- return -ENOMEM;
+ if (r == 0)
+ break;
- switch (word[0]) {
+ if (strlen(item) < 2 || item[1] != '=')
+ return -EINVAL;
+
+ switch (item[0]) {
case 's':
k = sd_id128_from_string(item+2, &id);
@@ -1182,6 +1210,8 @@ static bool file_has_type_prefix(const char *prefix, const char *filename) {
}
static bool file_type_wanted(int flags, const char *filename) {
+ assert(filename);
+
if (!endswith(filename, ".journal") && !endswith(filename, ".journal~"))
return false;
@@ -1206,7 +1236,7 @@ static bool file_type_wanted(int flags, const char *filename) {
static int add_any_file(sd_journal *j, const char *path) {
JournalFile *f = NULL;
- int r;
+ int r, k;
assert(j);
assert(path);
@@ -1215,20 +1245,23 @@ static int add_any_file(sd_journal *j, const char *path) {
return 0;
if (ordered_hashmap_size(j->files) >= JOURNAL_FILES_MAX) {
- log_warning("Too many open journal files, not adding %s.", path);
- return set_put_error(j, -ETOOMANYREFS);
+ log_debug("Too many open journal files, not adding %s.", path);
+ r = -ETOOMANYREFS;
+ goto fail;
}
r = journal_file_open(path, O_RDONLY, 0, false, false, NULL, j->mmap, NULL, &f);
- if (r < 0)
- return r;
+ if (r < 0) {
+ log_debug_errno(r, "Failed to open journal file %s: %m", path);
+ goto fail;
+ }
/* journal_file_dump(f); */
r = ordered_hashmap_put(j->files, f->path, f);
if (r < 0) {
journal_file_close(f);
- return r;
+ goto fail;
}
log_debug("File %s added.", f->path);
@@ -1238,11 +1271,17 @@ static int add_any_file(sd_journal *j, const char *path) {
j->current_invalidate_counter ++;
return 0;
+
+fail:
+ k = journal_put_error(j, r, path);
+ if (k < 0)
+ return k;
+
+ return r;
}
static int add_file(sd_journal *j, const char *prefix, const char *filename) {
- _cleanup_free_ char *path = NULL;
- int r;
+ const char *path;
assert(j);
assert(prefix);
@@ -1252,34 +1291,24 @@ static int add_file(sd_journal *j, const char *prefix, const char *filename) {
!file_type_wanted(j->flags, filename))
return 0;
- path = strjoin(prefix, "/", filename, NULL);
- if (!path)
- return -ENOMEM;
-
- r = add_any_file(j, path);
- if (r == -ENOENT)
- return 0;
- return r;
+ path = strjoina(prefix, "/", filename);
+ return add_any_file(j, path);
}
-static int remove_file(sd_journal *j, const char *prefix, const char *filename) {
- _cleanup_free_ char *path;
+static void remove_file(sd_journal *j, const char *prefix, const char *filename) {
+ const char *path;
JournalFile *f;
assert(j);
assert(prefix);
assert(filename);
- path = strjoin(prefix, "/", filename, NULL);
- if (!path)
- return -ENOMEM;
-
+ path = strjoina(prefix, "/", filename);
f = ordered_hashmap_get(j->files, path);
if (!f)
- return 0;
+ return;
remove_file_real(j, f);
- return 0;
}
static void remove_file_real(sd_journal *j, JournalFile *f) {
@@ -1308,12 +1337,27 @@ static void remove_file_real(sd_journal *j, JournalFile *f) {
j->current_invalidate_counter ++;
}
+static int dirname_is_machine_id(const char *fn) {
+ sd_id128_t id, machine;
+ int r;
+
+ r = sd_id128_get_machine(&machine);
+ if (r < 0)
+ return r;
+
+ r = sd_id128_from_string(fn, &id);
+ if (r < 0)
+ return r;
+
+ return sd_id128_equal(id, machine);
+}
+
static int add_directory(sd_journal *j, const char *prefix, const char *dirname) {
_cleanup_free_ char *path = NULL;
- int r;
_cleanup_closedir_ DIR *d = NULL;
- sd_id128_t id, mid;
+ struct dirent *de = NULL;
Directory *m;
+ int r, k;
assert(j);
assert(prefix);
@@ -1322,35 +1366,36 @@ static int add_directory(sd_journal *j, const char *prefix, const char *dirname)
log_debug("Considering %s/%s.", prefix, dirname);
if ((j->flags & SD_JOURNAL_LOCAL_ONLY) &&
- (sd_id128_from_string(dirname, &id) < 0 ||
- sd_id128_get_machine(&mid) < 0 ||
- !(sd_id128_equal(id, mid) || path_startswith(prefix, "/run"))))
+ !(dirname_is_machine_id(dirname) > 0 || path_startswith(prefix, "/run")))
return 0;
path = strjoin(prefix, "/", dirname, NULL);
- if (!path)
- return -ENOMEM;
+ if (!path) {
+ r = -ENOMEM;
+ goto fail;
+ }
d = opendir(path);
if (!d) {
- log_debug_errno(errno, "Failed to open %s: %m", path);
- if (errno == ENOENT)
- return 0;
- return -errno;
+ r = log_debug_errno(errno, "Failed to open directory %s: %m", path);
+ goto fail;
}
m = hashmap_get(j->directories_by_path, path);
if (!m) {
m = new0(Directory, 1);
- if (!m)
- return -ENOMEM;
+ if (!m) {
+ r = -ENOMEM;
+ goto fail;
+ }
m->is_root = false;
m->path = path;
if (hashmap_put(j->directories_by_path, m->path, m) < 0) {
free(m);
- return -ENOMEM;
+ r = -ENOMEM;
+ goto fail;
}
path = NULL; /* avoid freeing in cleanup */
@@ -1372,41 +1417,30 @@ static int add_directory(sd_journal *j, const char *prefix, const char *dirname)
inotify_rm_watch(j->inotify_fd, m->wd);
}
- for (;;) {
- struct dirent *de;
-
- errno = 0;
- de = readdir(d);
- if (!de && errno != 0) {
- r = -errno;
- log_debug_errno(errno, "Failed to read directory %s: %m", m->path);
- return r;
- }
- if (!de)
- break;
+ FOREACH_DIRENT_ALL(de, d, return log_debug_errno(errno, "Failed to read directory %s: %m", m->path)) {
if (dirent_is_file_with_suffix(de, ".journal") ||
- dirent_is_file_with_suffix(de, ".journal~")) {
- r = add_file(j, m->path, de->d_name);
- if (r < 0) {
- log_debug_errno(r, "Failed to add file %s/%s: %m",
- m->path, de->d_name);
- r = set_put_error(j, r);
- if (r < 0)
- return r;
- }
- }
+ dirent_is_file_with_suffix(de, ".journal~"))
+ (void) add_file(j, m->path, de->d_name);
}
check_network(j, dirfd(d));
return 0;
+
+fail:
+ k = journal_put_error(j, r, path ?: dirname);
+ if (k < 0)
+ return k;
+
+ return r;
}
-static int add_root_directory(sd_journal *j, const char *p) {
+static int add_root_directory(sd_journal *j, const char *p, bool missing_ok) {
_cleanup_closedir_ DIR *d = NULL;
+ struct dirent *de;
Directory *m;
- int r;
+ int r, k;
assert(j);
assert(p);
@@ -1419,26 +1453,35 @@ static int add_root_directory(sd_journal *j, const char *p) {
p = strjoina(j->prefix, p);
d = opendir(p);
- if (!d)
- return -errno;
+ if (!d) {
+ if (errno == ENOENT && missing_ok)
+ return 0;
+
+ r = log_debug_errno(errno, "Failed to open root directory %s: %m", p);
+ goto fail;
+ }
m = hashmap_get(j->directories_by_path, p);
if (!m) {
m = new0(Directory, 1);
- if (!m)
- return -ENOMEM;
+ if (!m) {
+ r = -ENOMEM;
+ goto fail;
+ }
m->is_root = true;
m->path = strdup(p);
if (!m->path) {
free(m);
- return -ENOMEM;
+ r = -ENOMEM;
+ goto fail;
}
if (hashmap_put(j->directories_by_path, m->path, m) < 0) {
free(m->path);
free(m);
- return -ENOMEM;
+ r = -ENOMEM;
+ goto fail;
}
j->current_invalidate_counter ++;
@@ -1461,42 +1504,27 @@ static int add_root_directory(sd_journal *j, const char *p) {
if (j->no_new_files)
return 0;
- for (;;) {
- struct dirent *de;
+ FOREACH_DIRENT_ALL(de, d, return log_debug_errno(errno, "Failed to read directory %s: %m", m->path)) {
sd_id128_t id;
- errno = 0;
- de = readdir(d);
- if (!de && errno != 0) {
- r = -errno;
- log_debug_errno(errno, "Failed to read directory %s: %m", m->path);
- return r;
- }
- if (!de)
- break;
-
if (dirent_is_file_with_suffix(de, ".journal") ||
- dirent_is_file_with_suffix(de, ".journal~")) {
- r = add_file(j, m->path, de->d_name);
- if (r < 0) {
- log_debug_errno(r, "Failed to add file %s/%s: %m",
- m->path, de->d_name);
- r = set_put_error(j, r);
- if (r < 0)
- return r;
- }
- } else if ((de->d_type == DT_DIR || de->d_type == DT_LNK || de->d_type == DT_UNKNOWN) &&
- sd_id128_from_string(de->d_name, &id) >= 0) {
-
- r = add_directory(j, m->path, de->d_name);
- if (r < 0)
- log_debug_errno(r, "Failed to add directory %s/%s: %m", m->path, de->d_name);
- }
+ dirent_is_file_with_suffix(de, ".journal~"))
+ (void) add_file(j, m->path, de->d_name);
+ else if (IN_SET(de->d_type, DT_DIR, DT_LNK, DT_UNKNOWN) &&
+ sd_id128_from_string(de->d_name, &id) >= 0)
+ (void) add_directory(j, m->path, de->d_name);
}
check_network(j, dirfd(d));
return 0;
+
+fail:
+ k = journal_put_error(j, r, p);
+ if (k < 0)
+ return k;
+
+ return r;
}
static void remove_directory(sd_journal *j, Directory *d) {
@@ -1521,8 +1549,8 @@ static void remove_directory(sd_journal *j, Directory *d) {
}
static int add_search_paths(sd_journal *j) {
- int r;
- const char search_paths[] =
+
+ static const char search_paths[] =
"/run/log/journal\0"
"/var/log/journal\0";
const char *p;
@@ -1532,14 +1560,8 @@ static int add_search_paths(sd_journal *j) {
/* We ignore most errors here, since the idea is to only open
* what's actually accessible, and ignore the rest. */
- NULSTR_FOREACH(p, search_paths) {
- r = add_root_directory(j, p);
- if (r < 0 && r != -ENOENT) {
- r = set_put_error(j, r);
- if (r < 0)
- return r;
- }
- }
+ NULSTR_FOREACH(p, search_paths)
+ (void) add_root_directory(j, p, true);
return 0;
}
@@ -1563,17 +1585,14 @@ static int add_current_paths(sd_journal *j) {
if (!dir)
return -ENOMEM;
- r = add_root_directory(j, dir);
- if (r < 0) {
- set_put_error(j, r);
+ r = add_root_directory(j, dir, true);
+ if (r < 0)
return r;
- }
}
return 0;
}
-
static int allocate_inotify(sd_journal *j) {
assert(j);
@@ -1701,11 +1720,9 @@ _public_ int sd_journal_open_directory(sd_journal **ret, const char *path, int f
if (!j)
return -ENOMEM;
- r = add_root_directory(j, path);
- if (r < 0) {
- set_put_error(j, r);
+ r = add_root_directory(j, path, false);
+ if (r < 0)
goto fail;
- }
*ret = j;
return 0;
@@ -1730,10 +1747,8 @@ _public_ int sd_journal_open_files(sd_journal **ret, const char **paths, int fla
STRV_FOREACH(path, paths) {
r = add_any_file(j, *path);
- if (r < 0) {
- log_error_errno(r, "Failed to open %s: %m", *path);
+ if (r < 0)
goto fail;
- }
}
j->no_new_files = true;
@@ -1750,6 +1765,7 @@ fail:
_public_ void sd_journal_close(sd_journal *j) {
Directory *d;
JournalFile *f;
+ char *p;
if (!j)
return;
@@ -1777,10 +1793,13 @@ _public_ void sd_journal_close(sd_journal *j) {
mmap_cache_unref(j->mmap);
}
+ while ((p = hashmap_steal_first(j->errors)))
+ free(p);
+ hashmap_free(j->errors);
+
free(j->path);
free(j->prefix);
free(j->unique_field);
- set_free(j->errors);
free(j);
}
@@ -2073,7 +2092,7 @@ _public_ int sd_journal_get_fd(sd_journal *j) {
if (j->no_new_files)
r = add_current_paths(j);
else if (j->path)
- r = add_root_directory(j, j->path);
+ r = add_root_directory(j, j->path, true);
else
r = add_search_paths(j);
if (r < 0)
@@ -2120,7 +2139,6 @@ _public_ int sd_journal_get_timeout(sd_journal *j, uint64_t *timeout_usec) {
static void process_inotify_event(sd_journal *j, struct inotify_event *e) {
Directory *d;
- int r;
assert(j);
assert(e);
@@ -2136,20 +2154,10 @@ static void process_inotify_event(sd_journal *j, struct inotify_event *e) {
/* Event for a journal file */
- if (e->mask & (IN_CREATE|IN_MOVED_TO|IN_MODIFY|IN_ATTRIB)) {
- r = add_file(j, d->path, e->name);
- if (r < 0) {
- log_debug_errno(r, "Failed to add file %s/%s: %m",
- d->path, e->name);
- set_put_error(j, r);
- }
-
- } else if (e->mask & (IN_DELETE|IN_MOVED_FROM|IN_UNMOUNT)) {
-
- r = remove_file(j, d->path, e->name);
- if (r < 0)
- log_debug_errno(r, "Failed to remove file %s/%s: %m", d->path, e->name);
- }
+ if (e->mask & (IN_CREATE|IN_MOVED_TO|IN_MODIFY|IN_ATTRIB))
+ (void) add_file(j, d->path, e->name);
+ else if (e->mask & (IN_DELETE|IN_MOVED_FROM|IN_UNMOUNT))
+ remove_file(j, d->path, e->name);
} else if (!d->is_root && e->len == 0) {
@@ -2162,11 +2170,8 @@ static void process_inotify_event(sd_journal *j, struct inotify_event *e) {
/* Event for root directory */
- if (e->mask & (IN_CREATE|IN_MOVED_TO|IN_MODIFY|IN_ATTRIB)) {
- r = add_directory(j, d->path, e->name);
- if (r < 0)
- log_debug_errno(r, "Failed to add directory %s/%s: %m", d->path, e->name);
- }
+ if (e->mask & (IN_CREATE|IN_MOVED_TO|IN_MODIFY|IN_ATTRIB))
+ (void) add_directory(j, d->path, e->name);
}
return;
@@ -2175,7 +2180,7 @@ static void process_inotify_event(sd_journal *j, struct inotify_event *e) {
if (e->mask & IN_IGNORED)
return;
- log_warning("Unknown inotify event.");
+ log_debug("Unknown inotify event.");
}
static int determine_change(sd_journal *j) {