diff --git a/core/java/src/net/i2p/I2PAppContext.java b/core/java/src/net/i2p/I2PAppContext.java index 7df62046c..553fd1bdb 100644 --- a/core/java/src/net/i2p/I2PAppContext.java +++ b/core/java/src/net/i2p/I2PAppContext.java @@ -36,6 +36,7 @@ import net.i2p.util.SimpleScheduler; import net.i2p.util.SimpleTimer; import net.i2p.util.SimpleTimer2; import net.i2p.util.SystemVersion; +import net.i2p.util.TempDirScanner; import net.i2p.util.I2PProperties.I2PPropertyCallback; /** @@ -436,6 +437,8 @@ public class I2PAppContext { // good or bad ? loop and try again? } else if (_tmpDir.mkdir()) { _tmpDir.deleteOnExit(); + if (!SystemVersion.isWindows() && !SystemVersion.isMac() && !SystemVersion.isAndroid()) + new TempDirScanner(this); } else { System.err.println("WARNING: Could not create temp dir " + _tmpDir.getAbsolutePath()); _tmpDir = new SecureDirectory(_routerDir, "tmp"); diff --git a/core/java/src/net/i2p/util/TempDirScanner.java b/core/java/src/net/i2p/util/TempDirScanner.java new file mode 100644 index 000000000..b73aa7716 --- /dev/null +++ b/core/java/src/net/i2p/util/TempDirScanner.java @@ -0,0 +1,66 @@ +package net.i2p.util; + +import java.io.File; + +import net.i2p.I2PAppContext; + +/** + * Prevent systemd from deleting our temp dir or any dirs or files in it. + * Scheduled by I2PAppContext when the temp dir is created. + * + * To configure/test systemd: Edit file /usr/lib/tmpfiles.d/tmp.conf, + * change line + * D /tmp 1777 root root - + * to + * D /tmp 1777 root root 24h + * + * Ref: https://lwn.net/Articles/975565/ + * Ref: https://systemd.io/TEMPORARY_DIRECTORIES/ + * Ref: man systemd-tmpfiles; man tmpfiles.d + * + * @since 0.9.64 + */ +public class TempDirScanner extends SimpleTimer2.TimedEvent { + private final I2PAppContext ctx; + + // systemd default is 10 days for /tmp? distro dependent. + // go a little faster than 1 day just in case + private static final long DELAY = 23*60*60*1000L; + + /** + * Schedules itself + */ + public TempDirScanner(I2PAppContext context) { + super(context.simpleTimer2()); + ctx = context; + schedule(DELAY); + } + + public void timeReached() { + scan(ctx.getTempDir()); + schedule(DELAY); + } + + /** + * Recursively timestamp all files and empty dirs + * We can't count on the filesystem updating access time. + * This should not affect any known usage of our temp dir. + */ + private static void scan(File f) { + if (f.isDirectory()) { + File[] files = f.listFiles(); + if (files != null) { + if (files.length > 0) { + for (File ff : files) { + scan(ff); + } + } else { + // Update last mod time on empty directories + f.setLastModified(System.currentTimeMillis()); + } + } + } else if (f.isFile()) { + f.setLastModified(System.currentTimeMillis()); + } + } +}