[tor-commits] [arm/release] Using SAVECONF when able to persist torrc

atagar at torproject.org atagar at torproject.org
Sun Jul 17 06:08:19 UTC 2011


commit d28bb39099548f46c97a1a11e5dd31bae0a47e41
Author: Damian Johnson <atagar at torproject.org>
Date:   Wed May 11 21:42:05 2011 -0700

    Using SAVECONF when able to persist torrc
    
    Moving config saving to the torConfig utility, and making it save via SAVECONF
    if it's equivilant (the contents and destination matches tor's state). This
    also includes other minor fixes and changes (like a bit more logging).
---
 src/cli/configPanel.py |   28 ++++---------------
 src/util/torConfig.py  |   69 ++++++++++++++++++++++++++++++++++++++++++++++++
 2 files changed, 75 insertions(+), 22 deletions(-)

diff --git a/src/cli/configPanel.py b/src/cli/configPanel.py
index 6ec3fce..7c1a62e 100644
--- a/src/cli/configPanel.py
+++ b/src/cli/configPanel.py
@@ -3,14 +3,13 @@ Panel presenting the configuration state for tor or arm. Options can be edited
 and the resulting configuration files saved.
 """
 
-import os
 import curses
 import threading
 
 import controller
 import popups
 
-from util import conf, enum, panel, torTools, torConfig, uiTools
+from util import conf, enum, panel, sysTools, torConfig, torTools, uiTools
 
 DEFAULT_CONFIG = {"features.config.selectionDetails.height": 6,
                   "features.config.prepopulateEditValues": True,
@@ -401,35 +400,20 @@ class ConfigPanel(panel.Panel):
           elif key == curses.KEY_RIGHT: selection = min(len(selectionOptions) - 1, selection + 1)
         
         if selection in (0, 1):
-          loadedTorrc = torConfig.getTorrc()
+          loadedTorrc, promptCanceled = torConfig.getTorrc(), False
           try: configLocation = loadedTorrc.getConfigLocation()
           except IOError: configLocation = ""
           
           if selection == 1:
             # prompts user for a configuration location
             configLocation = popups.inputPrompt("Save to (esc to cancel): ", configLocation)
-            if configLocation: configLocation = os.path.abspath(configLocation)
+            if not configLocation: promptCanceled = True
           
-          if configLocation:
+          if not promptCanceled:
             try:
-              # make dir if the path doesn't already exist
-              baseDir = os.path.dirname(configLocation)
-              if not os.path.exists(baseDir): os.makedirs(baseDir)
-              
-              # saves the configuration to the file
-              configFile = open(configLocation, "w")
-              configFile.write("\n".join(configLines))
-              configFile.close()
-              
-              # reloads the cached torrc if overwriting it
-              if configLocation == loadedTorrc.getConfigLocation():
-                try:
-                  loadedTorrc.load()
-                  panels["torrc"]._lastContentHeightArgs = None
-                except IOError: pass
-              
+              torConfig.saveConf(configLocation, configLines)
               msg = "Saved configuration to %s" % configLocation
-            except (IOError, OSError), exc:
+            except IOError, exc:
               msg = "Unable to save configuration (%s)" % sysTools.getFileErrorMsg(exc)
             
             popups.showMsg(msg, 2)
diff --git a/src/util/torConfig.py b/src/util/torConfig.py
index 030a169..4a25f0f 100644
--- a/src/util/torConfig.py
+++ b/src/util/torConfig.py
@@ -3,6 +3,7 @@ Helper functions for working with tor's configuration file.
 """
 
 import os
+import time
 import socket
 import threading
 
@@ -381,6 +382,74 @@ def getCustomOptions(includeValue = False):
   if includeValue: return configLines
   else: return [line[:line.find(" ")] for line in configLines]
 
+def saveConf(destination = None, contents = None):
+  """
+  Saves the configuration to the given path. If this is equivilant to
+  issuing a SAVECONF (the contents and destination match what tor's using)
+  then that's done. Otherwise, this writes the contents directly. This raises
+  an IOError if unsuccessful.
+  
+  Arguments:
+    destination - path to be saved to, the current config location if None
+    contents    - configuration to be saved, the current config if None
+  """
+  
+  if destination:
+    destination = os.path.abspath(destination)
+  
+  # fills default config values, and sets isSaveconf to false if they differ
+  # from the arguments
+  isSaveconf, startTime = True, time.time()
+  
+  currentConfig = getCustomOptions(True)
+  if not contents: contents = currentConfig
+  else: isSaveconf &= contents == currentConfig
+  
+  currentLocation = None
+  try:
+    currentLocation = getConfigLocation()
+    if not destination: destination = currentLocation
+    else: isSaveconf &= destination == currentLocation
+  except IOError: pass
+  
+  if not destination: raise IOError("unable to determine the torrc's path")
+  logMsg = "Saved config by %%s to %s (runtime: %%0.4f)" % destination
+  
+  # attempts SAVECONF if we're updating our torrc with the current state
+  if isSaveconf:
+    try:
+      torTools.getConn().getTorCtl().save_conf()
+      
+      try: getTorrc().load()
+      except IOError: pass
+      
+      log.log(log.DEBUG, logMsg % ("SAVECONF", time.time() - startTime))
+      return # if successful then we're done
+    except:
+      # example error:
+      # TorCtl.TorCtl.ErrorReply: 551 Unable to write configuration to disk.
+      pass
+  
+  # if the SAVECONF fails or this is a custom save then write contents directly
+  try:
+    # make dir if the path doesn't already exist
+    baseDir = os.path.dirname(destination)
+    if not os.path.exists(baseDir): os.makedirs(baseDir)
+    
+    # saves the configuration to the file
+    configFile = open(destination, "w")
+    configFile.write("\n".join(contents))
+    configFile.close()
+  except (IOError, OSError), exc:
+    raise IOError(exc)
+  
+  # reloads the cached torrc if overwriting it
+  if destination == currentLocation:
+    try: getTorrc().load()
+    except IOError: pass
+  
+  log.log(log.DEBUG, logMsg % ("directly writing", time.time() - startTime))
+
 def validate(contents = None):
   """
   Performs validation on the given torrc contents, providing back a listing of





More information about the tor-commits mailing list