def _loadConfigOptions(self):
        """
    Fetches the configuration options available from tor or arm.
    """

        self.confContents = []
        self.confImportantContents = []

        if self.configType == State.TOR:
            conn, configOptionLines = torTools.getConn(), []
            customOptions = torConfig.getCustomOptions()
            configOptionQuery = conn.getInfo("config/names")

            if configOptionQuery:
                configOptionLines = configOptionQuery.strip().split("\n")

            for line in configOptionLines:
                # lines are of the form "<option> <type>[ <documentation>]", like:
                # UseEntryGuards Boolean
                # documentation is aparently only in older versions (for instance,
                # 0.2.1.25)
                lineComp = line.strip().split(" ")
                confOption, confType = lineComp[0], lineComp[1]

                # skips private and virtual entries if not configured to show them
                if not self._config[
                        "features.config.state.showPrivateOptions"] and confOption.startswith(
                            "__"):
                    continue
                elif not self._config[
                        "features.config.state.showVirtualOptions"] and confType == "Virtual":
                    continue

                self.confContents.append(
                    ConfigEntry(confOption, confType,
                                not confOption in customOptions))
        elif self.configType == State.ARM:
            # loaded via the conf utility
            armConf = conf.getConfig("arm")
            for key in armConf.getKeys():
                pass  # TODO: implement

        # mirror listing with only the important configuration options
        self.confImportantContents = []
        for entry in self.confContents:
            if torConfig.isImportant(entry.get(Field.OPTION)):
                self.confImportantContents.append(entry)

        # if there aren't any important options then show everything
        if not self.confImportantContents:
            self.confImportantContents = self.confContents

        self.setSortOrder()  # initial sorting of the contents
Beispiel #2
0
    def __init__(self, stdscr, configType, config=None):
        panel.Panel.__init__(self, stdscr, "configState", 0)

        self.sortOrdering = DEFAULT_SORT_ORDER
        self._config = dict(DEFAULT_CONFIG)
        if config:
            config.update(
                self._config, {
                    "features.config.selectionDetails.height": 0,
                    "features.config.state.colWidth.option": 5,
                    "features.config.state.colWidth.value": 5
                })

            self.sortOrdering = config.getIntCSV("features.config.order",
                                                 self.sortOrdering, 3, 0, 6)

        self.configType = configType
        self.confContents = []
        self.scroller = uiTools.Scroller(True)
        self.valsLock = threading.RLock()

        if self.configType == TOR_STATE:
            conn = torTools.getConn()
            customOptions = torConfig.getCustomOptions()
            configOptionLines = conn.getInfo("config/names",
                                             "").strip().split("\n")

            for line in configOptionLines:
                # lines are of the form "<option> <type>", like:
                # UseEntryGuards Boolean
                confOption, confType = line.strip().split(" ", 1)

                # skips private and virtual entries if not set to show them
                if not self._config[
                        "features.config.state.showPrivateOptions"] and confOption.startswith(
                            "__"):
                    continue
                elif not self._config[
                        "features.config.state.showVirtualOptions"] and confType == "Virtual":
                    continue

                manEntry = torConfig.getConfigDescription(confOption)
                self.confContents.append(
                    ConfigEntry(confOption, confType,
                                not confOption in customOptions, manEntry))

            self.setSortOrder()  # initial sorting of the contents
        elif self.configType == ARM_STATE:
            # loaded via the conf utility
            armConf = conf.getConfig("arm")
            for key in armConf.getKeys():
                pass  # TODO: implement
Beispiel #3
0
def loadLogMessages():
  """
  Fetches a mapping of common log messages to their runlevels from the config.
  """
  
  global COMMON_LOG_MESSAGES
  armConf = conf.getConfig("arm")
  
  COMMON_LOG_MESSAGES = {}
  for confKey in armConf.getKeys():
    if confKey.startswith("msg."):
      eventType = confKey[4:].upper()
      messages = armConf.get(confKey, [])
      COMMON_LOG_MESSAGES[eventType] = messages
Beispiel #4
0
def loadLogMessages():
    """
  Fetches a mapping of common log messages to their runlevels from the config.
  """

    global COMMON_LOG_MESSAGES
    armConf = conf.getConfig("arm")

    COMMON_LOG_MESSAGES = {}
    for confKey in armConf.getKeys():
        if confKey.startswith("msg."):
            eventType = confKey[4:].upper()
            messages = armConf.get(confKey, [])
            COMMON_LOG_MESSAGES[eventType] = messages
Beispiel #5
0
 def _loadConfigOptions(self):
   """
   Fetches the configuration options available from tor or arm.
   """
   
   self.confContents = []
   self.confImportantContents = []
   
   if self.configType == State.TOR:
     conn, configOptionLines = torTools.getConn(), []
     customOptions = torConfig.getCustomOptions()
     configOptionQuery = conn.getInfo("config/names")
     
     if configOptionQuery:
       configOptionLines = configOptionQuery.strip().split("\n")
     
     for line in configOptionLines:
       # lines are of the form "<option> <type>[ <documentation>]", like:
       # UseEntryGuards Boolean
       # documentation is aparently only in older versions (for instance,
       # 0.2.1.25)
       lineComp = line.strip().split(" ")
       confOption, confType = lineComp[0], lineComp[1]
       
       # skips private and virtual entries if not configured to show them
       if not self._config["features.config.state.showPrivateOptions"] and confOption.startswith("__"):
         continue
       elif not self._config["features.config.state.showVirtualOptions"] and confType == "Virtual":
         continue
       
       self.confContents.append(ConfigEntry(confOption, confType, not confOption in customOptions))
   elif self.configType == State.ARM:
     # loaded via the conf utility
     armConf = conf.getConfig("arm")
     for key in armConf.getKeys():
       pass # TODO: implement
   
   # mirror listing with only the important configuration options
   self.confImportantContents = []
   for entry in self.confContents:
     if torConfig.isImportant(entry.get(Field.OPTION)):
       self.confImportantContents.append(entry)
   
   # if there aren't any important options then show everything
   if not self.confImportantContents:
     self.confImportantContents = self.confContents
   
   self.setSortOrder() # initial sorting of the contents
Beispiel #6
0
 def __init__(self, stdscr, configType, config=None):
   panel.Panel.__init__(self, stdscr, "configState", 0)
   
   self.sortOrdering = DEFAULT_SORT_ORDER
   self._config = dict(DEFAULT_CONFIG)
   if config:
     config.update(self._config, {
       "features.config.selectionDetails.height": 0,
       "features.config.state.colWidth.option": 5,
       "features.config.state.colWidth.value": 5})
     
     self.sortOrdering = config.getIntCSV("features.config.order", self.sortOrdering, 3, 0, 6)
   
   self.configType = configType
   self.confContents = []
   self.scroller = uiTools.Scroller(True)
   self.valsLock = threading.RLock()
   
   if self.configType == TOR_STATE:
     conn = torTools.getConn()
     customOptions = torConfig.getCustomOptions()
     configOptionLines = conn.getInfo("config/names", "").strip().split("\n")
     
     for line in configOptionLines:
       # lines are of the form "<option> <type>", like:
       # UseEntryGuards Boolean
       confOption, confType = line.strip().split(" ", 1)
       
       # skips private and virtual entries if not set to show them
       if not self._config["features.config.state.showPrivateOptions"] and confOption.startswith("__"):
         continue
       elif not self._config["features.config.state.showVirtualOptions"] and confType == "Virtual":
         continue
       
       manEntry = torConfig.getConfigDescription(confOption)
       self.confContents.append(ConfigEntry(confOption, confType, not confOption in customOptions, manEntry))
     
     self.setSortOrder() # initial sorting of the contents
   elif self.configType == ARM_STATE:
     # loaded via the conf utility
     armConf = conf.getConfig("arm")
     for key in armConf.getKeys():
       pass # TODO: implement
def drawTorMonitor(stdscr, startTime):
    """
  Main draw loop context.
  
  Arguments:
    stdscr    - curses window
    startTime - unix time for when arm was started
  """

    initController(stdscr, startTime)
    control = getController()

    # provides notice about any unused config keys
    for key in conf.getConfig("arm").getUnusedKeys():
        log.log(CONFIG["log.configEntryUndefined"],
                "Unused configuration entry: %s" % key)

    # tells daemon panels to start
    for panelImpl in control.getDaemonPanels():
        panelImpl.start()

    # allows for background transparency
    try:
        curses.use_default_colors()
    except curses.error:
        pass

    # makes the cursor invisible
    try:
        curses.curs_set(0)
    except curses.error:
        pass

    # logs the initialization time
    msg = "arm started (initialization took %0.3f seconds)" % (time.time() -
                                                               startTime)
    log.log(CONFIG["log.startTime"], msg)

    # main draw loop
    overrideKey = None  # uses this rather than waiting on user input
    isUnresponsive = False  # flag for heartbeat responsiveness check
    if not torTools.getConn().isAlive(): overrideKey = ord('w')  # shows wizard

    while not control.isDone():
        displayPanels = control.getDisplayPanels()
        isUnresponsive = heartbeatCheck(isUnresponsive)

        # sets panel visability
        for panelImpl in control.getAllPanels():
            panelImpl.setVisible(panelImpl in displayPanels)

        # redraws the interface if it's needed
        control.redraw(False)
        stdscr.refresh()

        # wait for user keyboard input until timeout, unless an override was set
        if overrideKey:
            key, overrideKey = overrideKey, None
        else:
            curses.halfdelay(CONFIG["features.redrawRate"] * 10)
            key = stdscr.getch()

        if key == curses.KEY_RIGHT:
            control.nextPage()
        elif key == curses.KEY_LEFT:
            control.prevPage()
        elif key == ord('p') or key == ord('P'):
            control.setPaused(not control.isPaused())
        elif key == ord('m') or key == ord('M'):
            cli.menu.menu.showMenu()
        elif key == ord('q') or key == ord('Q'):
            # provides prompt to confirm that arm should exit
            if CONFIG["features.confirmQuit"]:
                msg = "Are you sure (q again to confirm)?"
                confirmationKey = cli.popups.showMsg(msg, attr=curses.A_BOLD)
                quitConfirmed = confirmationKey in (ord('q'), ord('Q'))
            else:
                quitConfirmed = True

            if quitConfirmed: control.quit()
        elif key == ord('x') or key == ord('X'):
            # provides prompt to confirm that arm should issue a sighup
            msg = "This will reset Tor's internal state. Are you sure (x again to confirm)?"
            confirmationKey = cli.popups.showMsg(msg, attr=curses.A_BOLD)

            if confirmationKey in (ord('x'), ord('X')):
                try:
                    torTools.getConn().reload()
                except IOError, exc:
                    log.log(
                        log.ERR, "Error detected when reloading tor: %s" %
                        sysTools.getFileErrorMsg(exc))
        elif key == ord('h') or key == ord('H'):
            overrideKey = cli.popups.showHelpPopup()
def initController(stdscr, startTime):
    """
  Spawns the controller, and related panels for it.
  
  Arguments:
    stdscr - curses window
  """

    global ARM_CONTROLLER
    config = conf.getConfig("arm")

    # initializes the panels
    stickyPanels = [
        cli.headerPanel.HeaderPanel(stdscr, startTime, config),
        LabelPanel(stdscr)
    ]
    pagePanels, firstPagePanels = [], []

    # first page: graph and log
    if CONFIG["features.panels.show.graph"]:
        firstPagePanels.append(cli.graphing.graphPanel.GraphPanel(stdscr))

    if CONFIG["features.panels.show.log"]:
        expandedEvents = cli.logPanel.expandEvents(CONFIG["startup.events"])
        firstPagePanels.append(
            cli.logPanel.LogPanel(stdscr, expandedEvents, config))

    if firstPagePanels: pagePanels.append(firstPagePanels)

    # second page: connections
    if not CONFIG["startup.blindModeEnabled"] and CONFIG[
            "features.panels.show.connection"]:
        pagePanels.append(
            [cli.connections.connPanel.ConnectionPanel(stdscr, config)])

    # third page: config
    if CONFIG["features.panels.show.config"]:
        pagePanels.append([
            cli.configPanel.ConfigPanel(stdscr, cli.configPanel.State.TOR,
                                        config)
        ])

    # fourth page: torrc
    if CONFIG["features.panels.show.torrc"]:
        pagePanels.append([
            cli.torrcPanel.TorrcPanel(stdscr, cli.torrcPanel.Config.TORRC,
                                      config)
        ])

    if CONFIG["features.panels.show.interpretor"]:
        pagePanels.append([cli.interpretorPanel.InterpretorPanel(stdscr)])

    # initializes the controller
    ARM_CONTROLLER = Controller(stdscr, stickyPanels, pagePanels)

    # additional configuration for the graph panel
    graphPanel = ARM_CONTROLLER.getPanel("graph")

    if graphPanel:
        # statistical monitors for graph
        bwStats = cli.graphing.bandwidthStats.BandwidthStats(config)
        graphPanel.addStats(GraphStat.BANDWIDTH, bwStats)
        graphPanel.addStats(GraphStat.SYSTEM_RESOURCES,
                            cli.graphing.resourceStats.ResourceStats())
        if not CONFIG["startup.blindModeEnabled"]:
            graphPanel.addStats(GraphStat.CONNECTIONS,
                                cli.graphing.connStats.ConnStats())

        # sets graph based on config parameter
        try:
            initialStats = GRAPH_INIT_STATS.get(CONFIG["features.graph.type"])
            graphPanel.setStats(initialStats)
        except ValueError:
            pass  # invalid stats, maybe connections when in blind mode

        # prepopulates bandwidth values from state file
        if CONFIG["features.graph.bw.prepopulate"] and torTools.getConn(
        ).isAlive():
            isSuccessful = bwStats.prepopulateFromState()
            if isSuccessful: graphPanel.updateInterval = 4
def startTorMonitor(startTime):
    """
  Initializes the interface and starts the main draw loop.
  
  Arguments:
    startTime - unix time for when arm was started
  """

    # initializes interface configs
    config = conf.getConfig("arm")
    config.update(CONFIG, {
        "features.redrawRate": 1,
        "features.refreshRate": 0
    })

    cli.graphing.graphPanel.loadConfig(config)
    cli.connections.connEntry.loadConfig(config)
    cli.wizard.loadConfig(config)

    # attempts to fetch the tor pid, warning if unsuccessful (this is needed for
    # checking its resource usage, among other things)
    conn = torTools.getConn()
    torPid = conn.getMyPid()

    if not torPid and conn.isAlive():
        msg = "Unable to determine Tor's pid. Some information, like its resource usage will be unavailable."
        log.log(CONFIG["log.unknownTorPid"], msg)

    # adds events needed for arm functionality to the torTools REQ_EVENTS
    # mapping (they're then included with any setControllerEvents call, and log
    # a more helpful error if unavailable)

    torTools.REQ_EVENTS["BW"] = "bandwidth graph won't function"

    if not CONFIG["startup.blindModeEnabled"]:
        torTools.REQ_EVENTS[
            "CIRC"] = "may cause issues in identifying client connections"

        # Configures connection resoultions. This is paused/unpaused according to
        # if Tor's connected or not.
        conn.addStatusListener(connResetListener)

        if torPid:
            # use the tor pid to help narrow connection results
            torCmdName = sysTools.getProcessName(torPid, "tor")
            connections.getResolver(torCmdName, torPid, "tor")
        else:
            # constructs singleton resolver and, if tor isn't connected, initizes
            # it to be paused
            connections.getResolver("tor").setPaused(not conn.isAlive())

        # hack to display a better (arm specific) notice if all resolvers fail
        connections.RESOLVER_FINAL_FAILURE_MSG = "We were unable to use any of your system's resolvers to get tor's connections. This is fine, but means that the connections page will be empty. This is usually permissions related so if you would like to fix this then run arm with the same user as tor (ie, \"sudo -u <tor user> arm\")."

    # provides a notice about any event types tor supports but arm doesn't
    missingEventTypes = cli.logPanel.getMissingEventTypes()

    if missingEventTypes:
        pluralLabel = "s" if len(missingEventTypes) > 1 else ""
        log.log(
            CONFIG["log.torEventTypeUnrecognized"],
            "arm doesn't recognize the following event type%s: %s (log 'UNKNOWN' events to see them)"
            % (pluralLabel, ", ".join(missingEventTypes)))

    try:
        curses.wrapper(drawTorMonitor, startTime)
    except KeyboardInterrupt:
        # Skip printing stack trace in case of keyboard interrupt. The
        # HALT_ACTIVITY attempts to prevent daemons from triggering a curses redraw
        # (which would leave the user's terminal in a screwed up state). There is
        # still a tiny timing issue here (after the exception but before the flag
        # is set) but I've never seen it happen in practice.

        panel.HALT_ACTIVITY = True
        shutdownDaemons()
Beispiel #10
0
def drawTorMonitor(stdscr, startTime):
  """
  Main draw loop context.
  
  Arguments:
    stdscr    - curses window
    startTime - unix time for when arm was started
  """
  
  initController(stdscr, startTime)
  control = getController()
  
  # provides notice about any unused config keys
  for key in conf.getConfig("arm").getUnusedKeys():
    log.log(CONFIG["log.configEntryUndefined"], "Unused configuration entry: %s" % key)
  
  # tells daemon panels to start
  for panelImpl in control.getDaemonPanels(): panelImpl.start()
  
  # allows for background transparency
  try: curses.use_default_colors()
  except curses.error: pass
  
  # makes the cursor invisible
  try: curses.curs_set(0)
  except curses.error: pass
  
  # logs the initialization time
  msg = "arm started (initialization took %0.3f seconds)" % (time.time() - startTime)
  log.log(CONFIG["log.startTime"], msg)
  
  # main draw loop
  overrideKey = None     # uses this rather than waiting on user input
  isUnresponsive = False # flag for heartbeat responsiveness check
  if not torTools.getConn().isAlive(): overrideKey = ord('w') # shows wizard
  
  while not control.isDone():
    displayPanels = control.getDisplayPanels()
    isUnresponsive = heartbeatCheck(isUnresponsive)
    
    # sets panel visability
    for panelImpl in control.getAllPanels():
      panelImpl.setVisible(panelImpl in displayPanels)
    
    # redraws the interface if it's needed
    control.redraw(False)
    stdscr.refresh()
    
    # wait for user keyboard input until timeout, unless an override was set
    if overrideKey:
      key, overrideKey = overrideKey, None
    else:
      curses.halfdelay(CONFIG["features.redrawRate"] * 10)
      key = stdscr.getch()
    
    if key == curses.KEY_RIGHT:
      control.nextPage()
    elif key == curses.KEY_LEFT:
      control.prevPage()
    elif key == ord('p') or key == ord('P'):
      control.setPaused(not control.isPaused())
    elif key == ord('m') or key == ord('M'):
      cli.menu.menu.showMenu()
    elif key == ord('q') or key == ord('Q'):
      # provides prompt to confirm that arm should exit
      if CONFIG["features.confirmQuit"]:
        msg = "Are you sure (q again to confirm)?"
        confirmationKey = cli.popups.showMsg(msg, attr = curses.A_BOLD)
        quitConfirmed = confirmationKey in (ord('q'), ord('Q'))
      else: quitConfirmed = True
      
      if quitConfirmed: control.quit()
    elif key == ord('x') or key == ord('X'):
      # provides prompt to confirm that arm should issue a sighup
      msg = "This will reset Tor's internal state. Are you sure (x again to confirm)?"
      confirmationKey = cli.popups.showMsg(msg, attr = curses.A_BOLD)
      
      if confirmationKey in (ord('x'), ord('X')):
        try: torTools.getConn().reload()
        except IOError, exc:
          log.log(log.ERR, "Error detected when reloading tor: %s" % sysTools.getFileErrorMsg(exc))
    elif key == ord('h') or key == ord('H'):
      overrideKey = cli.popups.showHelpPopup()
Beispiel #11
0
def initController(stdscr, startTime):
  """
  Spawns the controller, and related panels for it.
  
  Arguments:
    stdscr - curses window
  """
  
  global ARM_CONTROLLER
  config = conf.getConfig("arm")
  
  # initializes the panels
  stickyPanels = [cli.headerPanel.HeaderPanel(stdscr, startTime, config),
                  LabelPanel(stdscr)]
  pagePanels, firstPagePanels = [], []
  
  # first page: graph and log
  if CONFIG["features.panels.show.graph"]:
    firstPagePanels.append(cli.graphing.graphPanel.GraphPanel(stdscr))
  
  if CONFIG["features.panels.show.log"]:
    expandedEvents = cli.logPanel.expandEvents(CONFIG["startup.events"])
    firstPagePanels.append(cli.logPanel.LogPanel(stdscr, expandedEvents, config))
  
  if firstPagePanels: pagePanels.append(firstPagePanels)
  
  # second page: connections
  if not CONFIG["startup.blindModeEnabled"] and CONFIG["features.panels.show.connection"]:
    pagePanels.append([cli.connections.connPanel.ConnectionPanel(stdscr, config)])
  
  # third page: config
  if CONFIG["features.panels.show.config"]:
    pagePanels.append([cli.configPanel.ConfigPanel(stdscr, cli.configPanel.State.TOR, config)])
  
  # fourth page: torrc
  if CONFIG["features.panels.show.torrc"]:
    pagePanels.append([cli.torrcPanel.TorrcPanel(stdscr, cli.torrcPanel.Config.TORRC, config)])
  
  if CONFIG["features.panels.show.interpretor"]:
    pagePanels.append([cli.interpretorPanel.InterpretorPanel(stdscr)])
  
  # initializes the controller
  ARM_CONTROLLER = Controller(stdscr, stickyPanels, pagePanels)
  
  # additional configuration for the graph panel
  graphPanel = ARM_CONTROLLER.getPanel("graph")
  
  if graphPanel:
    # statistical monitors for graph
    bwStats = cli.graphing.bandwidthStats.BandwidthStats(config)
    graphPanel.addStats(GraphStat.BANDWIDTH, bwStats)
    graphPanel.addStats(GraphStat.SYSTEM_RESOURCES, cli.graphing.resourceStats.ResourceStats())
    if not CONFIG["startup.blindModeEnabled"]:
      graphPanel.addStats(GraphStat.CONNECTIONS, cli.graphing.connStats.ConnStats())
    
    # sets graph based on config parameter
    try:
      initialStats = GRAPH_INIT_STATS.get(CONFIG["features.graph.type"])
      graphPanel.setStats(initialStats)
    except ValueError: pass # invalid stats, maybe connections when in blind mode
    
    # prepopulates bandwidth values from state file
    if CONFIG["features.graph.bw.prepopulate"] and torTools.getConn().isAlive():
      isSuccessful = bwStats.prepopulateFromState()
      if isSuccessful: graphPanel.updateInterval = 4
Beispiel #12
0
def startTorMonitor(startTime):
  """
  Initializes the interface and starts the main draw loop.
  
  Arguments:
    startTime - unix time for when arm was started
  """
  
  # initializes interface configs
  config = conf.getConfig("arm")
  config.update(CONFIG, {
    "features.redrawRate": 1,
    "features.refreshRate": 0})
  
  cli.graphing.graphPanel.loadConfig(config)
  cli.connections.connEntry.loadConfig(config)
  cli.wizard.loadConfig(config)
  
  # attempts to fetch the tor pid, warning if unsuccessful (this is needed for
  # checking its resource usage, among other things)
  conn = torTools.getConn()
  torPid = conn.getMyPid()
  
  if not torPid and conn.isAlive():
    msg = "Unable to determine Tor's pid. Some information, like its resource usage will be unavailable."
    log.log(CONFIG["log.unknownTorPid"], msg)
  
  # adds events needed for arm functionality to the torTools REQ_EVENTS
  # mapping (they're then included with any setControllerEvents call, and log
  # a more helpful error if unavailable)
  
  torTools.REQ_EVENTS["BW"] = "bandwidth graph won't function"
  
  if not CONFIG["startup.blindModeEnabled"]:
    torTools.REQ_EVENTS["CIRC"] = "may cause issues in identifying client connections"
    
    # Configures connection resoultions. This is paused/unpaused according to
    # if Tor's connected or not.
    conn.addStatusListener(connResetListener)
    
    if torPid:
      # use the tor pid to help narrow connection results
      torCmdName = sysTools.getProcessName(torPid, "tor")
      connections.getResolver(torCmdName, torPid, "tor")
    else:
      # constructs singleton resolver and, if tor isn't connected, initizes
      # it to be paused
      connections.getResolver("tor").setPaused(not conn.isAlive())
    
    # hack to display a better (arm specific) notice if all resolvers fail
    connections.RESOLVER_FINAL_FAILURE_MSG = "We were unable to use any of your system's resolvers to get tor's connections. This is fine, but means that the connections page will be empty. This is usually permissions related so if you would like to fix this then run arm with the same user as tor (ie, \"sudo -u <tor user> arm\")."
  
  # provides a notice about any event types tor supports but arm doesn't
  missingEventTypes = cli.logPanel.getMissingEventTypes()
  
  if missingEventTypes:
    pluralLabel = "s" if len(missingEventTypes) > 1 else ""
    log.log(CONFIG["log.torEventTypeUnrecognized"], "arm doesn't recognize the following event type%s: %s (log 'UNKNOWN' events to see them)" % (pluralLabel, ", ".join(missingEventTypes)))
  
  try:
    curses.wrapper(drawTorMonitor, startTime)
  except KeyboardInterrupt:
    # Skip printing stack trace in case of keyboard interrupt. The
    # HALT_ACTIVITY attempts to prevent daemons from triggering a curses redraw
    # (which would leave the user's terminal in a screwed up state). There is
    # still a tiny timing issue here (after the exception but before the flag
    # is set) but I've never seen it happen in practice.
    
    panel.HALT_ACTIVITY = True
    shutdownDaemons()
Beispiel #13
0
 def getRefreshRate(self):
   # provides the rate at which the panel has new stats to display
   if self._config["features.graph.ps.cachedOnly"]:
     return int(conf.getConfig("arm").get("queries.ps.rate", 5))
   else: return 1
Beispiel #14
0
    def draw(self, width, height):
        self.valsLock.acquire()

        # If true, we assume that the cached value in self._lastContentHeight is
        # still accurate, and stop drawing when there's nothing more to display.
        # Otherwise the self._lastContentHeight is suspect, and we'll process all
        # the content to check if it's right (and redraw again with the corrected
        # height if not).
        trustLastContentHeight = self._lastContentHeightArgs == (width, height)

        # restricts scroll location to valid bounds
        self.scroll = max(
            0, min(self.scroll, self._lastContentHeight - height + 1))

        renderedContents, corrections, confLocation = None, {}, None
        if self.configType == Config.TORRC:
            loadedTorrc = torConfig.getTorrc()
            loadedTorrc.getLock().acquire()
            confLocation = loadedTorrc.getConfigLocation()

            if not loadedTorrc.isLoaded():
                renderedContents = ["### Unable to load the torrc ###"]
            else:
                renderedContents = loadedTorrc.getDisplayContents(
                    self.stripComments)

                # constructs a mapping of line numbers to the issue on it
                corrections = dict(
                    (lineNum, (issue, msg))
                    for lineNum, issue, msg in loadedTorrc.getCorrections())

            loadedTorrc.getLock().release()
        else:
            loadedArmrc = conf.getConfig("arm")
            confLocation = loadedArmrc.path
            renderedContents = list(loadedArmrc.rawContents)

        # offset to make room for the line numbers
        lineNumOffset = 0
        if self.showLineNum:
            if len(renderedContents) == 0: lineNumOffset = 2
            else: lineNumOffset = int(math.log10(len(renderedContents))) + 2

        # draws left-hand scroll bar if content's longer than the height
        scrollOffset = 0
        if self._config[
                "features.config.file.showScrollbars"] and self._lastContentHeight > height - 1:
            scrollOffset = 3
            self.addScrollBar(self.scroll, self.scroll + height - 1,
                              self._lastContentHeight, 1)

        displayLine = -self.scroll + 1  # line we're drawing on

        # draws the top label
        if self.isTitleVisible():
            sourceLabel = "Tor" if self.configType == Config.TORRC else "Arm"
            locationLabel = " (%s)" % confLocation if confLocation else ""
            self.addstr(
                0, 0,
                "%s Configuration File%s:" % (sourceLabel, locationLabel),
                curses.A_STANDOUT)

        isMultiline = False  # true if we're in the middle of a multiline torrc entry
        for lineNumber in range(0, len(renderedContents)):
            lineText = renderedContents[lineNumber]
            lineText = lineText.rstrip()  # remove ending whitespace

            # blank lines are hidden when stripping comments
            if self.stripComments and not lineText: continue

            # splits the line into its component (msg, format) tuples
            lineComp = {
                "option": ["", curses.A_BOLD | uiTools.getColor("green")],
                "argument": ["", curses.A_BOLD | uiTools.getColor("cyan")],
                "correction": ["", curses.A_BOLD | uiTools.getColor("cyan")],
                "comment": ["", uiTools.getColor("white")]
            }

            # parses the comment
            commentIndex = lineText.find("#")
            if commentIndex != -1:
                lineComp["comment"][0] = lineText[commentIndex:]
                lineText = lineText[:commentIndex]

            # splits the option and argument, preserving any whitespace around them
            strippedLine = lineText.strip()
            optionIndex = strippedLine.find(" ")
            if isMultiline:
                # part of a multiline entry started on a previous line so everything
                # is part of the argument
                lineComp["argument"][0] = lineText
            elif optionIndex == -1:
                # no argument provided
                lineComp["option"][0] = lineText
            else:
                optionText = strippedLine[:optionIndex]
                optionEnd = lineText.find(optionText) + len(optionText)
                lineComp["option"][0] = lineText[:optionEnd]
                lineComp["argument"][0] = lineText[optionEnd:]

            # flags following lines as belonging to this multiline entry if it ends
            # with a slash
            if strippedLine: isMultiline = strippedLine.endswith("\\")

            # gets the correction
            if lineNumber in corrections:
                lineIssue, lineIssueMsg = corrections[lineNumber]

                if lineIssue in (torConfig.ValidationError.DUPLICATE,
                                 torConfig.ValidationError.IS_DEFAULT):
                    lineComp["option"][1] = curses.A_BOLD | uiTools.getColor(
                        "blue")
                    lineComp["argument"][1] = curses.A_BOLD | uiTools.getColor(
                        "blue")
                elif lineIssue == torConfig.ValidationError.MISMATCH:
                    lineComp["argument"][1] = curses.A_BOLD | uiTools.getColor(
                        "red")
                    lineComp["correction"][0] = " (%s)" % lineIssueMsg
                else:
                    # For some types of configs the correction field is simply used to
                    # provide extra data (for instance, the type for tor state fields).
                    lineComp["correction"][0] = " (%s)" % lineIssueMsg
                    lineComp["correction"][
                        1] = curses.A_BOLD | uiTools.getColor("magenta")

            # draws the line number
            if self.showLineNum and displayLine < height and displayLine >= 1:
                lineNumStr = ("%%%ii" % (lineNumOffset - 1)) % (lineNumber + 1)
                self.addstr(displayLine, scrollOffset, lineNumStr,
                            curses.A_BOLD | uiTools.getColor("yellow"))

            # draws the rest of the components with line wrap
            cursorLoc, lineOffset = lineNumOffset + scrollOffset, 0
            maxLinesPerEntry = self._config[
                "features.config.file.maxLinesPerEntry"]
            displayQueue = [
                lineComp[entry]
                for entry in ("option", "argument", "correction", "comment")
            ]

            while displayQueue:
                msg, format = displayQueue.pop(0)

                maxMsgSize, includeBreak = width - cursorLoc, False
                if len(msg) >= maxMsgSize:
                    # message is too long - break it up
                    if lineOffset == maxLinesPerEntry - 1:
                        msg = uiTools.cropStr(msg, maxMsgSize)
                    else:
                        includeBreak = True
                        msg, remainder = uiTools.cropStr(
                            msg, maxMsgSize, 4, 4, uiTools.Ending.HYPHEN, True)
                        displayQueue.insert(0, (remainder.strip(), format))

                drawLine = displayLine + lineOffset
                if msg and drawLine < height and drawLine >= 1:
                    self.addstr(drawLine, cursorLoc, msg, format)

                # If we're done, and have added content to this line, then start
                # further content on the next line.
                cursorLoc += len(msg)
                includeBreak |= not displayQueue and cursorLoc != lineNumOffset + scrollOffset

                if includeBreak:
                    lineOffset += 1
                    cursorLoc = lineNumOffset + scrollOffset

            displayLine += max(lineOffset, 1)

            if trustLastContentHeight and displayLine >= height: break

        if not trustLastContentHeight:
            self._lastContentHeightArgs = (width, height)
            newContentHeight = displayLine + self.scroll - 1

            if self._lastContentHeight != newContentHeight:
                self._lastContentHeight = newContentHeight
                self.redraw(True)

        self.valsLock.release()
Beispiel #15
0
 def draw(self, subwindow, width, height):
   self.valsLock.acquire()
   
   # If true, we assume that the cached value in self._lastContentHeight is
   # still accurate, and stop drawing when there's nothing more to display.
   # Otherwise the self._lastContentHeight is suspect, and we'll process all
   # the content to check if it's right (and redraw again with the corrected
   # height if not).
   trustLastContentHeight = self._lastContentHeightArgs == (width, height)
   
   # restricts scroll location to valid bounds
   self.scroll = max(0, min(self.scroll, self._lastContentHeight - height + 1))
   
   renderedContents, corrections, confLocation = None, {}, None
   if self.configType == TORRC:
     loadedTorrc = torConfig.getTorrc()
     loadedTorrc.getLock().acquire()
     confLocation = loadedTorrc.getConfigLocation()
     
     if not loadedTorrc.isLoaded():
       renderedContents = ["### Unable to load the torrc ###"]
     else:
       renderedContents = loadedTorrc.getDisplayContents(self.stripComments)
       
       # constructs a mapping of line numbers to the issue on it
       corrections = dict((lineNum, (issue, msg)) for lineNum, issue, msg in loadedTorrc.getCorrections())
     
     loadedTorrc.getLock().release()
   else:
     loadedArmrc = conf.getConfig("arm")
     confLocation = loadedArmrc.path
     renderedContents = list(loadedArmrc.rawContents)
   
   # offset to make room for the line numbers
   lineNumOffset = 0
   if self.showLineNum:
     if len(renderedContents) == 0: lineNumOffset = 2
     else: lineNumOffset = int(math.log10(len(renderedContents))) + 2
   
   # draws left-hand scroll bar if content's longer than the height
   scrollOffset = 0
   if self._config["features.config.file.showScrollbars"] and self._lastContentHeight > height - 1:
     scrollOffset = 3
     self.addScrollBar(self.scroll, self.scroll + height - 1, self._lastContentHeight, 1)
   
   displayLine = -self.scroll + 1 # line we're drawing on
   
   # draws the top label
   if self.showLabel:
     sourceLabel = "Tor" if self.configType == TORRC else "Arm"
     locationLabel = " (%s)" % confLocation if confLocation else ""
     self.addstr(0, 0, "%s Configuration File%s:" % (sourceLabel, locationLabel), curses.A_STANDOUT)
   
   isMultiline = False # true if we're in the middle of a multiline torrc entry
   for lineNumber in range(0, len(renderedContents)):
     lineText = renderedContents[lineNumber]
     lineText = lineText.rstrip() # remove ending whitespace
     
     # blank lines are hidden when stripping comments
     if self.stripComments and not lineText: continue
     
     # splits the line into its component (msg, format) tuples
     lineComp = {"option": ["", curses.A_BOLD | uiTools.getColor("green")],
                 "argument": ["", curses.A_BOLD | uiTools.getColor("cyan")],
                 "correction": ["", curses.A_BOLD | uiTools.getColor("cyan")],
                 "comment": ["", uiTools.getColor("white")]}
     
     # parses the comment
     commentIndex = lineText.find("#")
     if commentIndex != -1:
       lineComp["comment"][0] = lineText[commentIndex:]
       lineText = lineText[:commentIndex]
     
     # splits the option and argument, preserving any whitespace around them
     strippedLine = lineText.strip()
     optionIndex = strippedLine.find(" ")
     if isMultiline:
       # part of a multiline entry started on a previous line so everything
       # is part of the argument
       lineComp["argument"][0] = lineText
     elif optionIndex == -1:
       # no argument provided
       lineComp["option"][0] = lineText
     else:
       optionText = strippedLine[:optionIndex]
       optionEnd = lineText.find(optionText) + len(optionText)
       lineComp["option"][0] = lineText[:optionEnd]
       lineComp["argument"][0] = lineText[optionEnd:]
     
     # flags following lines as belonging to this multiline entry if it ends
     # with a slash
     if strippedLine: isMultiline = strippedLine.endswith("\\")
     
     # gets the correction
     if lineNumber in corrections:
       lineIssue, lineIssueMsg = corrections[lineNumber]
       
       if lineIssue in (torConfig.VAL_DUPLICATE, torConfig.VAL_IS_DEFAULT):
         lineComp["option"][1] = curses.A_BOLD | uiTools.getColor("blue")
         lineComp["argument"][1] = curses.A_BOLD | uiTools.getColor("blue")
       elif lineIssue == torConfig.VAL_MISMATCH:
         lineComp["argument"][1] = curses.A_BOLD | uiTools.getColor("red")
         lineComp["correction"][0] = " (%s)" % lineIssueMsg
       else:
         # For some types of configs the correction field is simply used to
         # provide extra data (for instance, the type for tor state fields).
         lineComp["correction"][0] = " (%s)" % lineIssueMsg
         lineComp["correction"][1] = curses.A_BOLD | uiTools.getColor("magenta")
     
     # draws the line number
     if self.showLineNum and displayLine < height and displayLine >= 1:
       lineNumStr = ("%%%ii" % (lineNumOffset - 1)) % (lineNumber + 1)
       self.addstr(displayLine, scrollOffset, lineNumStr, curses.A_BOLD | uiTools.getColor("yellow"))
     
     # draws the rest of the components with line wrap
     cursorLoc, lineOffset = lineNumOffset + scrollOffset, 0
     maxLinesPerEntry = self._config["features.config.file.maxLinesPerEntry"]
     displayQueue = [lineComp[entry] for entry in ("option", "argument", "correction", "comment")]
     
     while displayQueue:
       msg, format = displayQueue.pop(0)
       
       maxMsgSize, includeBreak = width - cursorLoc, False
       if len(msg) >= maxMsgSize:
         # message is too long - break it up
         if lineOffset == maxLinesPerEntry - 1:
           msg = uiTools.cropStr(msg, maxMsgSize)
         else:
           includeBreak = True
           msg, remainder = uiTools.cropStr(msg, maxMsgSize, 4, 4, uiTools.END_WITH_HYPHEN, True)
           displayQueue.insert(0, (remainder.strip(), format))
       
       drawLine = displayLine + lineOffset
       if msg and drawLine < height and drawLine >= 1:
         self.addstr(drawLine, cursorLoc, msg, format)
       
       # If we're done, and have added content to this line, then start
       # further content on the next line.
       cursorLoc += len(msg)
       includeBreak |= not displayQueue and cursorLoc != lineNumOffset + scrollOffset
       
       if includeBreak:
         lineOffset += 1
         cursorLoc = lineNumOffset + scrollOffset
     
     displayLine += max(lineOffset, 1)
     
     if trustLastContentHeight and displayLine >= height: break
   
   if not trustLastContentHeight:
     self._lastContentHeightArgs = (width, height)
     newContentHeight = displayLine + self.scroll - 1
     
     if self._lastContentHeight != newContentHeight:
       self._lastContentHeight = newContentHeight
       self.redraw(True)
   
   self.valsLock.release()