summaryrefslogtreecommitdiff
path: root/src/journal/journal-vacuum.c
diff options
context:
space:
mode:
Diffstat (limited to 'src/journal/journal-vacuum.c')
-rw-r--r--src/journal/journal-vacuum.c318
1 files changed, 0 insertions, 318 deletions
diff --git a/src/journal/journal-vacuum.c b/src/journal/journal-vacuum.c
deleted file mode 100644
index 731f6c770f..0000000000
--- a/src/journal/journal-vacuum.c
+++ /dev/null
@@ -1,318 +0,0 @@
-/*-*- Mode: C; c-basic-offset: 8; indent-tabs-mode: nil -*-*/
-
-/***
- This file is part of systemd.
-
- Copyright 2011 Lennart Poettering
-
- systemd is free software; you can redistribute it and/or modify it
- under the terms of the GNU Lesser General Public License as published by
- the Free Software Foundation; either version 2.1 of the License, or
- (at your option) any later version.
-
- systemd is distributed in the hope that it will be useful, but
- WITHOUT ANY WARRANTY; without even the implied warranty of
- MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
- Lesser General Public License for more details.
-
- You should have received a copy of the GNU Lesser General Public License
- along with systemd; If not, see <http://www.gnu.org/licenses/>.
-***/
-
-#include <sys/types.h>
-#include <fcntl.h>
-#include <sys/stat.h>
-#include <sys/statvfs.h>
-#include <unistd.h>
-
-#ifdef HAVE_XATTR
-#include <attr/xattr.h>
-#endif
-
-#include "journal-def.h"
-#include "journal-file.h"
-#include "journal-vacuum.h"
-#include "sd-id128.h"
-#include "util.h"
-
-struct vacuum_info {
- off_t usage;
- char *filename;
-
- uint64_t realtime;
- sd_id128_t seqnum_id;
- uint64_t seqnum;
-
- bool have_seqnum;
-};
-
-static int vacuum_compare(const void *_a, const void *_b) {
- const struct vacuum_info *a, *b;
-
- a = _a;
- b = _b;
-
- if (a->have_seqnum && b->have_seqnum &&
- sd_id128_equal(a->seqnum_id, b->seqnum_id)) {
- if (a->seqnum < b->seqnum)
- return -1;
- else if (a->seqnum > b->seqnum)
- return 1;
- else
- return 0;
- }
-
- if (a->realtime < b->realtime)
- return -1;
- else if (a->realtime > b->realtime)
- return 1;
- else if (a->have_seqnum && b->have_seqnum)
- return memcmp(&a->seqnum_id, &b->seqnum_id, 16);
- else
- return strcmp(a->filename, b->filename);
-}
-
-static void patch_realtime(
- const char *dir,
- const char *fn,
- const struct stat *st,
- unsigned long long *realtime) {
-
- usec_t x;
-
-#ifdef HAVE_XATTR
- uint64_t crtime;
- _cleanup_free_ const char *path = NULL;
-#endif
-
- /* The timestamp was determined by the file name, but let's
- * see if the file might actually be older than the file name
- * suggested... */
-
- assert(dir);
- assert(fn);
- assert(st);
- assert(realtime);
-
- x = timespec_load(&st->st_ctim);
- if (x > 0 && x != (usec_t) -1 && x < *realtime)
- *realtime = x;
-
- x = timespec_load(&st->st_atim);
- if (x > 0 && x != (usec_t) -1 && x < *realtime)
- *realtime = x;
-
- x = timespec_load(&st->st_mtim);
- if (x > 0 && x != (usec_t) -1 && x < *realtime)
- *realtime = x;
-
-#ifdef HAVE_XATTR
- /* Let's read the original creation time, if possible. Ideally
- * we'd just query the creation time the FS might provide, but
- * unfortunately there's currently no sane API to query
- * it. Hence let's implement this manually... */
-
- /* Unfortunately there is is not fgetxattrat(), so we need to
- * go via path here. :-( */
-
- path = strjoin(dir, "/", fn, NULL);
- if (!path)
- return;
-
- if (getxattr(path, "user.crtime_usec", &crtime, sizeof(crtime)) == sizeof(crtime)) {
- crtime = le64toh(crtime);
-
- if (crtime > 0 && crtime != (uint64_t) -1 && crtime < *realtime)
- *realtime = crtime;
- }
-#endif
-}
-
-int journal_directory_vacuum(
- const char *directory,
- uint64_t max_use,
- uint64_t min_free,
- usec_t max_retention_usec,
- usec_t *oldest_usec) {
-
- DIR *d;
- int r = 0;
- struct vacuum_info *list = NULL;
- unsigned n_list = 0, n_allocated = 0, i;
- uint64_t sum = 0;
- usec_t retention_limit = 0;
-
- assert(directory);
-
- if (max_use <= 0 && min_free <= 0 && max_retention_usec <= 0)
- return 0;
-
- if (max_retention_usec > 0) {
- retention_limit = now(CLOCK_REALTIME);
- if (retention_limit > max_retention_usec)
- retention_limit -= max_retention_usec;
- else
- max_retention_usec = retention_limit = 0;
- }
-
- d = opendir(directory);
- if (!d)
- return -errno;
-
- for (;;) {
- int k;
- struct dirent *de;
- union dirent_storage buf;
- size_t q;
- struct stat st;
- char *p;
- unsigned long long seqnum = 0, realtime;
- sd_id128_t seqnum_id;
- bool have_seqnum;
-
- k = readdir_r(d, &buf.de, &de);
- if (k != 0) {
- r = -k;
- goto finish;
- }
-
- if (!de)
- break;
-
- if (fstatat(dirfd(d), de->d_name, &st, AT_SYMLINK_NOFOLLOW) < 0)
- continue;
-
- if (!S_ISREG(st.st_mode))
- continue;
-
- q = strlen(de->d_name);
-
- if (endswith(de->d_name, ".journal")) {
-
- /* Vacuum archived files */
-
- if (q < 1 + 32 + 1 + 16 + 1 + 16 + 8)
- continue;
-
- if (de->d_name[q-8-16-1] != '-' ||
- de->d_name[q-8-16-1-16-1] != '-' ||
- de->d_name[q-8-16-1-16-1-32-1] != '@')
- continue;
-
- p = strdup(de->d_name);
- if (!p) {
- r = -ENOMEM;
- goto finish;
- }
-
- de->d_name[q-8-16-1-16-1] = 0;
- if (sd_id128_from_string(de->d_name + q-8-16-1-16-1-32, &seqnum_id) < 0) {
- free(p);
- continue;
- }
-
- if (sscanf(de->d_name + q-8-16-1-16, "%16llx-%16llx.journal", &seqnum, &realtime) != 2) {
- free(p);
- continue;
- }
-
- have_seqnum = true;
-
- } else if (endswith(de->d_name, ".journal~")) {
- unsigned long long tmp;
-
- /* Vacuum corrupted files */
-
- if (q < 1 + 16 + 1 + 16 + 8 + 1)
- continue;
-
- if (de->d_name[q-1-8-16-1] != '-' ||
- de->d_name[q-1-8-16-1-16-1] != '@')
- continue;
-
- p = strdup(de->d_name);
- if (!p) {
- r = -ENOMEM;
- goto finish;
- }
-
- if (sscanf(de->d_name + q-1-8-16-1-16, "%16llx-%16llx.journal~", &realtime, &tmp) != 2) {
- free(p);
- continue;
- }
-
- have_seqnum = false;
- } else
- /* We do not vacuum active files or unknown files! */
- continue;
-
- patch_realtime(directory, de->d_name, &st, &realtime);
-
- if (n_list >= n_allocated) {
- struct vacuum_info *j;
-
- n_allocated = MAX(n_allocated * 2U, 8U);
- j = realloc(list, n_allocated * sizeof(struct vacuum_info));
- if (!j) {
- free(p);
- r = -ENOMEM;
- goto finish;
- }
-
- list = j;
- }
-
- list[n_list].filename = p;
- list[n_list].usage = 512UL * (uint64_t) st.st_blocks;
- list[n_list].seqnum = seqnum;
- list[n_list].realtime = realtime;
- list[n_list].seqnum_id = seqnum_id;
- list[n_list].have_seqnum = have_seqnum;
-
- sum += list[n_list].usage;
-
- n_list ++;
- }
-
- if (n_list > 0)
- qsort(list, n_list, sizeof(struct vacuum_info), vacuum_compare);
-
- for (i = 0; i < n_list; i++) {
- struct statvfs ss;
-
- if (fstatvfs(dirfd(d), &ss) < 0) {
- r = -errno;
- goto finish;
- }
-
- if ((max_retention_usec <= 0 || list[i].realtime >= retention_limit) &&
- (max_use <= 0 || sum <= max_use) &&
- (min_free <= 0 || (uint64_t) ss.f_bavail * (uint64_t) ss.f_bsize >= min_free))
- break;
-
- if (unlinkat(dirfd(d), list[i].filename, 0) >= 0) {
- log_debug("Deleted archived journal %s/%s.", directory, list[i].filename);
-
- if ((uint64_t) list[i].usage > sum)
- sum -= list[i].usage;
- else
- sum = 0;
-
- } else if (errno != ENOENT)
- log_warning("Failed to delete %s/%s: %m", directory, list[i].filename);
- }
-
- if (oldest_usec && i < n_list && (*oldest_usec == 0 || list[i].realtime < *oldest_usec))
- *oldest_usec = list[i].realtime;
-
-finish:
- for (i = 0; i < n_list; i++)
- free(list[i].filename);
-
- free(list);
-
- if (d)
- closedir(d);
-
- return r;
-}