mirror of
https://github.com/AuxXxilium/eudev.git
synced 2024-11-24 07:20:56 +07:00
journal: rework directory enumeration/watch logic
There's now sd_journal_new_directory() for watching specific journal directories. This is exposed in journalctl -D. sd_journal_wait() and sd_journal_process() now return whether changes in the journal are invalidating or just appending. We now create inotify kernel watches only when we actually need them
This commit is contained in:
parent
e02d1cf72d
commit
a963990ff4
7
TODO
7
TODO
@ -34,6 +34,8 @@ Bugfixes:
|
|||||||
|
|
||||||
Features:
|
Features:
|
||||||
|
|
||||||
|
* compile libsystemd-journal statically into journalctl so that we can share util.c and suchlike
|
||||||
|
|
||||||
* replace BindTo= by BindsTo=, but keep old name for compat
|
* replace BindTo= by BindsTo=, but keep old name for compat
|
||||||
|
|
||||||
* switch-root: sockets need relabelling
|
* switch-root: sockets need relabelling
|
||||||
@ -50,8 +52,6 @@ Features:
|
|||||||
|
|
||||||
* .device aliases need to be implemented with the "following" logic, probably.
|
* .device aliases need to be implemented with the "following" logic, probably.
|
||||||
|
|
||||||
* add sd_journal_wait() to make things easier for sync programs that just want to wait for changes
|
|
||||||
|
|
||||||
* refuse taking lower-case variable names in sd_journal_send() and friends.
|
* refuse taking lower-case variable names in sd_journal_send() and friends.
|
||||||
|
|
||||||
* when running as user instance: implicitly default to WorkingDirectory=$HOME for all services.
|
* when running as user instance: implicitly default to WorkingDirectory=$HOME for all services.
|
||||||
@ -206,9 +206,6 @@ Features:
|
|||||||
|
|
||||||
* support container_ttys=
|
* support container_ttys=
|
||||||
|
|
||||||
* journald: make configurable "store-on-var", "store-on-run", "dont-store", "auto"
|
|
||||||
(store-persistent, store-volatile?)
|
|
||||||
|
|
||||||
* introduce mix of BindTo and Requisite
|
* introduce mix of BindTo and Requisite
|
||||||
|
|
||||||
* journalctl: show multiline log messages sanely, expand tabs, and show all valid utf8 messages
|
* journalctl: show multiline log messages sanely, expand tabs, and show all valid utf8 messages
|
||||||
|
@ -217,6 +217,18 @@
|
|||||||
current boot.</para></listitem>
|
current boot.</para></listitem>
|
||||||
</varlistentry>
|
</varlistentry>
|
||||||
|
|
||||||
|
<varlistentry>
|
||||||
|
<term><option>--directory=</option></term>
|
||||||
|
<term><option>-D</option></term>
|
||||||
|
|
||||||
|
<listitem><para>Takes an absolute
|
||||||
|
directory path as argument. If
|
||||||
|
specified will opearte on the
|
||||||
|
specified journal directory instead of
|
||||||
|
the default runtime and system journal
|
||||||
|
paths.</para></listitem>
|
||||||
|
</varlistentry>
|
||||||
|
|
||||||
<varlistentry>
|
<varlistentry>
|
||||||
<term><option>--new-id128</option></term>
|
<term><option>--new-id128</option></term>
|
||||||
|
|
||||||
|
@ -31,6 +31,14 @@
|
|||||||
#include "list.h"
|
#include "list.h"
|
||||||
|
|
||||||
typedef struct Match Match;
|
typedef struct Match Match;
|
||||||
|
typedef struct Location Location;
|
||||||
|
typedef struct Directory Directory;
|
||||||
|
|
||||||
|
typedef enum location_type {
|
||||||
|
LOCATION_HEAD,
|
||||||
|
LOCATION_TAIL,
|
||||||
|
LOCATION_DISCRETE
|
||||||
|
} location_type_t;
|
||||||
|
|
||||||
struct Match {
|
struct Match {
|
||||||
char *data;
|
char *data;
|
||||||
@ -40,13 +48,7 @@ struct Match {
|
|||||||
LIST_FIELDS(Match, matches);
|
LIST_FIELDS(Match, matches);
|
||||||
};
|
};
|
||||||
|
|
||||||
typedef enum location_type {
|
struct Location {
|
||||||
LOCATION_HEAD,
|
|
||||||
LOCATION_TAIL,
|
|
||||||
LOCATION_DISCRETE
|
|
||||||
} location_type_t;
|
|
||||||
|
|
||||||
typedef struct Location {
|
|
||||||
location_type_t type;
|
location_type_t type;
|
||||||
|
|
||||||
uint64_t seqnum;
|
uint64_t seqnum;
|
||||||
@ -62,7 +64,13 @@ typedef struct Location {
|
|||||||
|
|
||||||
uint64_t xor_hash;
|
uint64_t xor_hash;
|
||||||
bool xor_hash_set;
|
bool xor_hash_set;
|
||||||
} Location;
|
};
|
||||||
|
|
||||||
|
struct Directory {
|
||||||
|
char *path;
|
||||||
|
int wd;
|
||||||
|
bool is_root;
|
||||||
|
};
|
||||||
|
|
||||||
struct sd_journal {
|
struct sd_journal {
|
||||||
int flags;
|
int flags;
|
||||||
@ -73,12 +81,15 @@ struct sd_journal {
|
|||||||
JournalFile *current_file;
|
JournalFile *current_file;
|
||||||
uint64_t current_field;
|
uint64_t current_field;
|
||||||
|
|
||||||
|
Hashmap *directories_by_path;
|
||||||
|
Hashmap *directories_by_wd;
|
||||||
|
|
||||||
int inotify_fd;
|
int inotify_fd;
|
||||||
Hashmap *inotify_wd_dirs;
|
|
||||||
Hashmap *inotify_wd_roots;
|
|
||||||
|
|
||||||
LIST_HEAD(Match, matches);
|
LIST_HEAD(Match, matches);
|
||||||
unsigned n_matches;
|
unsigned n_matches;
|
||||||
|
|
||||||
|
unsigned current_invalidate_counter, last_invalidate_counter;
|
||||||
};
|
};
|
||||||
|
|
||||||
#endif
|
#endif
|
||||||
|
@ -39,6 +39,7 @@
|
|||||||
#include "build.h"
|
#include "build.h"
|
||||||
#include "pager.h"
|
#include "pager.h"
|
||||||
#include "logs-show.h"
|
#include "logs-show.h"
|
||||||
|
#include "strv.h"
|
||||||
|
|
||||||
static OutputMode arg_output = OUTPUT_SHORT;
|
static OutputMode arg_output = OUTPUT_SHORT;
|
||||||
static bool arg_follow = false;
|
static bool arg_follow = false;
|
||||||
@ -50,6 +51,7 @@ static bool arg_new_id128 = false;
|
|||||||
static bool arg_quiet = false;
|
static bool arg_quiet = false;
|
||||||
static bool arg_local = false;
|
static bool arg_local = false;
|
||||||
static bool arg_this_boot = false;
|
static bool arg_this_boot = false;
|
||||||
|
static const char *arg_directory = NULL;
|
||||||
|
|
||||||
static int help(void) {
|
static int help(void) {
|
||||||
|
|
||||||
@ -67,6 +69,7 @@ static int help(void) {
|
|||||||
" -q --quiet Don't show privilege warning\n"
|
" -q --quiet Don't show privilege warning\n"
|
||||||
" -l --local Only local entries\n"
|
" -l --local Only local entries\n"
|
||||||
" -b --this-boot Show data only from current boot\n"
|
" -b --this-boot Show data only from current boot\n"
|
||||||
|
" -D --directory=PATH Show journal files from directory\n"
|
||||||
" --new-id128 Generate a new 128 Bit id\n",
|
" --new-id128 Generate a new 128 Bit id\n",
|
||||||
program_invocation_short_name);
|
program_invocation_short_name);
|
||||||
|
|
||||||
@ -95,6 +98,7 @@ static int parse_argv(int argc, char *argv[]) {
|
|||||||
{ "quiet", no_argument, NULL, 'q' },
|
{ "quiet", no_argument, NULL, 'q' },
|
||||||
{ "local", no_argument, NULL, 'l' },
|
{ "local", no_argument, NULL, 'l' },
|
||||||
{ "this-boot", no_argument, NULL, 'b' },
|
{ "this-boot", no_argument, NULL, 'b' },
|
||||||
|
{ "directory", required_argument, NULL, 'D' },
|
||||||
{ NULL, 0, NULL, 0 }
|
{ NULL, 0, NULL, 0 }
|
||||||
};
|
};
|
||||||
|
|
||||||
@ -103,7 +107,7 @@ static int parse_argv(int argc, char *argv[]) {
|
|||||||
assert(argc >= 0);
|
assert(argc >= 0);
|
||||||
assert(argv);
|
assert(argv);
|
||||||
|
|
||||||
while ((c = getopt_long(argc, argv, "hfo:an:qlb", options, NULL)) >= 0) {
|
while ((c = getopt_long(argc, argv, "hfo:an:qlbD:", options, NULL)) >= 0) {
|
||||||
|
|
||||||
switch (c) {
|
switch (c) {
|
||||||
|
|
||||||
@ -166,6 +170,10 @@ static int parse_argv(int argc, char *argv[]) {
|
|||||||
arg_this_boot = true;
|
arg_this_boot = true;
|
||||||
break;
|
break;
|
||||||
|
|
||||||
|
case 'D':
|
||||||
|
arg_directory = optarg;
|
||||||
|
break;
|
||||||
|
|
||||||
case '?':
|
case '?':
|
||||||
return -EINVAL;
|
return -EINVAL;
|
||||||
|
|
||||||
@ -209,12 +217,88 @@ static int generate_new_id128(void) {
|
|||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
static int add_matches(sd_journal *j, char **args) {
|
||||||
|
char **i;
|
||||||
|
int r;
|
||||||
|
|
||||||
|
assert(j);
|
||||||
|
|
||||||
|
STRV_FOREACH(i, args) {
|
||||||
|
|
||||||
|
if (path_is_absolute(*i)) {
|
||||||
|
char *p;
|
||||||
|
const char *path;
|
||||||
|
struct stat st;
|
||||||
|
|
||||||
|
p = canonicalize_file_name(*i);
|
||||||
|
path = p ? p : *i;
|
||||||
|
|
||||||
|
if (stat(path, &st) < 0) {
|
||||||
|
free(p);
|
||||||
|
log_error("Couldn't stat file: %m");
|
||||||
|
return -errno;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (S_ISREG(st.st_mode) && (0111 & st.st_mode)) {
|
||||||
|
char *t;
|
||||||
|
|
||||||
|
t = strappend("_EXE=", path);
|
||||||
|
if (!t) {
|
||||||
|
free(p);
|
||||||
|
log_error("Out of memory");
|
||||||
|
return -ENOMEM;
|
||||||
|
}
|
||||||
|
|
||||||
|
r = sd_journal_add_match(j, t, strlen(t));
|
||||||
|
free(t);
|
||||||
|
} else {
|
||||||
|
free(p);
|
||||||
|
log_error("File is not a regular file or is not executable: %s", *i);
|
||||||
|
return -EINVAL;
|
||||||
|
}
|
||||||
|
|
||||||
|
free(p);
|
||||||
|
} else
|
||||||
|
r = sd_journal_add_match(j, *i, strlen(*i));
|
||||||
|
|
||||||
|
if (r < 0) {
|
||||||
|
log_error("Failed to add match: %s", strerror(-r));
|
||||||
|
return r;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
static int add_this_boot(sd_journal *j) {
|
||||||
|
char match[9+32+1] = "_BOOT_ID=";
|
||||||
|
sd_id128_t boot_id;
|
||||||
|
int r;
|
||||||
|
|
||||||
|
if (!arg_this_boot)
|
||||||
|
return 0;
|
||||||
|
|
||||||
|
r = sd_id128_get_boot(&boot_id);
|
||||||
|
if (r < 0) {
|
||||||
|
log_error("Failed to get boot id: %s", strerror(-r));
|
||||||
|
return r;
|
||||||
|
}
|
||||||
|
|
||||||
|
sd_id128_to_string(boot_id, match + 9);
|
||||||
|
r = sd_journal_add_match(j, match, strlen(match));
|
||||||
|
if (r < 0) {
|
||||||
|
log_error("Failed to add match: %s", strerror(-r));
|
||||||
|
return r;
|
||||||
|
}
|
||||||
|
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
int main(int argc, char *argv[]) {
|
int main(int argc, char *argv[]) {
|
||||||
int r, i;
|
int r;
|
||||||
sd_journal *j = NULL;
|
sd_journal *j = NULL;
|
||||||
unsigned line = 0;
|
unsigned line = 0;
|
||||||
bool need_seek = false;
|
bool need_seek = false;
|
||||||
struct stat st;
|
|
||||||
|
|
||||||
log_parse_environment();
|
log_parse_environment();
|
||||||
log_open();
|
log_open();
|
||||||
@ -233,73 +317,23 @@ int main(int argc, char *argv[]) {
|
|||||||
log_warning("Showing user generated messages only. Users in the group 'adm' can see all messages. Pass -q to turn this message off.");
|
log_warning("Showing user generated messages only. Users in the group 'adm' can see all messages. Pass -q to turn this message off.");
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
r = sd_journal_open(&j, arg_local ? SD_JOURNAL_LOCAL_ONLY : 0);
|
if (arg_directory)
|
||||||
|
r = sd_journal_open_directory(&j, arg_directory, 0);
|
||||||
|
else
|
||||||
|
r = sd_journal_open(&j, arg_local ? SD_JOURNAL_LOCAL_ONLY : 0);
|
||||||
|
|
||||||
if (r < 0) {
|
if (r < 0) {
|
||||||
log_error("Failed to open journal: %s", strerror(-r));
|
log_error("Failed to open journal: %s", strerror(-r));
|
||||||
goto finish;
|
goto finish;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (arg_this_boot) {
|
r = add_this_boot(j);
|
||||||
char match[9+32+1] = "_BOOT_ID=";
|
if (r < 0)
|
||||||
sd_id128_t boot_id;
|
goto finish;
|
||||||
|
|
||||||
r = sd_id128_get_boot(&boot_id);
|
r = add_matches(j, argv + optind);
|
||||||
if (r < 0) {
|
if (r < 0)
|
||||||
log_error("Failed to get boot id: %s", strerror(-r));
|
goto finish;
|
||||||
goto finish;
|
|
||||||
}
|
|
||||||
|
|
||||||
sd_id128_to_string(boot_id, match + 9);
|
|
||||||
|
|
||||||
r = sd_journal_add_match(j, match, strlen(match));
|
|
||||||
if (r < 0) {
|
|
||||||
log_error("Failed to add match: %s", strerror(-r));
|
|
||||||
goto finish;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
for (i = optind; i < argc; i++) {
|
|
||||||
if (path_is_absolute(argv[i])) {
|
|
||||||
char *p = NULL;
|
|
||||||
const char *path;
|
|
||||||
|
|
||||||
p = canonicalize_file_name(argv[i]);
|
|
||||||
path = p ? p : argv[i];
|
|
||||||
|
|
||||||
if (stat(path, &st) < 0) {
|
|
||||||
free(p);
|
|
||||||
log_error("Couldn't stat file: %m");
|
|
||||||
r = -errno;
|
|
||||||
goto finish;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (S_ISREG(st.st_mode) && (0111 & st.st_mode)) {
|
|
||||||
char *t;
|
|
||||||
|
|
||||||
t = strappend("_EXE=", path);
|
|
||||||
if (!t) {
|
|
||||||
free(p);
|
|
||||||
log_error("Out of memory");
|
|
||||||
goto finish;
|
|
||||||
}
|
|
||||||
|
|
||||||
r = sd_journal_add_match(j, t, strlen(t));
|
|
||||||
free(t);
|
|
||||||
} else {
|
|
||||||
free(p);
|
|
||||||
log_error("File is not a regular file or is not executable: %s", argv[i]);
|
|
||||||
goto finish;
|
|
||||||
}
|
|
||||||
|
|
||||||
free(p);
|
|
||||||
} else
|
|
||||||
r = sd_journal_add_match(j, argv[i], strlen(argv[i]));
|
|
||||||
|
|
||||||
if (r < 0) {
|
|
||||||
log_error("Failed to add match: %s", strerror(-r));
|
|
||||||
goto finish;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
if (!arg_quiet) {
|
if (!arg_quiet) {
|
||||||
usec_t start, end;
|
usec_t start, end;
|
||||||
|
@ -61,4 +61,5 @@ global:
|
|||||||
LIBSYSTEMD_JOURNAL_187 {
|
LIBSYSTEMD_JOURNAL_187 {
|
||||||
global:
|
global:
|
||||||
sd_journal_wait;
|
sd_journal_wait;
|
||||||
|
sd_journal_open_directory;
|
||||||
} LIBSYSTEMD_JOURNAL_184;
|
} LIBSYSTEMD_JOURNAL_184;
|
||||||
|
@ -935,8 +935,8 @@ _public_ int sd_journal_seek_tail(sd_journal *j) {
|
|||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
static int add_file(sd_journal *j, const char *prefix, const char *dir, const char *filename) {
|
static int add_file(sd_journal *j, const char *prefix, const char *filename) {
|
||||||
char *fn;
|
char *path;
|
||||||
int r;
|
int r;
|
||||||
JournalFile *f;
|
JournalFile *f;
|
||||||
|
|
||||||
@ -949,27 +949,23 @@ static int add_file(sd_journal *j, const char *prefix, const char *dir, const ch
|
|||||||
(startswith(filename, "system@") && endswith(filename, ".journal"))))
|
(startswith(filename, "system@") && endswith(filename, ".journal"))))
|
||||||
return 0;
|
return 0;
|
||||||
|
|
||||||
if (dir)
|
path = join(prefix, "/", filename, NULL);
|
||||||
fn = join(prefix, "/", dir, "/", filename, NULL);
|
if (!path)
|
||||||
else
|
|
||||||
fn = join(prefix, "/", filename, NULL);
|
|
||||||
|
|
||||||
if (!fn)
|
|
||||||
return -ENOMEM;
|
return -ENOMEM;
|
||||||
|
|
||||||
if (hashmap_get(j->files, fn)) {
|
if (hashmap_get(j->files, path)) {
|
||||||
free(fn);
|
free(path);
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (hashmap_size(j->files) >= JOURNAL_FILES_MAX) {
|
if (hashmap_size(j->files) >= JOURNAL_FILES_MAX) {
|
||||||
log_debug("Too many open journal files, not adding %s, ignoring.", fn);
|
log_debug("Too many open journal files, not adding %s, ignoring.", path);
|
||||||
free(fn);
|
free(path);
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
r = journal_file_open(fn, O_RDONLY, 0, NULL, &f);
|
r = journal_file_open(path, O_RDONLY, 0, NULL, &f);
|
||||||
free(fn);
|
free(path);
|
||||||
|
|
||||||
if (r < 0) {
|
if (r < 0) {
|
||||||
if (errno == ENOENT)
|
if (errno == ENOENT)
|
||||||
@ -986,83 +982,110 @@ static int add_file(sd_journal *j, const char *prefix, const char *dir, const ch
|
|||||||
return r;
|
return r;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
j->current_invalidate_counter ++;
|
||||||
|
|
||||||
log_debug("File %s got added.", f->path);
|
log_debug("File %s got added.", f->path);
|
||||||
|
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
static int remove_file(sd_journal *j, const char *prefix, const char *dir, const char *filename) {
|
static int remove_file(sd_journal *j, const char *prefix, const char *filename) {
|
||||||
char *fn;
|
char *path;
|
||||||
JournalFile *f;
|
JournalFile *f;
|
||||||
|
|
||||||
assert(j);
|
assert(j);
|
||||||
assert(prefix);
|
assert(prefix);
|
||||||
assert(filename);
|
assert(filename);
|
||||||
|
|
||||||
if (dir)
|
path = join(prefix, "/", filename, NULL);
|
||||||
fn = join(prefix, "/", dir, "/", filename, NULL);
|
if (!path)
|
||||||
else
|
|
||||||
fn = join(prefix, "/", filename, NULL);
|
|
||||||
|
|
||||||
if (!fn)
|
|
||||||
return -ENOMEM;
|
return -ENOMEM;
|
||||||
|
|
||||||
f = hashmap_get(j->files, fn);
|
f = hashmap_get(j->files, path);
|
||||||
free(fn);
|
free(path);
|
||||||
|
|
||||||
if (!f)
|
if (!f)
|
||||||
return 0;
|
return 0;
|
||||||
|
|
||||||
hashmap_remove(j->files, f->path);
|
hashmap_remove(j->files, f->path);
|
||||||
journal_file_close(f);
|
journal_file_close(f);
|
||||||
|
|
||||||
|
j->current_invalidate_counter ++;
|
||||||
|
|
||||||
log_debug("File %s got removed.", f->path);
|
log_debug("File %s got removed.", f->path);
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
static int add_directory(sd_journal *j, const char *prefix, const char *dir) {
|
static int add_directory(sd_journal *j, const char *prefix, const char *dirname) {
|
||||||
char *fn;
|
char *path;
|
||||||
int r;
|
int r;
|
||||||
DIR *d;
|
DIR *d;
|
||||||
int wd;
|
|
||||||
sd_id128_t id, mid;
|
sd_id128_t id, mid;
|
||||||
|
Directory *m;
|
||||||
|
|
||||||
assert(j);
|
assert(j);
|
||||||
assert(prefix);
|
assert(prefix);
|
||||||
assert(dir);
|
assert(dirname);
|
||||||
|
|
||||||
if ((j->flags & SD_JOURNAL_LOCAL_ONLY) &&
|
if ((j->flags & SD_JOURNAL_LOCAL_ONLY) &&
|
||||||
(sd_id128_from_string(dir, &id) < 0 ||
|
(sd_id128_from_string(dirname, &id) < 0 ||
|
||||||
sd_id128_get_machine(&mid) < 0 ||
|
sd_id128_get_machine(&mid) < 0 ||
|
||||||
!sd_id128_equal(id, mid)))
|
!sd_id128_equal(id, mid)))
|
||||||
return 0;
|
return 0;
|
||||||
|
|
||||||
fn = join(prefix, "/", dir, NULL);
|
path = join(prefix, "/", dirname, NULL);
|
||||||
if (!fn)
|
if (!path)
|
||||||
return -ENOMEM;
|
return -ENOMEM;
|
||||||
|
|
||||||
d = opendir(fn);
|
d = opendir(path);
|
||||||
|
|
||||||
if (!d) {
|
if (!d) {
|
||||||
free(fn);
|
log_debug("Failed to open %s: %m", path);
|
||||||
|
free(path);
|
||||||
|
|
||||||
if (errno == ENOENT)
|
if (errno == ENOENT)
|
||||||
return 0;
|
return 0;
|
||||||
|
|
||||||
return -errno;
|
return -errno;
|
||||||
}
|
}
|
||||||
|
|
||||||
wd = inotify_add_watch(j->inotify_fd, fn,
|
m = hashmap_get(j->directories_by_path, path);
|
||||||
IN_CREATE|IN_MOVED_TO|IN_MODIFY|IN_ATTRIB|IN_DELETE|
|
if (!m) {
|
||||||
IN_DELETE_SELF|IN_MOVE_SELF|IN_UNMOUNT|
|
m = new0(Directory, 1);
|
||||||
IN_DONT_FOLLOW|IN_ONLYDIR);
|
if (!m) {
|
||||||
if (wd > 0) {
|
closedir(d);
|
||||||
if (hashmap_put(j->inotify_wd_dirs, INT_TO_PTR(wd), fn) < 0)
|
free(path);
|
||||||
inotify_rm_watch(j->inotify_fd, wd);
|
return -ENOMEM;
|
||||||
else
|
}
|
||||||
fn = NULL;
|
|
||||||
}
|
|
||||||
|
|
||||||
free(fn);
|
m->is_root = false;
|
||||||
|
m->path = path;
|
||||||
|
|
||||||
|
if (hashmap_put(j->directories_by_path, m->path, m) < 0) {
|
||||||
|
closedir(d);
|
||||||
|
free(m->path);
|
||||||
|
free(m);
|
||||||
|
return -ENOMEM;
|
||||||
|
}
|
||||||
|
|
||||||
|
j->current_invalidate_counter ++;
|
||||||
|
|
||||||
|
log_debug("Directory %s got added.", m->path);
|
||||||
|
|
||||||
|
} else if (m->is_root) {
|
||||||
|
free (path);
|
||||||
|
closedir(d);
|
||||||
|
return 0;
|
||||||
|
} else
|
||||||
|
free(path);
|
||||||
|
|
||||||
|
if (m->wd <= 0 && j->inotify_fd >= 0) {
|
||||||
|
|
||||||
|
m->wd = inotify_add_watch(j->inotify_fd, m->path,
|
||||||
|
IN_CREATE|IN_MOVED_TO|IN_MODIFY|IN_ATTRIB|IN_DELETE|
|
||||||
|
IN_DELETE_SELF|IN_MOVE_SELF|IN_UNMOUNT|
|
||||||
|
IN_DONT_FOLLOW|IN_ONLYDIR);
|
||||||
|
|
||||||
|
if (m->wd > 0 && hashmap_put(j->directories_by_wd, INT_TO_PTR(m->wd), m) < 0)
|
||||||
|
inotify_rm_watch(j->inotify_fd, m->wd);
|
||||||
|
}
|
||||||
|
|
||||||
for (;;) {
|
for (;;) {
|
||||||
struct dirent buf, *de;
|
struct dirent buf, *de;
|
||||||
@ -1071,81 +1094,190 @@ static int add_directory(sd_journal *j, const char *prefix, const char *dir) {
|
|||||||
if (r != 0 || !de)
|
if (r != 0 || !de)
|
||||||
break;
|
break;
|
||||||
|
|
||||||
if (!dirent_is_file_with_suffix(de, ".journal"))
|
if (dirent_is_file_with_suffix(de, ".journal")) {
|
||||||
continue;
|
r = add_file(j, m->path, de->d_name);
|
||||||
|
if (r < 0)
|
||||||
r = add_file(j, prefix, dir, de->d_name);
|
log_debug("Failed to add file %s/%s: %s", m->path, de->d_name, strerror(-r));
|
||||||
if (r < 0)
|
}
|
||||||
log_debug("Failed to add file %s/%s/%s: %s", prefix, dir, de->d_name, strerror(-r));
|
|
||||||
}
|
}
|
||||||
|
|
||||||
closedir(d);
|
closedir(d);
|
||||||
|
|
||||||
log_debug("Directory %s/%s got added.", prefix, dir);
|
|
||||||
|
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
static void remove_directory_wd(sd_journal *j, int wd) {
|
static int add_root_directory(sd_journal *j, const char *p) {
|
||||||
char *p;
|
DIR *d;
|
||||||
|
Directory *m;
|
||||||
assert(j);
|
int r;
|
||||||
assert(wd > 0);
|
|
||||||
|
|
||||||
if (j->inotify_fd >= 0)
|
|
||||||
inotify_rm_watch(j->inotify_fd, wd);
|
|
||||||
|
|
||||||
p = hashmap_remove(j->inotify_wd_dirs, INT_TO_PTR(wd));
|
|
||||||
|
|
||||||
if (p) {
|
|
||||||
log_debug("Directory %s got removed.", p);
|
|
||||||
free(p);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
static void add_root_wd(sd_journal *j, const char *p) {
|
|
||||||
int wd;
|
|
||||||
char *k;
|
|
||||||
|
|
||||||
assert(j);
|
assert(j);
|
||||||
assert(p);
|
assert(p);
|
||||||
|
|
||||||
wd = inotify_add_watch(j->inotify_fd, p,
|
if ((j->flags & SD_JOURNAL_RUNTIME_ONLY) &&
|
||||||
IN_CREATE|IN_MOVED_TO|IN_MODIFY|IN_ATTRIB|IN_DELETE|
|
!path_startswith(p, "/run"))
|
||||||
IN_DONT_FOLLOW|IN_ONLYDIR);
|
return -EINVAL;
|
||||||
if (wd <= 0)
|
|
||||||
return;
|
|
||||||
|
|
||||||
k = strdup(p);
|
d = opendir(p);
|
||||||
if (!k || hashmap_put(j->inotify_wd_roots, INT_TO_PTR(wd), k) < 0) {
|
if (!d)
|
||||||
inotify_rm_watch(j->inotify_fd, wd);
|
return -errno;
|
||||||
free(k);
|
|
||||||
|
m = hashmap_get(j->directories_by_path, p);
|
||||||
|
if (!m) {
|
||||||
|
m = new0(Directory, 1);
|
||||||
|
if (!m) {
|
||||||
|
closedir(d);
|
||||||
|
return -ENOMEM;
|
||||||
|
}
|
||||||
|
|
||||||
|
m->is_root = true;
|
||||||
|
m->path = strdup(p);
|
||||||
|
if (!m->path) {
|
||||||
|
closedir(d);
|
||||||
|
free(m);
|
||||||
|
return -ENOMEM;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (hashmap_put(j->directories_by_path, m->path, m) < 0) {
|
||||||
|
closedir(d);
|
||||||
|
free(m->path);
|
||||||
|
free(m);
|
||||||
|
return -ENOMEM;
|
||||||
|
}
|
||||||
|
|
||||||
|
j->current_invalidate_counter ++;
|
||||||
|
|
||||||
|
log_debug("Root directory %s got added.", m->path);
|
||||||
|
|
||||||
|
} else if (!m->is_root) {
|
||||||
|
closedir(d);
|
||||||
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if (m->wd <= 0 && j->inotify_fd >= 0) {
|
||||||
|
|
||||||
|
m->wd = inotify_add_watch(j->inotify_fd, m->path,
|
||||||
|
IN_CREATE|IN_MOVED_TO|IN_MODIFY|IN_ATTRIB|IN_DELETE|
|
||||||
|
IN_DONT_FOLLOW|IN_ONLYDIR);
|
||||||
|
|
||||||
|
if (m->wd > 0 && hashmap_put(j->directories_by_wd, INT_TO_PTR(m->wd), m) < 0)
|
||||||
|
inotify_rm_watch(j->inotify_fd, m->wd);
|
||||||
|
}
|
||||||
|
|
||||||
|
for (;;) {
|
||||||
|
struct dirent buf, *de;
|
||||||
|
sd_id128_t id;
|
||||||
|
|
||||||
|
r = readdir_r(d, &buf, &de);
|
||||||
|
if (r != 0 || !de)
|
||||||
|
break;
|
||||||
|
|
||||||
|
if (dirent_is_file_with_suffix(de, ".journal")) {
|
||||||
|
r = add_file(j, m->path, de->d_name);
|
||||||
|
if (r < 0)
|
||||||
|
log_debug("Failed to add file %s/%s: %s", m->path, de->d_name, strerror(-r));
|
||||||
|
|
||||||
|
} else if ((de->d_type == DT_DIR || 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("Failed to add directory %s/%s: %s", m->path, de->d_name, strerror(-r));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
closedir(d);
|
||||||
|
|
||||||
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
static void remove_root_wd(sd_journal *j, int wd) {
|
static int remove_directory(sd_journal *j, Directory *d) {
|
||||||
char *p;
|
assert(j);
|
||||||
|
|
||||||
|
if (d->wd > 0) {
|
||||||
|
hashmap_remove(j->directories_by_wd, INT_TO_PTR(d->wd));
|
||||||
|
|
||||||
|
if (j->inotify_fd >= 0)
|
||||||
|
inotify_rm_watch(j->inotify_fd, d->wd);
|
||||||
|
}
|
||||||
|
|
||||||
|
hashmap_remove(j->directories_by_path, d->path);
|
||||||
|
|
||||||
|
if (d->is_root)
|
||||||
|
log_debug("Root directory %s got removed.", d->path);
|
||||||
|
else
|
||||||
|
log_debug("Directory %s got removed.", d->path);
|
||||||
|
|
||||||
|
free(d->path);
|
||||||
|
free(d);
|
||||||
|
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
static int add_search_paths(sd_journal *j) {
|
||||||
|
|
||||||
|
const char search_paths[] =
|
||||||
|
"/run/log/journal\0"
|
||||||
|
"/var/log/journal\0";
|
||||||
|
const char *p;
|
||||||
|
|
||||||
assert(j);
|
assert(j);
|
||||||
assert(wd > 0);
|
|
||||||
|
|
||||||
if (j->inotify_fd >= 0)
|
/* We ignore most errors here, since the idea is to only open
|
||||||
inotify_rm_watch(j->inotify_fd, wd);
|
* what's actually accessible, and ignore the rest. */
|
||||||
|
|
||||||
p = hashmap_remove(j->inotify_wd_roots, INT_TO_PTR(wd));
|
NULSTR_FOREACH(p, search_paths)
|
||||||
|
add_root_directory(j, p);
|
||||||
|
|
||||||
if (p) {
|
return 0;
|
||||||
log_debug("Root %s got removed.", p);
|
}
|
||||||
free(p);
|
|
||||||
|
static int allocate_inotify(sd_journal *j) {
|
||||||
|
assert(j);
|
||||||
|
|
||||||
|
if (j->inotify_fd < 0) {
|
||||||
|
j->inotify_fd = inotify_init1(IN_NONBLOCK|IN_CLOEXEC);
|
||||||
|
if (j->inotify_fd < 0)
|
||||||
|
return -errno;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if (!j->directories_by_wd) {
|
||||||
|
j->directories_by_wd = hashmap_new(trivial_hash_func, trivial_compare_func);
|
||||||
|
if (!j->directories_by_wd)
|
||||||
|
return -ENOMEM;
|
||||||
|
}
|
||||||
|
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
static sd_journal *journal_new(int flags) {
|
||||||
|
sd_journal *j;
|
||||||
|
|
||||||
|
j = new0(sd_journal, 1);
|
||||||
|
if (!j)
|
||||||
|
return NULL;
|
||||||
|
|
||||||
|
j->inotify_fd = -1;
|
||||||
|
j->flags = flags;
|
||||||
|
|
||||||
|
j->files = hashmap_new(string_hash_func, string_compare_func);
|
||||||
|
if (!j->files) {
|
||||||
|
free(j);
|
||||||
|
return NULL;
|
||||||
|
}
|
||||||
|
|
||||||
|
j->directories_by_path = hashmap_new(string_hash_func, string_compare_func);
|
||||||
|
if (!j->directories_by_path) {
|
||||||
|
hashmap_free(j->files);
|
||||||
|
free(j);
|
||||||
|
return NULL;
|
||||||
|
}
|
||||||
|
|
||||||
|
return j;
|
||||||
}
|
}
|
||||||
|
|
||||||
_public_ int sd_journal_open(sd_journal **ret, int flags) {
|
_public_ int sd_journal_open(sd_journal **ret, int flags) {
|
||||||
sd_journal *j;
|
sd_journal *j;
|
||||||
const char *p;
|
|
||||||
const char search_paths[] =
|
|
||||||
"/run/log/journal\0"
|
|
||||||
"/var/log/journal\0";
|
|
||||||
int r;
|
int r;
|
||||||
|
|
||||||
if (!ret)
|
if (!ret)
|
||||||
@ -1156,75 +1288,13 @@ _public_ int sd_journal_open(sd_journal **ret, int flags) {
|
|||||||
SD_JOURNAL_SYSTEM_ONLY))
|
SD_JOURNAL_SYSTEM_ONLY))
|
||||||
return -EINVAL;
|
return -EINVAL;
|
||||||
|
|
||||||
j = new0(sd_journal, 1);
|
j = journal_new(flags);
|
||||||
if (!j)
|
if (!j)
|
||||||
return -ENOMEM;
|
return -ENOMEM;
|
||||||
|
|
||||||
j->flags = flags;
|
r = add_search_paths(j);
|
||||||
|
if (r < 0)
|
||||||
j->inotify_fd = inotify_init1(IN_NONBLOCK|IN_CLOEXEC);
|
|
||||||
if (j->inotify_fd < 0) {
|
|
||||||
r = -errno;
|
|
||||||
goto fail;
|
goto fail;
|
||||||
}
|
|
||||||
|
|
||||||
j->files = hashmap_new(string_hash_func, string_compare_func);
|
|
||||||
if (!j->files) {
|
|
||||||
r = -ENOMEM;
|
|
||||||
goto fail;
|
|
||||||
}
|
|
||||||
|
|
||||||
j->inotify_wd_dirs = hashmap_new(trivial_hash_func, trivial_compare_func);
|
|
||||||
j->inotify_wd_roots = hashmap_new(trivial_hash_func, trivial_compare_func);
|
|
||||||
|
|
||||||
if (!j->inotify_wd_dirs || !j->inotify_wd_roots) {
|
|
||||||
r = -ENOMEM;
|
|
||||||
goto fail;
|
|
||||||
}
|
|
||||||
|
|
||||||
/* 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) {
|
|
||||||
DIR *d;
|
|
||||||
|
|
||||||
if ((flags & SD_JOURNAL_RUNTIME_ONLY) &&
|
|
||||||
!path_startswith(p, "/run"))
|
|
||||||
continue;
|
|
||||||
|
|
||||||
d = opendir(p);
|
|
||||||
if (!d) {
|
|
||||||
if (errno != ENOENT)
|
|
||||||
log_debug("Failed to open %s: %m", p);
|
|
||||||
continue;
|
|
||||||
}
|
|
||||||
|
|
||||||
add_root_wd(j, p);
|
|
||||||
|
|
||||||
for (;;) {
|
|
||||||
struct dirent buf, *de;
|
|
||||||
sd_id128_t id;
|
|
||||||
|
|
||||||
r = readdir_r(d, &buf, &de);
|
|
||||||
if (r != 0 || !de)
|
|
||||||
break;
|
|
||||||
|
|
||||||
if (dirent_is_file_with_suffix(de, ".journal")) {
|
|
||||||
r = add_file(j, p, NULL, de->d_name);
|
|
||||||
if (r < 0)
|
|
||||||
log_debug("Failed to add file %s/%s: %s", p, de->d_name, strerror(-r));
|
|
||||||
|
|
||||||
} else if ((de->d_type == DT_DIR || de->d_type == DT_UNKNOWN) &&
|
|
||||||
sd_id128_from_string(de->d_name, &id) >= 0) {
|
|
||||||
|
|
||||||
r = add_directory(j, p, de->d_name);
|
|
||||||
if (r < 0)
|
|
||||||
log_debug("Failed to add directory %s/%s: %s", p, de->d_name, strerror(-r));
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
closedir(d);
|
|
||||||
}
|
|
||||||
|
|
||||||
*ret = j;
|
*ret = j;
|
||||||
return 0;
|
return 0;
|
||||||
@ -1233,44 +1303,64 @@ fail:
|
|||||||
sd_journal_close(j);
|
sd_journal_close(j);
|
||||||
|
|
||||||
return r;
|
return r;
|
||||||
};
|
}
|
||||||
|
|
||||||
|
_public_ int sd_journal_open_directory(sd_journal **ret, const char *path, int flags) {
|
||||||
|
sd_journal *j;
|
||||||
|
int r;
|
||||||
|
|
||||||
|
if (!ret)
|
||||||
|
return -EINVAL;
|
||||||
|
|
||||||
|
if (!path || !path_is_absolute(path))
|
||||||
|
return -EINVAL;
|
||||||
|
|
||||||
|
if (flags != 0)
|
||||||
|
return -EINVAL;
|
||||||
|
|
||||||
|
j = journal_new(flags);
|
||||||
|
if (!j)
|
||||||
|
return -ENOMEM;
|
||||||
|
|
||||||
|
r = add_root_directory(j, path);
|
||||||
|
if (r < 0)
|
||||||
|
goto fail;
|
||||||
|
|
||||||
|
*ret = j;
|
||||||
|
return 0;
|
||||||
|
|
||||||
|
fail:
|
||||||
|
sd_journal_close(j);
|
||||||
|
|
||||||
|
return r;
|
||||||
|
}
|
||||||
|
|
||||||
_public_ void sd_journal_close(sd_journal *j) {
|
_public_ void sd_journal_close(sd_journal *j) {
|
||||||
|
Directory *d;
|
||||||
|
JournalFile *f;
|
||||||
|
|
||||||
if (!j)
|
if (!j)
|
||||||
return;
|
return;
|
||||||
|
|
||||||
if (j->inotify_wd_dirs) {
|
while ((f = hashmap_steal_first(j->files)))
|
||||||
void *k;
|
journal_file_close(f);
|
||||||
|
|
||||||
while ((k = hashmap_first_key(j->inotify_wd_dirs)))
|
hashmap_free(j->files);
|
||||||
remove_directory_wd(j, PTR_TO_INT(k));
|
|
||||||
|
|
||||||
hashmap_free(j->inotify_wd_dirs);
|
while ((d = hashmap_first(j->directories_by_path)))
|
||||||
}
|
remove_directory(j, d);
|
||||||
|
|
||||||
if (j->inotify_wd_roots) {
|
while ((d = hashmap_first(j->directories_by_wd)))
|
||||||
void *k;
|
remove_directory(j, d);
|
||||||
|
|
||||||
while ((k = hashmap_first_key(j->inotify_wd_roots)))
|
hashmap_free(j->directories_by_path);
|
||||||
remove_root_wd(j, PTR_TO_INT(k));
|
hashmap_free(j->directories_by_wd);
|
||||||
|
|
||||||
hashmap_free(j->inotify_wd_roots);
|
|
||||||
}
|
|
||||||
|
|
||||||
if (j->files) {
|
|
||||||
JournalFile *f;
|
|
||||||
|
|
||||||
while ((f = hashmap_steal_first(j->files)))
|
|
||||||
journal_file_close(f);
|
|
||||||
|
|
||||||
hashmap_free(j->files);
|
|
||||||
}
|
|
||||||
|
|
||||||
sd_journal_flush_matches(j);
|
|
||||||
|
|
||||||
if (j->inotify_fd >= 0)
|
if (j->inotify_fd >= 0)
|
||||||
close_nointr_nofail(j->inotify_fd);
|
close_nointr_nofail(j->inotify_fd);
|
||||||
|
|
||||||
|
sd_journal_flush_matches(j);
|
||||||
|
|
||||||
free(j);
|
free(j);
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -1506,52 +1596,37 @@ _public_ void sd_journal_restart_data(sd_journal *j) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
_public_ int sd_journal_get_fd(sd_journal *j) {
|
_public_ int sd_journal_get_fd(sd_journal *j) {
|
||||||
|
int r;
|
||||||
|
|
||||||
if (!j)
|
if (!j)
|
||||||
return -EINVAL;
|
return -EINVAL;
|
||||||
|
|
||||||
|
if (j->inotify_fd >= 0)
|
||||||
|
return j->inotify_fd;
|
||||||
|
|
||||||
|
r = allocate_inotify(j);
|
||||||
|
if (r < 0)
|
||||||
|
return r;
|
||||||
|
|
||||||
|
/* Iterate through all dirs again, to add them to the
|
||||||
|
* inotify */
|
||||||
|
r = add_search_paths(j);
|
||||||
|
if (r < 0)
|
||||||
|
return r;
|
||||||
|
|
||||||
return j->inotify_fd;
|
return j->inotify_fd;
|
||||||
}
|
}
|
||||||
|
|
||||||
static void process_inotify_event(sd_journal *j, struct inotify_event *e) {
|
static void process_inotify_event(sd_journal *j, struct inotify_event *e) {
|
||||||
char *p;
|
Directory *d;
|
||||||
int r;
|
int r;
|
||||||
|
|
||||||
assert(j);
|
assert(j);
|
||||||
assert(e);
|
assert(e);
|
||||||
|
|
||||||
/* Is this a subdirectory we watch? */
|
/* Is this a subdirectory we watch? */
|
||||||
p = hashmap_get(j->inotify_wd_dirs, INT_TO_PTR(e->wd));
|
d = hashmap_get(j->directories_by_wd, INT_TO_PTR(e->wd));
|
||||||
if (p) {
|
if (d) {
|
||||||
|
|
||||||
if (!(e->mask & IN_ISDIR) && e->len > 0 && endswith(e->name, ".journal")) {
|
|
||||||
|
|
||||||
/* Event for a journal file */
|
|
||||||
|
|
||||||
if (e->mask & (IN_CREATE|IN_MOVED_TO|IN_MODIFY|IN_ATTRIB)) {
|
|
||||||
r = add_file(j, p, NULL, e->name);
|
|
||||||
if (r < 0)
|
|
||||||
log_debug("Failed to add file %s/%s: %s", p, e->name, strerror(-r));
|
|
||||||
} else if (e->mask & (IN_DELETE|IN_UNMOUNT)) {
|
|
||||||
|
|
||||||
r = remove_file(j, p, NULL, e->name);
|
|
||||||
if (r < 0)
|
|
||||||
log_debug("Failed to remove file %s/%s: %s", p, e->name, strerror(-r));
|
|
||||||
}
|
|
||||||
|
|
||||||
} else if (e->len == 0) {
|
|
||||||
|
|
||||||
/* Event for the directory itself */
|
|
||||||
|
|
||||||
if (e->mask & (IN_DELETE_SELF|IN_MOVE_SELF|IN_UNMOUNT))
|
|
||||||
remove_directory_wd(j, e->wd);
|
|
||||||
}
|
|
||||||
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
/* Must be the root directory then? */
|
|
||||||
p = hashmap_get(j->inotify_wd_roots, INT_TO_PTR(e->wd));
|
|
||||||
if (p) {
|
|
||||||
sd_id128_t id;
|
sd_id128_t id;
|
||||||
|
|
||||||
if (!(e->mask & IN_ISDIR) && e->len > 0 && endswith(e->name, ".journal")) {
|
if (!(e->mask & IN_ISDIR) && e->len > 0 && endswith(e->name, ".journal")) {
|
||||||
@ -1559,25 +1634,36 @@ static void process_inotify_event(sd_journal *j, struct inotify_event *e) {
|
|||||||
/* Event for a journal file */
|
/* Event for a journal file */
|
||||||
|
|
||||||
if (e->mask & (IN_CREATE|IN_MOVED_TO|IN_MODIFY|IN_ATTRIB)) {
|
if (e->mask & (IN_CREATE|IN_MOVED_TO|IN_MODIFY|IN_ATTRIB)) {
|
||||||
r = add_file(j, p, NULL, e->name);
|
r = add_file(j, d->path, e->name);
|
||||||
if (r < 0)
|
if (r < 0)
|
||||||
log_debug("Failed to add file %s/%s: %s", p, e->name, strerror(-r));
|
log_debug("Failed to add file %s/%s: %s", d->path, e->name, strerror(-r));
|
||||||
|
|
||||||
} else if (e->mask & (IN_DELETE|IN_UNMOUNT)) {
|
} else if (e->mask & (IN_DELETE|IN_UNMOUNT)) {
|
||||||
|
|
||||||
r = remove_file(j, p, NULL, e->name);
|
r = remove_file(j, d->path, e->name);
|
||||||
if (r < 0)
|
if (r < 0)
|
||||||
log_debug("Failed to remove file %s/%s: %s", p, e->name, strerror(-r));
|
log_debug("Failed to remove file %s/%s: %s", d->path, e->name, strerror(-r));
|
||||||
}
|
}
|
||||||
|
|
||||||
} else if ((e->mask & IN_ISDIR) && e->len > 0 && sd_id128_from_string(e->name, &id) >= 0) {
|
} else if (!d->is_root && e->len == 0) {
|
||||||
|
|
||||||
/* Event for subdirectory */
|
/* Event for a subdirectory */
|
||||||
|
|
||||||
|
if (e->mask & (IN_DELETE_SELF|IN_MOVE_SELF|IN_UNMOUNT)) {
|
||||||
|
r = remove_directory(j, d);
|
||||||
|
if (r < 0)
|
||||||
|
log_debug("Failed to remove directory %s: %s", d->path, strerror(-r));
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
} else if (d->is_root && (e->mask & IN_ISDIR) && e->len > 0 && sd_id128_from_string(e->name, &id) >= 0) {
|
||||||
|
|
||||||
|
/* Event for root directory */
|
||||||
|
|
||||||
if (e->mask & (IN_CREATE|IN_MOVED_TO|IN_MODIFY|IN_ATTRIB)) {
|
if (e->mask & (IN_CREATE|IN_MOVED_TO|IN_MODIFY|IN_ATTRIB)) {
|
||||||
|
r = add_directory(j, d->path, e->name);
|
||||||
r = add_directory(j, p, e->name);
|
|
||||||
if (r < 0)
|
if (r < 0)
|
||||||
log_debug("Failed to add directory %s/%s: %s", p, e->name, strerror(-r));
|
log_debug("Failed to add directory %s/%s: %s", d->path, e->name, strerror(-r));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -1590,8 +1676,20 @@ static void process_inotify_event(sd_journal *j, struct inotify_event *e) {
|
|||||||
log_warning("Unknown inotify event.");
|
log_warning("Unknown inotify event.");
|
||||||
}
|
}
|
||||||
|
|
||||||
|
static int determine_change(sd_journal *j) {
|
||||||
|
bool b;
|
||||||
|
|
||||||
|
assert(j);
|
||||||
|
|
||||||
|
b = j->current_invalidate_counter != j->last_invalidate_counter;
|
||||||
|
j->last_invalidate_counter = j->current_invalidate_counter;
|
||||||
|
|
||||||
|
return b ? SD_JOURNAL_INVALIDATE : SD_JOURNAL_APPEND;
|
||||||
|
}
|
||||||
|
|
||||||
_public_ int sd_journal_process(sd_journal *j) {
|
_public_ int sd_journal_process(sd_journal *j) {
|
||||||
uint8_t buffer[sizeof(struct inotify_event) + FILENAME_MAX];
|
uint8_t buffer[sizeof(struct inotify_event) + FILENAME_MAX];
|
||||||
|
bool got_something = false;
|
||||||
|
|
||||||
if (!j)
|
if (!j)
|
||||||
return -EINVAL;
|
return -EINVAL;
|
||||||
@ -1602,12 +1700,14 @@ _public_ int sd_journal_process(sd_journal *j) {
|
|||||||
|
|
||||||
l = read(j->inotify_fd, buffer, sizeof(buffer));
|
l = read(j->inotify_fd, buffer, sizeof(buffer));
|
||||||
if (l < 0) {
|
if (l < 0) {
|
||||||
if (errno == EINTR || errno == EAGAIN)
|
if (errno == EAGAIN || errno == EINTR)
|
||||||
return 0;
|
return got_something ? determine_change(j) : SD_JOURNAL_NOP;
|
||||||
|
|
||||||
return -errno;
|
return -errno;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
got_something = true;
|
||||||
|
|
||||||
e = (struct inotify_event*) buffer;
|
e = (struct inotify_event*) buffer;
|
||||||
while (l > 0) {
|
while (l > 0) {
|
||||||
size_t step;
|
size_t step;
|
||||||
@ -1621,20 +1721,38 @@ _public_ int sd_journal_process(sd_journal *j) {
|
|||||||
l -= step;
|
l -= step;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
return determine_change(j);
|
||||||
}
|
}
|
||||||
|
|
||||||
_public_ int sd_journal_wait(sd_journal *j, uint64_t timeout_usec) {
|
_public_ int sd_journal_wait(sd_journal *j, uint64_t timeout_usec) {
|
||||||
int r, k;
|
int r;
|
||||||
|
|
||||||
assert(j);
|
assert(j);
|
||||||
|
|
||||||
r = fd_wait_for_event(j->inotify_fd, POLLIN, timeout_usec);
|
if (j->inotify_fd < 0) {
|
||||||
k = sd_journal_process(j);
|
|
||||||
|
/* This is the first invocation, hence create the
|
||||||
|
* inotify watch */
|
||||||
|
r = sd_journal_get_fd(j);
|
||||||
|
if (r < 0)
|
||||||
|
return r;
|
||||||
|
|
||||||
|
/* The journal might have changed since the context
|
||||||
|
* object was created and we weren't watching before,
|
||||||
|
* hence don't wait for anything, and return
|
||||||
|
* immediately. */
|
||||||
|
return determine_change(j);
|
||||||
|
}
|
||||||
|
|
||||||
|
do {
|
||||||
|
r = fd_wait_for_event(j->inotify_fd, POLLIN, timeout_usec);
|
||||||
|
} while (r == -EINTR);
|
||||||
|
|
||||||
if (r < 0)
|
if (r < 0)
|
||||||
return r;
|
return r;
|
||||||
|
|
||||||
return k;
|
return sd_journal_process(j);
|
||||||
}
|
}
|
||||||
|
|
||||||
_public_ int sd_journal_get_cutoff_realtime_usec(sd_journal *j, uint64_t *from, uint64_t *to) {
|
_public_ int sd_journal_get_cutoff_realtime_usec(sd_journal *j, uint64_t *from, uint64_t *to) {
|
||||||
|
@ -72,6 +72,7 @@ enum {
|
|||||||
};
|
};
|
||||||
|
|
||||||
int sd_journal_open(sd_journal **ret, int flags);
|
int sd_journal_open(sd_journal **ret, int flags);
|
||||||
|
int sd_journal_open_directory(sd_journal **ret, const char *path, int flags);
|
||||||
void sd_journal_close(sd_journal *j);
|
void sd_journal_close(sd_journal *j);
|
||||||
|
|
||||||
int sd_journal_previous(sd_journal *j);
|
int sd_journal_previous(sd_journal *j);
|
||||||
@ -107,8 +108,7 @@ int sd_journal_get_cutoff_monotonic_usec(sd_journal *j, const sd_id128_t boot_id
|
|||||||
enum {
|
enum {
|
||||||
SD_JOURNAL_NOP,
|
SD_JOURNAL_NOP,
|
||||||
SD_JOURNAL_APPEND,
|
SD_JOURNAL_APPEND,
|
||||||
SD_JOURNAL_INVALIDATE_ADD,
|
SD_JOURNAL_INVALIDATE
|
||||||
SD_JOURNAL_INVALIDATE_REMOVE
|
|
||||||
};
|
};
|
||||||
|
|
||||||
int sd_journal_get_fd(sd_journal *j);
|
int sd_journal_get_fd(sd_journal *j);
|
||||||
|
Loading…
Reference in New Issue
Block a user