package freenet.config; import java.io.BufferedInputStream; import java.io.BufferedReader; import java.io.BufferedWriter; import java.io.File; import java.io.FileInputStream; import java.io.FileOutputStream; import java.io.IOException; import java.io.InputStreamReader; import java.io.OutputStreamWriter; import java.util.HashMap; import org.tanukisoftware.wrapper.WrapperManager; import freenet.node.NodeInitException; import freenet.support.Logger; import freenet.support.io.Closer; import freenet.support.io.FileUtil; /** * Class to allow us to easily change wrapper properties. * @author toad */ public class WrapperConfig { private static HashMap<String, String> overrides = new HashMap<String, String>(); public static String getWrapperProperty(String name) { synchronized(WrapperConfig.class) { String override = overrides.get(name); if(override != null) return override; } return WrapperManager.getProperties().getProperty(name, null); } public static boolean canChangeProperties() { if(!WrapperManager.isControlledByNativeWrapper()) { Logger.normal(WrapperConfig.class, "Cannot alter properties: not running under wrapper"); return false; } File f = new File("wrapper.conf"); if(!f.exists()) { Logger.normal(WrapperConfig.class, "Cannot alter properties: wrapper.conf does not exist"); return false; } if(!f.canRead()) { Logger.normal(WrapperConfig.class, "Cannot alter properties: wrapper.conf not readable"); return false; } if(!f.canWrite()) { Logger.normal(WrapperConfig.class, "Cannot alter properties: wrapper.conf not writable"); return false; } if(!FileUtil.getCanonicalFile(f).getParentFile().canWrite()) { Logger.normal(WrapperConfig.class, "Cannot alter properties: parent dir not writable"); return false; // Can we create a file in order to rename over wrapper.conf? } return true; } /** * Synchronized because we only want one instance running at once. * @param name The property to set. * @param value The value to set it to. * @return True if the property was successfully updated. */ public static synchronized boolean setWrapperProperty(String name, String value) { // Some of this copied from UpdateDeployContext, hence no GPL header on this file as none there. File oldConfig = new File("wrapper.conf"); File newConfig = new File("wrapper.conf.new"); FileInputStream fis = null; FileOutputStream fos = null; try { fis = new FileInputStream(oldConfig); BufferedInputStream bis = new BufferedInputStream(fis); InputStreamReader isr = new InputStreamReader(bis); BufferedReader br = new BufferedReader(isr); fos = new FileOutputStream(newConfig); OutputStreamWriter osw = new OutputStreamWriter(fos); BufferedWriter bw = new BufferedWriter(osw); String line; boolean written = false; boolean writtenReload = false; while((line = br.readLine()) != null) { if(line.startsWith(name+"=")) { bw.write(name+'='+value+'\n'); written = true; } else if(line.equalsIgnoreCase("wrapper.restart.reload_configuration=TRUE")) { bw.write(line+'\n'); writtenReload = true; } else { bw.write(line+'\n'); } } br.close(); fis = null; if(!written) bw.write(name+'='+value+'\n'); if(!writtenReload) bw.write("wrapper.restart.reload_configuration=TRUE\n"); bw.close(); fos = null; } catch(IOException e) { Closer.close(fis); Closer.close(fos); fis = null; fos = null; if(oldConfig.exists()) newConfig.delete(); Logger.error(WrapperConfig.class, "Cannot update wrapper property "+"name: "+e, e); System.err.println("Unable to update wrapper property "+name+" : "+e); return false; } finally { Closer.close(fis); Closer.close(fos); } if(!newConfig.renameTo(oldConfig)) { File oldOldConfig = new File("wrapper.conf.old"); if(oldOldConfig.exists() && !oldOldConfig.delete()) try { oldOldConfig = File.createTempFile("wrapper.conf", ".old.tmp", new File(".")); } catch (IOException e) { String error = "Unable to create temporary file and unable to copy wrapper.conf to wrapper.conf.old. Could not update wrapper.conf trying to set property "+name; Logger.error(WrapperConfig.class, error); System.err.println(error); return false; } if(!oldConfig.renameTo(oldOldConfig)) { String error = "Unable to change property "+name+": Could not move old config file "+oldConfig+", so could not rename new config file "+newConfig+" over it (already tried without deleting."; Logger.error(WrapperConfig.class, error); System.err.println(error); return false; } if(!newConfig.renameTo(oldConfig)) { String error = "Unable to rename "+newConfig+" to "+oldConfig+" even after moving the old config file out of the way! Trying to restore previous config file so the node will start up..."; Logger.error(WrapperConfig.class, error); System.err.println(error); if(!oldOldConfig.renameTo(oldConfig)) { System.err.println("CATASTROPHIC UPDATE ERROR: Unable to rename backup copy of config file over the current config file, after failing to update config file! The node will not boot until you get a new wrapper.conf!\n"+ "The old config file is saved in "+oldOldConfig+" and it should be renamed to wrapper.conf"); System.exit(NodeInitException.EXIT_BROKE_WRAPPER_CONF); } } } // Wrapper properties are read-only, so don't setProperty(). overrides.put(name, value); return true; } }