1 |
commit: a7c99506d9de81b9a2a7547bd11715073de1ce95 |
2 |
Author: Will Miles <wmiles <AT> sgl <DOT> com> |
3 |
AuthorDate: Thu Aug 24 01:53:16 2017 +0000 |
4 |
Commit: William Hubbs <williamh <AT> gentoo <DOT> org> |
5 |
CommitDate: Thu Nov 30 19:56:54 2017 +0000 |
6 |
URL: https://gitweb.gentoo.org/proj/openrc.git/commit/?id=a7c99506 |
7 |
|
8 |
Fix repeated dependency cache rebuild if clock skewed |
9 |
|
10 |
rc_deptree_update_needed would return early as soon as it found |
11 |
any file newer than the existing dependency cache. Unfortunately, |
12 |
the first file found may not be the newest one there; so the |
13 |
clock skew workaround in rc-misc:_rc_deptree_load would be given |
14 |
a timestamp that was still too old. |
15 |
|
16 |
This fix forces a full scan of all relevant files, so as to |
17 |
ensure that we return a timestamp that will allow the clock skew |
18 |
fix to operate. The runtime cost is no worse than the case where |
19 |
the cache is up to date (ie. we must check every possible file). |
20 |
|
21 |
This fixes #161. |
22 |
|
23 |
src/librc/librc-depend.c | 123 +++++++++++++++++++++++++++-------------------- |
24 |
1 file changed, 71 insertions(+), 52 deletions(-) |
25 |
|
26 |
diff --git a/src/librc/librc-depend.c b/src/librc/librc-depend.c |
27 |
index 1c993998..37f0b60d 100644 |
28 |
--- a/src/librc/librc-depend.c |
29 |
+++ b/src/librc/librc-depend.c |
30 |
@@ -542,52 +542,41 @@ rc_deptree_order(const RC_DEPTREE *deptree, const char *runlevel, int options) |
31 |
} |
32 |
librc_hidden_def(rc_deptree_order) |
33 |
|
34 |
+ |
35 |
+/* Given a time, recurse the target path to find out if there are |
36 |
+ any older (or newer) files. If false, sets the time to the |
37 |
+ oldest (or newest) found. |
38 |
+*/ |
39 |
static bool |
40 |
-mtime_check(const char *source, const char *target, bool newer, |
41 |
+deep_mtime_check(const char *target, bool newer, |
42 |
time_t *rel, char *file) |
43 |
{ |
44 |
struct stat buf; |
45 |
- time_t mtime; |
46 |
bool retval = true; |
47 |
DIR *dp; |
48 |
struct dirent *d; |
49 |
char path[PATH_MAX]; |
50 |
int serrno = errno; |
51 |
|
52 |
- /* We have to exist */ |
53 |
- if (stat(source, &buf) != 0) |
54 |
- return false; |
55 |
- mtime = buf.st_mtime; |
56 |
- |
57 |
/* If target does not exist, return true to mimic shell test */ |
58 |
if (stat(target, &buf) != 0) |
59 |
return true; |
60 |
|
61 |
if (newer) { |
62 |
- if (mtime < buf.st_mtime) { |
63 |
- if (rel == NULL) |
64 |
- return false; |
65 |
+ if (*rel < buf.st_mtime) { |
66 |
retval = false; |
67 |
- } |
68 |
- if (rel != NULL) { |
69 |
- if (*rel < buf.st_mtime) { |
70 |
- if (file) |
71 |
- strlcpy(file, target, PATH_MAX); |
72 |
- *rel = buf.st_mtime; |
73 |
- } |
74 |
+ |
75 |
+ if (file) |
76 |
+ strlcpy(file, target, PATH_MAX); |
77 |
+ *rel = buf.st_mtime; |
78 |
} |
79 |
} else { |
80 |
- if (mtime > buf.st_mtime) { |
81 |
- if (rel == NULL) |
82 |
- return false; |
83 |
+ if (*rel > buf.st_mtime) { |
84 |
retval = false; |
85 |
- } |
86 |
- if (rel != NULL) { |
87 |
- if (*rel > buf.st_mtime) { |
88 |
- if (file) |
89 |
- strlcpy(file, target, PATH_MAX); |
90 |
- *rel = buf.st_mtime; |
91 |
- } |
92 |
+ |
93 |
+ if (file) |
94 |
+ strlcpy(file, target, PATH_MAX); |
95 |
+ *rel = buf.st_mtime; |
96 |
} |
97 |
} |
98 |
|
99 |
@@ -602,16 +591,38 @@ mtime_check(const char *source, const char *target, bool newer, |
100 |
if (d->d_name[0] == '.') |
101 |
continue; |
102 |
snprintf(path, sizeof(path), "%s/%s", target, d->d_name); |
103 |
- if (!mtime_check(source, path, newer, rel, file)) { |
104 |
+ if (!deep_mtime_check(path, newer, rel, file)) { |
105 |
retval = false; |
106 |
- if (rel == NULL) |
107 |
- break; |
108 |
} |
109 |
} |
110 |
closedir(dp); |
111 |
return retval; |
112 |
} |
113 |
|
114 |
+/* Recursively check if target is older/newer than source. |
115 |
+ * If false, return the filename and most different time (if |
116 |
+ * the return value arguments are non-null). |
117 |
+ */ |
118 |
+static bool |
119 |
+mtime_check(const char *source, const char *target, bool newer, |
120 |
+ time_t *rel, char *file) |
121 |
+{ |
122 |
+ struct stat buf; |
123 |
+ time_t mtime; |
124 |
+ bool retval = true; |
125 |
+ |
126 |
+ /* We have to exist */ |
127 |
+ if (stat(source, &buf) != 0) |
128 |
+ return false; |
129 |
+ mtime = buf.st_mtime; |
130 |
+ |
131 |
+ retval = deep_mtime_check(target,newer,&mtime,file); |
132 |
+ if (rel) { |
133 |
+ *rel = mtime; |
134 |
+ } |
135 |
+ return retval; |
136 |
+} |
137 |
+ |
138 |
bool |
139 |
rc_newer_than(const char *source, const char *target, |
140 |
time_t *newest, char *file) |
141 |
@@ -670,6 +681,8 @@ rc_deptree_update_needed(time_t *newest, char *file) |
142 |
RC_STRINGLIST *config; |
143 |
RC_STRING *s; |
144 |
int i; |
145 |
+ struct stat buf; |
146 |
+ time_t mtime; |
147 |
|
148 |
/* Create base directories if needed */ |
149 |
for (i = 0; depdirs[i]; i++) |
150 |
@@ -677,42 +690,48 @@ rc_deptree_update_needed(time_t *newest, char *file) |
151 |
fprintf(stderr, "mkdir `%s': %s\n", depdirs[i], strerror(errno)); |
152 |
|
153 |
/* Quick test to see if anything we use has changed and we have |
154 |
- * data in our deptree */ |
155 |
- if (!existss(RC_DEPTREE_CACHE)) |
156 |
- return true; |
157 |
- if (!rc_newer_than(RC_DEPTREE_CACHE, RC_INITDIR, newest, file)) |
158 |
- return true; |
159 |
- if (!rc_newer_than(RC_DEPTREE_CACHE, RC_CONFDIR, newest, file)) |
160 |
- return true; |
161 |
+ * data in our deptree. */ |
162 |
+ |
163 |
+ if (stat(RC_DEPTREE_CACHE, &buf) == 0) { |
164 |
+ mtime = buf.st_mtime; |
165 |
+ } else { |
166 |
+ /* No previous cache found. |
167 |
+ * We still run the scan, in case of clock skew; we still need to return |
168 |
+ * the newest time. |
169 |
+ */ |
170 |
+ newer = true; |
171 |
+ mtime = time(NULL); |
172 |
+ } |
173 |
+ |
174 |
+ newer |= !deep_mtime_check(RC_INITDIR,true,&mtime,file); |
175 |
+ newer |= !deep_mtime_check(RC_CONFDIR,true,&mtime,file); |
176 |
#ifdef RC_PKG_INITDIR |
177 |
- if (!rc_newer_than(RC_DEPTREE_CACHE, RC_PKG_INITDIR, newest, file)) |
178 |
- return true; |
179 |
+ newer |= !deep_mtime_check(RC_PKG_INITDIR,true,&mtime,file); |
180 |
#endif |
181 |
#ifdef RC_PKG_CONFDIR |
182 |
- if (!rc_newer_than(RC_DEPTREE_CACHE, RC_PKG_CONFDIR, newest, file)) |
183 |
- return true; |
184 |
+ newer |= !deep_mtime_check(RC_PKG_CONFDIR,true,&mtime,file); |
185 |
#endif |
186 |
-#ifdef RC_LOCAL_INITDIR |
187 |
- if (!rc_newer_than(RC_DEPTREE_CACHE, RC_LOCAL_INITDIR, newest, file)) |
188 |
- return true; |
189 |
+#ifdef RC_LOCAL_INITDIRs |
190 |
+ newer |= !deep_mtime_check(RC_LOCAL_INITDIR,true,&mtime,file); |
191 |
#endif |
192 |
#ifdef RC_LOCAL_CONFDIR |
193 |
- if (!rc_newer_than(RC_DEPTREE_CACHE, RC_LOCAL_CONFDIR, newest, file)) |
194 |
- return true; |
195 |
+ newer |= !deep_mtime_check(RC_LOCAL_CONFDIR,true,&mtime,file); |
196 |
#endif |
197 |
- if (!rc_newer_than(RC_DEPTREE_CACHE, RC_CONF, newest, file)) |
198 |
- return true; |
199 |
+ newer |= !deep_mtime_check(RC_CONF,true,&mtime,file); |
200 |
|
201 |
/* Some init scripts dependencies change depending on config files |
202 |
* outside of baselayout, like syslog-ng, so we check those too. */ |
203 |
config = rc_config_list(RC_DEPCONFIG); |
204 |
TAILQ_FOREACH(s, config, entries) { |
205 |
- if (!rc_newer_than(RC_DEPTREE_CACHE, s->value, newest, file)) { |
206 |
- newer = true; |
207 |
- break; |
208 |
- } |
209 |
+ newer |= !deep_mtime_check(s->value, true, &mtime, file); |
210 |
} |
211 |
rc_stringlist_free(config); |
212 |
+ |
213 |
+ /* Return newest file time, if requested */ |
214 |
+ if ((newer) && (newest != NULL)) { |
215 |
+ *newest = mtime; |
216 |
+ } |
217 |
+ |
218 |
return newer; |
219 |
} |
220 |
librc_hidden_def(rc_deptree_update_needed) |