forked from I2P_Developers/i2p.i2p
Router: Move update extraction code to new class in tasks/
This commit is contained in:
@@ -8,15 +8,10 @@ package net.i2p.router;
|
||||
*
|
||||
*/
|
||||
|
||||
import java.io.BufferedReader;
|
||||
import java.io.File;
|
||||
import java.io.FileInputStream;
|
||||
import java.io.InputStreamReader;
|
||||
import java.io.IOException;
|
||||
import java.util.Collection;
|
||||
import java.util.Collections;
|
||||
import java.util.List;
|
||||
import java.util.Locale;
|
||||
import java.util.Map;
|
||||
import java.util.Properties;
|
||||
import java.util.Set;
|
||||
@@ -49,7 +44,6 @@ import net.i2p.router.util.EventLog;
|
||||
import net.i2p.stat.RateStat;
|
||||
import net.i2p.stat.StatManager;
|
||||
import net.i2p.util.ByteCache;
|
||||
import net.i2p.util.FileUtil;
|
||||
import net.i2p.util.FortunaRandomSource;
|
||||
import net.i2p.util.I2PAppThread;
|
||||
import net.i2p.util.I2PThread;
|
||||
@@ -113,6 +107,7 @@ public class Router implements RouterClock.ClockShiftListener {
|
||||
private final static String DNS_CACHE_TIME = "" + (5*60);
|
||||
private static final String EVENTLOG = "eventlog.txt";
|
||||
private static final String PROP_JBIGI = "jbigi.loadedResource";
|
||||
public static final String UPDATE_FILE = "i2pupdate.zip";
|
||||
|
||||
private static final String originalTimeZoneID;
|
||||
static {
|
||||
@@ -1495,199 +1490,11 @@ public class Router implements RouterClock.ClockShiftListener {
|
||||
// If it does an update, it never returns.
|
||||
// I guess it's better to have the other-router check above this, we don't want to
|
||||
// overwrite an existing running router's jar files. Other than ours.
|
||||
r.installUpdates();
|
||||
InstallUpdate.installUpdates(r);
|
||||
// ********* Start no threads before here ********* //
|
||||
r.runRouter();
|
||||
}
|
||||
}
|
||||
|
||||
public static final String UPDATE_FILE = "i2pupdate.zip";
|
||||
private static final String DELETE_FILE = "deletelist.txt";
|
||||
|
||||
/**
|
||||
* Context must be available.
|
||||
* Unzip update file found in the router dir OR base dir, to the base dir
|
||||
*
|
||||
* If successfull, will call exit() and never return.
|
||||
*
|
||||
* If we can't write to the base dir, complain.
|
||||
* Note: _log not available here.
|
||||
*/
|
||||
private void installUpdates() {
|
||||
File updateFile = new File(_context.getRouterDir(), UPDATE_FILE);
|
||||
boolean exists = updateFile.exists();
|
||||
if (!exists) {
|
||||
updateFile = new File(_context.getBaseDir(), UPDATE_FILE);
|
||||
exists = updateFile.exists();
|
||||
}
|
||||
if (exists) {
|
||||
// do a simple permissions test, if it fails leave the file in place and don't restart
|
||||
File test = new File(_context.getBaseDir(), "history.txt");
|
||||
if ((test.exists() && !test.canWrite()) || (!_context.getBaseDir().canWrite())) {
|
||||
System.out.println("ERROR: No write permissions on " + _context.getBaseDir() +
|
||||
" to extract software update file");
|
||||
// carry on
|
||||
return;
|
||||
}
|
||||
System.out.println("INFO: Update file exists [" + UPDATE_FILE + "] - installing");
|
||||
// verify the whole thing first
|
||||
// we could remember this fails, and not bother restarting, but who cares...
|
||||
boolean ok = FileUtil.verifyZip(updateFile);
|
||||
if (ok) {
|
||||
// This may be useful someday. First added in 0.8.2
|
||||
// Moved above the extract so we don't NCDFE
|
||||
_config.put("router.updateLastInstalled", "" + System.currentTimeMillis());
|
||||
// Set the last version to the current version, since 0.8.13
|
||||
_config.put("router.previousVersion", RouterVersion.VERSION);
|
||||
_config.put("router.previousFullVersion", RouterVersion.FULL_VERSION);
|
||||
saveConfig();
|
||||
ok = FileUtil.extractZip(updateFile, _context.getBaseDir());
|
||||
}
|
||||
|
||||
// Very important - we have now trashed our jars.
|
||||
// After this point, do not use any new I2P classes, or they will fail to load
|
||||
// and we will die with NCDFE.
|
||||
// Ideally, do not use I2P classes at all, new or not.
|
||||
try {
|
||||
if (ok) {
|
||||
// We do this here so we may delete old jars before we restart
|
||||
deleteListedFiles();
|
||||
System.out.println("INFO: Update installed");
|
||||
} else {
|
||||
System.out.println("ERROR: Update failed!");
|
||||
}
|
||||
if (!ok) {
|
||||
// we can't leave the file in place or we'll continually restart, so rename it
|
||||
File bad = new File(_context.getRouterDir(), "BAD-" + UPDATE_FILE);
|
||||
boolean renamed = updateFile.renameTo(bad);
|
||||
if (renamed) {
|
||||
System.out.println("Moved update file to " + bad.getAbsolutePath());
|
||||
} else {
|
||||
System.out.println("Deleting file " + updateFile.getAbsolutePath());
|
||||
ok = true; // so it will be deleted
|
||||
}
|
||||
}
|
||||
if (ok) {
|
||||
boolean deleted = updateFile.delete();
|
||||
if (!deleted) {
|
||||
System.out.println("ERROR: Unable to delete the update file!");
|
||||
updateFile.deleteOnExit();
|
||||
}
|
||||
}
|
||||
// exit whether ok or not
|
||||
if (_context.hasWrapper())
|
||||
System.out.println("INFO: Restarting after update");
|
||||
else
|
||||
System.out.println("WARNING: Exiting after update, restart I2P");
|
||||
} catch (Throwable t) {
|
||||
// hide the NCDFE
|
||||
// hopefully the update file got deleted or we will loop
|
||||
}
|
||||
System.exit(EXIT_HARD_RESTART);
|
||||
} else {
|
||||
deleteJbigiFiles();
|
||||
// It was here starting in 0.8.12 so it could be used the very first time
|
||||
// Now moved up so it is usually run only after an update
|
||||
// But the first time before jetty 6 it will run here...
|
||||
// Here we can't remove jars
|
||||
deleteListedFiles();
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Remove extracted libjbigi.so and libjcpuid.so files if we have a newer jbigi.jar,
|
||||
* so the new ones will be extracted.
|
||||
* We do this after the restart, not after the extract, because it's safer, and
|
||||
* because people may upgrade their jbigi.jar file manually.
|
||||
*
|
||||
* Copied from NativeBigInteger, which we can't access here or the
|
||||
* libs will get loaded.
|
||||
*/
|
||||
private void deleteJbigiFiles() {
|
||||
boolean isX86 = SystemVersion.isX86();
|
||||
String osName = System.getProperty("os.name").toLowerCase(Locale.US);
|
||||
boolean isWin = SystemVersion.isWindows();
|
||||
boolean isMac = SystemVersion.isMac();
|
||||
// only do this on these OSes
|
||||
boolean goodOS = isWin || isMac ||
|
||||
osName.contains("linux") || osName.contains("freebsd");
|
||||
|
||||
// only do this on these x86
|
||||
File jbigiJar = new File(_context.getBaseDir(), "lib/jbigi.jar");
|
||||
if (isX86 && goodOS && jbigiJar.exists()) {
|
||||
String libPrefix = (isWin ? "" : "lib");
|
||||
String libSuffix = (isWin ? ".dll" : isMac ? ".jnilib" : ".so");
|
||||
|
||||
File jcpuidLib = new File(_context.getBaseDir(), libPrefix + "jcpuid" + libSuffix);
|
||||
if (jcpuidLib.canWrite() && jbigiJar.lastModified() > jcpuidLib.lastModified()) {
|
||||
String path = jcpuidLib.getAbsolutePath();
|
||||
boolean success = FileUtil.copy(path, path + ".bak", true, true);
|
||||
if (success) {
|
||||
boolean success2 = jcpuidLib.delete();
|
||||
if (success2) {
|
||||
System.out.println("New jbigi.jar detected, moved jcpuid library to " +
|
||||
path + ".bak");
|
||||
System.out.println("Check logs for successful installation of new library");
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
File jbigiLib = new File(_context.getBaseDir(), libPrefix + "jbigi" + libSuffix);
|
||||
if (jbigiLib.canWrite() && jbigiJar.lastModified() > jbigiLib.lastModified()) {
|
||||
String path = jbigiLib.getAbsolutePath();
|
||||
boolean success = FileUtil.copy(path, path + ".bak", true, true);
|
||||
if (success) {
|
||||
boolean success2 = jbigiLib.delete();
|
||||
if (success2) {
|
||||
System.out.println("New jbigi.jar detected, moved jbigi library to " +
|
||||
path + ".bak");
|
||||
System.out.println("Check logs for successful installation of new library");
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Delete all files listed in the delete file.
|
||||
* Format: One file name per line, comment lines start with '#'.
|
||||
* All file names must be relative to $I2P, absolute file names not allowed.
|
||||
* We probably can't remove old jars this way.
|
||||
* Fails silently.
|
||||
* Use no new I2P classes here so it may be called after zip extraction.
|
||||
* @since 0.8.12
|
||||
*/
|
||||
private void deleteListedFiles() {
|
||||
File deleteFile = new File(_context.getBaseDir(), DELETE_FILE);
|
||||
if (!deleteFile.exists())
|
||||
return;
|
||||
// this is similar to FileUtil.readTextFile() but we can't use any I2P classes here
|
||||
FileInputStream fis = null;
|
||||
BufferedReader in = null;
|
||||
try {
|
||||
fis = new FileInputStream(deleteFile);
|
||||
in = new BufferedReader(new InputStreamReader(fis, "UTF-8"));
|
||||
String line;
|
||||
while ( (line = in.readLine()) != null) {
|
||||
String fl = line.trim();
|
||||
if (fl.contains("..") || fl.startsWith("#") || fl.length() == 0)
|
||||
continue;
|
||||
File df = new File(fl);
|
||||
if (df.isAbsolute())
|
||||
continue;
|
||||
df = new File(_context.getBaseDir(), fl);
|
||||
if (df.exists() && !df.isDirectory()) {
|
||||
if (df.delete())
|
||||
System.out.println("INFO: File [" + fl + "] deleted");
|
||||
}
|
||||
}
|
||||
} catch (IOException ioe) {}
|
||||
finally {
|
||||
if (in != null) try { in.close(); } catch(IOException ioe) {}
|
||||
if (deleteFile.delete())
|
||||
System.out.println("INFO: File [" + DELETE_FILE + "] deleted");
|
||||
}
|
||||
}
|
||||
|
||||
/*******
|
||||
private static void verifyWrapperConfig() {
|
||||
|
215
router/java/src/net/i2p/router/tasks/InstallUpdate.java
Normal file
215
router/java/src/net/i2p/router/tasks/InstallUpdate.java
Normal file
@@ -0,0 +1,215 @@
|
||||
package net.i2p.router.tasks;
|
||||
|
||||
import java.io.BufferedReader;
|
||||
import java.io.File;
|
||||
import java.io.FileInputStream;
|
||||
import java.io.InputStreamReader;
|
||||
import java.io.IOException;
|
||||
import java.util.HashMap;
|
||||
import java.util.Locale;
|
||||
import java.util.Map;
|
||||
|
||||
import net.i2p.router.Router;
|
||||
import net.i2p.router.RouterContext;
|
||||
import net.i2p.router.RouterVersion;
|
||||
import net.i2p.util.FileUtil;
|
||||
import net.i2p.util.SystemVersion;
|
||||
|
||||
/**
|
||||
* If the i2pupdate.zip file is present,
|
||||
* unzip it and JVM exit.
|
||||
*
|
||||
* @since 0.9.20 moved from Router.java
|
||||
*/
|
||||
public class InstallUpdate {
|
||||
|
||||
private static final String DELETE_FILE = "deletelist.txt";
|
||||
|
||||
/**
|
||||
* Context must be available.
|
||||
* Unzip update file found in the router dir OR base dir, to the base dir
|
||||
*
|
||||
* If successful, will call exit() and never return.
|
||||
*
|
||||
* If we can't write to the base dir, write message to System.out and return.
|
||||
* Note: _log not available here.
|
||||
*/
|
||||
public static void installUpdates(Router r) {
|
||||
RouterContext context = r.getContext();
|
||||
File updateFile = new File(context.getRouterDir(), Router.UPDATE_FILE);
|
||||
boolean exists = updateFile.exists();
|
||||
if (!exists) {
|
||||
updateFile = new File(context.getBaseDir(), Router.UPDATE_FILE);
|
||||
exists = updateFile.exists();
|
||||
}
|
||||
if (exists) {
|
||||
// do a simple permissions test, if it fails leave the file in place and don't restart
|
||||
File test = new File(context.getBaseDir(), "history.txt");
|
||||
if ((test.exists() && !test.canWrite()) || (!context.getBaseDir().canWrite())) {
|
||||
System.out.println("ERROR: No write permissions on " + context.getBaseDir() +
|
||||
" to extract software update file");
|
||||
// carry on
|
||||
return;
|
||||
}
|
||||
System.out.println("INFO: Update file exists [" + Router.UPDATE_FILE + "] - installing");
|
||||
// verify the whole thing first
|
||||
// we could remember this fails, and not bother restarting, but who cares...
|
||||
boolean ok = FileUtil.verifyZip(updateFile);
|
||||
if (ok) {
|
||||
// This may be useful someday. First added in 0.8.2
|
||||
// Moved above the extract so we don't NCDFE
|
||||
Map<String, String> config = new HashMap<String, String>(4);
|
||||
config.put("router.updateLastInstalled", "" + System.currentTimeMillis());
|
||||
// Set the last version to the current version, since 0.8.13
|
||||
config.put("router.previousVersion", RouterVersion.VERSION);
|
||||
config.put("router.previousFullVersion", RouterVersion.FULL_VERSION);
|
||||
r.saveConfig(config, null);
|
||||
ok = FileUtil.extractZip(updateFile, context.getBaseDir());
|
||||
}
|
||||
|
||||
// Very important - we have now trashed our jars.
|
||||
// After this point, do not use any new I2P classes, or they will fail to load
|
||||
// and we will die with NCDFE.
|
||||
// Ideally, do not use I2P classes at all, new or not.
|
||||
try {
|
||||
if (ok) {
|
||||
// We do this here so we may delete old jars before we restart
|
||||
deleteListedFiles(context);
|
||||
System.out.println("INFO: Update installed");
|
||||
} else {
|
||||
System.out.println("ERROR: Update failed!");
|
||||
}
|
||||
if (!ok) {
|
||||
// we can't leave the file in place or we'll continually restart, so rename it
|
||||
File bad = new File(context.getRouterDir(), "BAD-" + Router.UPDATE_FILE);
|
||||
boolean renamed = updateFile.renameTo(bad);
|
||||
if (renamed) {
|
||||
System.out.println("Moved update file to " + bad.getAbsolutePath());
|
||||
} else {
|
||||
System.out.println("Deleting file " + updateFile.getAbsolutePath());
|
||||
ok = true; // so it will be deleted
|
||||
}
|
||||
}
|
||||
if (ok) {
|
||||
boolean deleted = updateFile.delete();
|
||||
if (!deleted) {
|
||||
System.out.println("ERROR: Unable to delete the update file!");
|
||||
updateFile.deleteOnExit();
|
||||
}
|
||||
}
|
||||
// exit whether ok or not
|
||||
if (context.hasWrapper())
|
||||
System.out.println("INFO: Restarting after update");
|
||||
else
|
||||
System.out.println("WARNING: Exiting after update, restart I2P");
|
||||
} catch (Throwable t) {
|
||||
// hide the NCDFE
|
||||
// hopefully the update file got deleted or we will loop
|
||||
}
|
||||
System.exit(Router.EXIT_HARD_RESTART);
|
||||
} else {
|
||||
deleteJbigiFiles(context);
|
||||
// It was here starting in 0.8.12 so it could be used the very first time
|
||||
// Now moved up so it is usually run only after an update
|
||||
// But the first time before jetty 6 it will run here...
|
||||
// Here we can't remove jars
|
||||
deleteListedFiles(context);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Remove extracted libjbigi.so and libjcpuid.so files if we have a newer jbigi.jar,
|
||||
* so the new ones will be extracted.
|
||||
* We do this after the restart, not after the extract, because it's safer, and
|
||||
* because people may upgrade their jbigi.jar file manually.
|
||||
*
|
||||
* Copied from NativeBigInteger, which we can't access here or the
|
||||
* libs will get loaded.
|
||||
*/
|
||||
private static void deleteJbigiFiles(RouterContext context) {
|
||||
boolean isX86 = SystemVersion.isX86();
|
||||
String osName = System.getProperty("os.name").toLowerCase(Locale.US);
|
||||
boolean isWin = SystemVersion.isWindows();
|
||||
boolean isMac = SystemVersion.isMac();
|
||||
// only do this on these OSes
|
||||
boolean goodOS = isWin || isMac ||
|
||||
osName.contains("linux") || osName.contains("freebsd");
|
||||
|
||||
// only do this on these x86
|
||||
File jbigiJar = new File(context.getBaseDir(), "lib/jbigi.jar");
|
||||
if (isX86 && goodOS && jbigiJar.exists()) {
|
||||
String libPrefix = (isWin ? "" : "lib");
|
||||
String libSuffix = (isWin ? ".dll" : isMac ? ".jnilib" : ".so");
|
||||
|
||||
File jcpuidLib = new File(context.getBaseDir(), libPrefix + "jcpuid" + libSuffix);
|
||||
if (jcpuidLib.canWrite() && jbigiJar.lastModified() > jcpuidLib.lastModified()) {
|
||||
String path = jcpuidLib.getAbsolutePath();
|
||||
boolean success = FileUtil.copy(path, path + ".bak", true, true);
|
||||
if (success) {
|
||||
boolean success2 = jcpuidLib.delete();
|
||||
if (success2) {
|
||||
System.out.println("New jbigi.jar detected, moved jcpuid library to " +
|
||||
path + ".bak");
|
||||
System.out.println("Check logs for successful installation of new library");
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
File jbigiLib = new File(context.getBaseDir(), libPrefix + "jbigi" + libSuffix);
|
||||
if (jbigiLib.canWrite() && jbigiJar.lastModified() > jbigiLib.lastModified()) {
|
||||
String path = jbigiLib.getAbsolutePath();
|
||||
boolean success = FileUtil.copy(path, path + ".bak", true, true);
|
||||
if (success) {
|
||||
boolean success2 = jbigiLib.delete();
|
||||
if (success2) {
|
||||
System.out.println("New jbigi.jar detected, moved jbigi library to " +
|
||||
path + ".bak");
|
||||
System.out.println("Check logs for successful installation of new library");
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Delete all files listed in the delete file.
|
||||
* Format: One file name per line, comment lines start with '#'.
|
||||
* All file names must be relative to $I2P, absolute file names not allowed.
|
||||
* We probably can't remove old jars this way.
|
||||
* Fails silently.
|
||||
* Use no new I2P classes here so it may be called after zip extraction.
|
||||
* @since 0.8.12
|
||||
*/
|
||||
private static void deleteListedFiles(RouterContext context) {
|
||||
File deleteFile = new File(context.getBaseDir(), DELETE_FILE);
|
||||
if (!deleteFile.exists())
|
||||
return;
|
||||
// this is similar to FileUtil.readTextFile() but we can't use any I2P classes here
|
||||
FileInputStream fis = null;
|
||||
BufferedReader in = null;
|
||||
try {
|
||||
fis = new FileInputStream(deleteFile);
|
||||
in = new BufferedReader(new InputStreamReader(fis, "UTF-8"));
|
||||
String line;
|
||||
while ( (line = in.readLine()) != null) {
|
||||
String fl = line.trim();
|
||||
if (fl.contains("..") || fl.startsWith("#") || fl.length() == 0)
|
||||
continue;
|
||||
File df = new File(fl);
|
||||
if (df.isAbsolute())
|
||||
continue;
|
||||
df = new File(context.getBaseDir(), fl);
|
||||
if (df.exists() && !df.isDirectory()) {
|
||||
if (df.delete())
|
||||
System.out.println("INFO: File [" + fl + "] deleted");
|
||||
}
|
||||
}
|
||||
} catch (IOException ioe) {}
|
||||
finally {
|
||||
if (in != null) try { in.close(); } catch(IOException ioe) {}
|
||||
if (deleteFile.delete())
|
||||
System.out.println("INFO: File [" + DELETE_FILE + "] deleted");
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@@ -4,6 +4,7 @@
|
||||
Miscellaneous classes, mostly things that are executed periodically as
|
||||
Jobs, Threads, and SimpleTimer.TimedEvents.
|
||||
These are used only by Router.java.
|
||||
Nothing here is to be used externally, not a part of the public API.
|
||||
</p>
|
||||
</body>
|
||||
</html>
|
||||
|
Reference in New Issue
Block a user