| OLD | NEW |
| (Empty) |
| 1 #!/usr/bin/env python | |
| 2 # Copyright (c) 2012 The Chromium Authors. All rights reserved. | |
| 3 # Use of this source code is governed by a BSD-style license that can be | |
| 4 # found in the LICENSE file. | |
| 5 | |
| 6 """Helper script to perform actions as a super-user on ChromeOS. | |
| 7 | |
| 8 Needs to be run with superuser privileges, typically using the | |
| 9 suid_python binary. | |
| 10 | |
| 11 Usage: | |
| 12 sudo python suid_actions.py --action=CleanFlimflamDirs | |
| 13 """ | |
| 14 | |
| 15 import optparse | |
| 16 import os | |
| 17 import shutil | |
| 18 import subprocess | |
| 19 import sys | |
| 20 import time | |
| 21 | |
| 22 sys.path.append('/usr/local') # to import autotest libs. | |
| 23 from autotest.cros import constants | |
| 24 from autotest.cros import cryptohome | |
| 25 | |
| 26 TEMP_BACKCHANNEL_FILE = '/tmp/pyauto_network_backchannel_file' | |
| 27 | |
| 28 | |
| 29 class SuidAction(object): | |
| 30 """Helper to perform some super-user actions on ChromeOS.""" | |
| 31 | |
| 32 def _ParseArgs(self): | |
| 33 parser = optparse.OptionParser() | |
| 34 parser.add_option( | |
| 35 '-a', '--action', help='Action to perform.') | |
| 36 self._options = parser.parse_args()[0] | |
| 37 if not self._options.action: | |
| 38 raise RuntimeError('No action specified.') | |
| 39 | |
| 40 def Run(self): | |
| 41 self._ParseArgs() | |
| 42 assert os.geteuid() == 0, 'Needs superuser privileges.' | |
| 43 handler = getattr(self, self._options.action) | |
| 44 assert handler and callable(handler), \ | |
| 45 'No handler for %s' % self._options.action | |
| 46 handler() | |
| 47 return 0 | |
| 48 | |
| 49 ## Actions ## | |
| 50 def CleanFlimflamDirs(self): | |
| 51 """Clean the contents of all connection manager (shill/flimflam) profiles. | |
| 52 """ | |
| 53 flimflam_dirs = ['/home/chronos/user/flimflam', | |
| 54 '/home/chronos/user/shill', | |
| 55 '/var/cache/flimflam', | |
| 56 '/var/cache/shill'] | |
| 57 | |
| 58 # The stop/start flimflam command should stop/start shill respectivly if | |
| 59 # enabled. | |
| 60 os.system('stop flimflam') | |
| 61 try: | |
| 62 for flimflam_dir in flimflam_dirs: | |
| 63 if not os.path.exists(flimflam_dir): | |
| 64 continue | |
| 65 for item in os.listdir(flimflam_dir): | |
| 66 path = os.path.join(flimflam_dir, item) | |
| 67 if os.path.isdir(path): | |
| 68 shutil.rmtree(path) | |
| 69 else: | |
| 70 os.remove(path) | |
| 71 finally: | |
| 72 os.system('start flimflam') | |
| 73 # TODO(stanleyw): crosbug.com/29421 This method should wait until | |
| 74 # flimflam/shill is fully initialized and accessible via DBus again. | |
| 75 # Otherwise, there is a race conditions and subsequent accesses to | |
| 76 # flimflam/shill may fail. Until this is fixed, waiting for the | |
| 77 # resolv.conf file to be created is better than nothing. | |
| 78 begin = time.time() | |
| 79 while not os.path.exists(constants.RESOLV_CONF_FILE): | |
| 80 if time.time() - begin > 10: | |
| 81 raise RuntimeError('Timeout while waiting for flimflam/shill start.') | |
| 82 time.sleep(.25) | |
| 83 | |
| 84 def RemoveAllCryptohomeVaults(self): | |
| 85 """Remove any existing cryptohome vaults.""" | |
| 86 cryptohome.remove_all_vaults() | |
| 87 | |
| 88 def _GetEthInterfaces(self): | |
| 89 """Returns a list of the eth* interfaces detected by the device.""" | |
| 90 # Assumes ethernet interfaces all have "eth" in the name. | |
| 91 import pyudev | |
| 92 return sorted([iface.sys_name for iface in | |
| 93 pyudev.Context().list_devices(subsystem='net') | |
| 94 if 'eth' in iface.sys_name]) | |
| 95 | |
| 96 def _Renameif(self, old_iface, new_iface, mac_address): | |
| 97 """Renames the interface with mac_address from old_iface to new_iface. | |
| 98 | |
| 99 Args: | |
| 100 old_iface: The name of the interface you want to change. | |
| 101 new_iface: The name of the interface you want to change to. | |
| 102 mac_address: The mac address of the interface being changed. | |
| 103 """ | |
| 104 subprocess.call(['stop', 'flimflam']) | |
| 105 subprocess.call(['ifconfig', old_iface, 'down']) | |
| 106 subprocess.call(['nameif', new_iface, mac_address]) | |
| 107 subprocess.call(['ifconfig', new_iface, 'up']) | |
| 108 subprocess.call(['start', 'flimflam']) | |
| 109 | |
| 110 # Check and make sure interfaces have been renamed | |
| 111 eth_ifaces = self._GetEthInterfaces() | |
| 112 if new_iface not in eth_ifaces: | |
| 113 raise RuntimeError('Interface %s was not renamed to %s' % | |
| 114 (old_iface, new_iface)) | |
| 115 elif old_iface in eth_ifaces: | |
| 116 raise RuntimeError('Old iface %s is still present' % old_iface) | |
| 117 | |
| 118 def SetupBackchannel(self): | |
| 119 """Renames the connected ethernet interface to eth_test for offline mode | |
| 120 testing. Does nothing if no connected interface is found. | |
| 121 """ | |
| 122 # Return the interface with ethernet connected or returns if none found. | |
| 123 for iface in self._GetEthInterfaces(): | |
| 124 with open('/sys/class/net/%s/operstate' % iface, 'r') as fp: | |
| 125 if 'up' in fp.read(): | |
| 126 eth_iface = iface | |
| 127 break | |
| 128 else: | |
| 129 return | |
| 130 | |
| 131 # Write backup file to be used by TeardownBackchannel to restore the | |
| 132 # interface names. | |
| 133 with open(TEMP_BACKCHANNEL_FILE, 'w') as fpw: | |
| 134 with open('/sys/class/net/%s/address' % eth_iface) as fp: | |
| 135 mac_address = fp.read().strip() | |
| 136 fpw.write('%s, %s' % (eth_iface, mac_address)) | |
| 137 | |
| 138 self._Renameif(eth_iface, 'eth_test', mac_address) | |
| 139 | |
| 140 def TeardownBackchannel(self): | |
| 141 """Restores the eth interface names if SetupBackchannel was called.""" | |
| 142 if not os.path.isfile(TEMP_BACKCHANNEL_FILE): | |
| 143 return | |
| 144 | |
| 145 with open(TEMP_BACKCHANNEL_FILE, 'r') as fp: | |
| 146 eth_iface, mac_address = fp.read().split(',') | |
| 147 | |
| 148 self._Renameif('eth_test', eth_iface, mac_address) | |
| 149 os.remove(TEMP_BACKCHANNEL_FILE) | |
| 150 | |
| 151 | |
| 152 if __name__ == '__main__': | |
| 153 sys.exit(SuidAction().Run()) | |
| OLD | NEW |