]> git.ipfire.org Git - thirdparty/systemd.git/blame - src/journal/journal-vacuum.c
util: fix bad strstrip() return value in normalize_env_assignment()
[thirdparty/systemd.git] / src / journal / journal-vacuum.c
CommitLineData
0284adc6
LP
1/*-*- Mode: C; c-basic-offset: 8; indent-tabs-mode: nil -*-*/
2
3/***
4 This file is part of systemd.
5
6 Copyright 2011 Lennart Poettering
7
8 systemd is free software; you can redistribute it and/or modify it
9 under the terms of the GNU Lesser General Public License as published by
10 the Free Software Foundation; either version 2.1 of the License, or
11 (at your option) any later version.
12
13 systemd is distributed in the hope that it will be useful, but
14 WITHOUT ANY WARRANTY; without even the implied warranty of
15 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
16 Lesser General Public License for more details.
17
18 You should have received a copy of the GNU Lesser General Public License
19 along with systemd; If not, see <http://www.gnu.org/licenses/>.
20***/
21
22#include <sys/types.h>
23#include <fcntl.h>
24#include <sys/stat.h>
25#include <sys/statvfs.h>
26#include <unistd.h>
27
28#include "journal-def.h"
29#include "journal-file.h"
30#include "journal-vacuum.h"
31#include "sd-id128.h"
32#include "util.h"
33
34struct vacuum_info {
35 off_t usage;
36 char *filename;
37
38 uint64_t realtime;
39 sd_id128_t seqnum_id;
40 uint64_t seqnum;
41
42 bool have_seqnum;
43};
44
45static int vacuum_compare(const void *_a, const void *_b) {
46 const struct vacuum_info *a, *b;
47
48 a = _a;
49 b = _b;
50
51 if (a->have_seqnum && b->have_seqnum &&
52 sd_id128_equal(a->seqnum_id, b->seqnum_id)) {
53 if (a->seqnum < b->seqnum)
54 return -1;
55 else if (a->seqnum > b->seqnum)
56 return 1;
57 else
58 return 0;
59 }
60
61 if (a->realtime < b->realtime)
62 return -1;
63 else if (a->realtime > b->realtime)
64 return 1;
65 else if (a->have_seqnum && b->have_seqnum)
66 return memcmp(&a->seqnum_id, &b->seqnum_id, 16);
67 else
68 return strcmp(a->filename, b->filename);
69}
70
71int journal_directory_vacuum(const char *directory, uint64_t max_use, uint64_t min_free) {
72 DIR *d;
73 int r = 0;
74 struct vacuum_info *list = NULL;
75 unsigned n_list = 0, n_allocated = 0, i;
76 uint64_t sum = 0;
77
78 assert(directory);
79
80 if (max_use <= 0)
81 return 0;
82
83 d = opendir(directory);
84 if (!d)
85 return -errno;
86
87 for (;;) {
88 int k;
89 struct dirent buf, *de;
90 size_t q;
91 struct stat st;
92 char *p;
93 unsigned long long seqnum = 0, realtime;
94 sd_id128_t seqnum_id;
95 bool have_seqnum;
96
97 k = readdir_r(d, &buf, &de);
98 if (k != 0) {
99 r = -k;
100 goto finish;
101 }
102
103 if (!de)
104 break;
105
106 if (fstatat(dirfd(d), de->d_name, &st, AT_SYMLINK_NOFOLLOW) < 0)
107 continue;
108
109 if (!S_ISREG(st.st_mode))
110 continue;
111
112 q = strlen(de->d_name);
113
114 if (endswith(de->d_name, ".journal")) {
115
116 /* Vacuum archived files */
117
118 if (q < 1 + 32 + 1 + 16 + 1 + 16 + 8)
119 continue;
120
121 if (de->d_name[q-8-16-1] != '-' ||
122 de->d_name[q-8-16-1-16-1] != '-' ||
123 de->d_name[q-8-16-1-16-1-32-1] != '@')
124 continue;
125
126 p = strdup(de->d_name);
127 if (!p) {
128 r = -ENOMEM;
129 goto finish;
130 }
131
132 de->d_name[q-8-16-1-16-1] = 0;
133 if (sd_id128_from_string(de->d_name + q-8-16-1-16-1-32, &seqnum_id) < 0) {
134 free(p);
135 continue;
136 }
137
138 if (sscanf(de->d_name + q-8-16-1-16, "%16llx-%16llx.journal", &seqnum, &realtime) != 2) {
139 free(p);
140 continue;
141 }
142
143 have_seqnum = true;
144
145 } else if (endswith(de->d_name, ".journal~")) {
146 unsigned long long tmp;
147
148 /* Vacuum corrupted files */
149
150 if (q < 1 + 16 + 1 + 16 + 8 + 1)
151 continue;
152
153 if (de->d_name[q-1-8-16-1] != '-' ||
154 de->d_name[q-1-8-16-1-16-1] != '@')
155 continue;
156
157 p = strdup(de->d_name);
158 if (!p) {
159 r = -ENOMEM;
160 goto finish;
161 }
162
163 if (sscanf(de->d_name + q-1-8-16-1-16, "%16llx-%16llx.journal~", &realtime, &tmp) != 2) {
164 free(p);
165 continue;
166 }
167
168 have_seqnum = false;
169 } else
170 continue;
171
172 if (n_list >= n_allocated) {
173 struct vacuum_info *j;
174
175 n_allocated = MAX(n_allocated * 2U, 8U);
176 j = realloc(list, n_allocated * sizeof(struct vacuum_info));
177 if (!j) {
178 free(p);
179 r = -ENOMEM;
180 goto finish;
181 }
182
183 list = j;
184 }
185
186 list[n_list].filename = p;
187 list[n_list].usage = 512UL * (uint64_t) st.st_blocks;
188 list[n_list].seqnum = seqnum;
189 list[n_list].realtime = realtime;
190 list[n_list].seqnum_id = seqnum_id;
191 list[n_list].have_seqnum = have_seqnum;
192
193 sum += list[n_list].usage;
194
195 n_list ++;
196 }
197
198 if (n_list > 0)
199 qsort(list, n_list, sizeof(struct vacuum_info), vacuum_compare);
200
201 for(i = 0; i < n_list; i++) {
202 struct statvfs ss;
203
204 if (fstatvfs(dirfd(d), &ss) < 0) {
205 r = -errno;
206 goto finish;
207 }
208
209 if (sum <= max_use &&
210 (uint64_t) ss.f_bavail * (uint64_t) ss.f_bsize >= min_free)
211 break;
212
213 if (unlinkat(dirfd(d), list[i].filename, 0) >= 0) {
2b43f939 214 log_debug("Deleted archived journal %s/%s.", directory, list[i].filename);
0284adc6
LP
215 sum -= list[i].usage;
216 } else if (errno != ENOENT)
217 log_warning("Failed to delete %s/%s: %m", directory, list[i].filename);
218 }
219
220finish:
221 for (i = 0; i < n_list; i++)
222 free(list[i].filename);
223
224 free(list);
225
226 if (d)
227 closedir(d);
228
229 return r;
230}