Steven Bennetts | 62fd725 | 2011-11-03 20:56:09 | [diff] [blame] | 1 | #!/usr/bin/env python |
| 2 | # Copyright (c) 2011 The Chromium OS 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 | """This script provides a suite of utility functions for the chroot. |
| 7 | """ |
| 8 | |
| 9 | import optparse |
| 10 | import os |
| 11 | import shutil |
| 12 | import subprocess |
| 13 | import sys |
| 14 | |
| 15 | _PROG = "crdev" |
| 16 | _SSH_KEY_FILEPATH = os.path.expanduser("~/.ssh/id_rsa") |
| 17 | _PUB_KEY_FILENAME = "~/.ssh/id_rsa.pub" |
| 18 | _PUB_KEY_FILEPATH = os.path.expanduser(_PUB_KEY_FILENAME) |
| 19 | _AUTH_KEYS_FILEPATH = os.path.expanduser("~/.ssh/authorized_keys") |
| 20 | _CHROME_MOUNT_PATH = "/tmp/chrome" |
Steven Bennetts | 26178d9 | 2011-11-22 18:54:41 | [diff] [blame] | 21 | # Note: no ~/ for sshfs: |
| 22 | _DEFAULT_HOST_CHROOT_DIR = "chromeos/chroot" |
| 23 | _HOST_CHROOT_DIR_FILENAME = os.path.expanduser("~/.chromedir") |
Steven Bennetts | 62fd725 | 2011-11-03 20:56:09 | [diff] [blame] | 24 | |
| 25 | RAN_SUDO = False |
| 26 | |
| 27 | ############################################################################### |
| 28 | # Utility commands |
| 29 | |
Steven Bennetts | 26178d9 | 2011-11-22 18:54:41 | [diff] [blame] | 30 | def _PrintError(msg, err=""): |
| 31 | """Print a message with an optional error message to stderr""" |
| 32 | if err: |
| 33 | print >> sys.stderr, "%s: %s" % (msg, err) |
| 34 | else: |
| 35 | print >> sys.stderr, msg |
| 36 | |
| 37 | def _Confirm(message, default_response="n"): |
Steven Bennetts | 62fd725 | 2011-11-03 20:56:09 | [diff] [blame] | 38 | """Request confirmation and return True/False.""" |
Steven Bennetts | 26178d9 | 2011-11-22 18:54:41 | [diff] [blame] | 39 | default_lc = default_response.lower() |
| 40 | if default_lc == "y": |
| 41 | input_msg = "%s [Y/n] " % message |
| 42 | else: |
| 43 | input_msg = "%s [y/N] " % message |
| 44 | |
| 45 | reply = raw_input(input_msg).lower() |
| 46 | if reply: |
| 47 | return reply == "y" |
| 48 | return default_lc == "y" |
Steven Bennetts | 62fd725 | 2011-11-03 20:56:09 | [diff] [blame] | 49 | |
| 50 | |
| 51 | def _CheckOverwriteFile(filepath): |
| 52 | """Check for a file and request confirmation if it exists.""" |
| 53 | if os.path.isfile(filepath): |
Steven Bennetts | 26178d9 | 2011-11-22 18:54:41 | [diff] [blame] | 54 | if not _Confirm("%s already exists. Overwrite?" % filepath): |
Steven Bennetts | 62fd725 | 2011-11-03 20:56:09 | [diff] [blame] | 55 | return False |
| 56 | return True |
| 57 | |
| 58 | |
| 59 | def _WriteFile(filepath, contents): |
| 60 | """Write string |contents| to |filepath|.""" |
| 61 | try: |
| 62 | print "Writing to: ", filepath |
| 63 | with open(filepath,"w") as f_1: |
| 64 | f_1.write(contents) |
Steven Bennetts | 26178d9 | 2011-11-22 18:54:41 | [diff] [blame] | 65 | except EnvironmentError as err: |
| 66 | _PrintError("Failed to write to file '%s'" % filepath, err) |
Steven Bennetts | 62fd725 | 2011-11-03 20:56:09 | [diff] [blame] | 67 | return False |
| 68 | |
| 69 | return True |
| 70 | |
| 71 | |
Steven Bennetts | 26178d9 | 2011-11-22 18:54:41 | [diff] [blame] | 72 | def _ReadFile(filepath): |
| 73 | """Return contents of |filepath| as a string.""" |
| 74 | try: |
| 75 | print "Reading from: " + filepath |
| 76 | with open(filepath,"r") as f_1: |
| 77 | result = f_1.read() |
| 78 | except EnvironmentError as err: |
| 79 | _PrintError("Failed to read from file '%s'" % filepath, err) |
| 80 | return None |
| 81 | |
| 82 | return result.rstrip() |
| 83 | |
| 84 | |
Steven Bennetts | 62fd725 | 2011-11-03 20:56:09 | [diff] [blame] | 85 | def _Sudo(): |
| 86 | """Request sudo access with message.""" |
| 87 | global RAN_SUDO |
| 88 | if not RAN_SUDO: |
| 89 | print "Executing: sudo -v" |
| 90 | try: |
| 91 | subprocess.call(["sudo", "-v"]) |
Steven Bennetts | 26178d9 | 2011-11-22 18:54:41 | [diff] [blame] | 92 | except EnvironmentError as err: |
| 93 | _PrintError("Failed to run sudo", err) |
Steven Bennetts | 62fd725 | 2011-11-03 20:56:09 | [diff] [blame] | 94 | return False |
| 95 | RAN_SUDO = True |
| 96 | return True |
| 97 | |
| 98 | |
| 99 | def _RunCommand(args): |
| 100 | """Pass |args| to subprocess.call() and check the result.""" |
| 101 | cmd = ''.join([x + " " for x in args]) |
| 102 | try: |
| 103 | if args[0] == "sudo": |
| 104 | if _Sudo() == False: |
| 105 | return False |
| 106 | print "Executing: ", cmd |
| 107 | retcode = subprocess.call(args) |
Steven Bennetts | 26178d9 | 2011-11-22 18:54:41 | [diff] [blame] | 108 | except EnvironmentError as err: |
| 109 | _PrintError("Failed to run command '%s'" % cmd, err) |
Steven Bennetts | 62fd725 | 2011-11-03 20:56:09 | [diff] [blame] | 110 | return False |
| 111 | else: |
| 112 | if retcode != 0: |
Steven Bennetts | 26178d9 | 2011-11-22 18:54:41 | [diff] [blame] | 113 | _PrintError("Error running command '%s'" % cmd, "%s" % retcode) |
Steven Bennetts | 62fd725 | 2011-11-03 20:56:09 | [diff] [blame] | 114 | return False |
| 115 | return True |
| 116 | |
| 117 | |
| 118 | def _GetCommandOutput(args): |
| 119 | """Pass |args| to subprocess.Popen and return the output.""" |
| 120 | cmd = ''.join([x + " " for x in args]) |
| 121 | try: |
| 122 | proc = subprocess.Popen(args, stdout=subprocess.PIPE) |
| 123 | result = proc.communicate()[0] |
Steven Bennetts | 26178d9 | 2011-11-22 18:54:41 | [diff] [blame] | 124 | except EnvironmentError as err: |
| 125 | _PrintError("Failed to run command '%s'" % cmd, err) |
Steven Bennetts | 62fd725 | 2011-11-03 20:56:09 | [diff] [blame] | 126 | return None |
| 127 | result = result.rstrip('\n') |
| 128 | return result |
| 129 | |
| 130 | |
Steven Bennetts | 26178d9 | 2011-11-22 18:54:41 | [diff] [blame] | 131 | def _MakeDirectory(dirpath, warn=True): |
Steven Bennetts | 62fd725 | 2011-11-03 20:56:09 | [diff] [blame] | 132 | """Create directory |dirpath| if it does not exist.""" |
| 133 | if not os.path.isdir(dirpath): |
| 134 | try: |
| 135 | print "Creating directory: ", dirpath |
| 136 | os.makedirs(dirpath) |
Steven Bennetts | 26178d9 | 2011-11-22 18:54:41 | [diff] [blame] | 137 | except EnvironmentError as err: |
| 138 | if warn: |
| 139 | _PrintError("Failed to create directory '%s'" % dirpath, err) |
Steven Bennetts | 62fd725 | 2011-11-03 20:56:09 | [diff] [blame] | 140 | return False |
| 141 | return True |
| 142 | |
| 143 | |
| 144 | def _RemoveFile(filepath): |
| 145 | """Remove file |filepath| if it exists.""" |
| 146 | if os.path.isfile(filepath): |
| 147 | try: |
| 148 | print "Removing file: ", filepath |
| 149 | os.remove(filepath) |
Steven Bennetts | 26178d9 | 2011-11-22 18:54:41 | [diff] [blame] | 150 | except EnvironmentError as err: |
| 151 | _PrintError("Failed to remove file '%s'" % filepath, err) |
Steven Bennetts | 62fd725 | 2011-11-03 20:56:09 | [diff] [blame] | 152 | return False |
| 153 | return True |
| 154 | |
| 155 | |
| 156 | def _RemoveDirectory(dirpath): |
| 157 | """Recursively remove directory |dirpath| if it exists.""" |
| 158 | if os.path.isdir(dirpath): |
| 159 | try: |
| 160 | print "Removing directory: ", dirpath |
| 161 | shutil.rmtree(dirpath) |
Steven Bennetts | 26178d9 | 2011-11-22 18:54:41 | [diff] [blame] | 162 | except EnvironmentError as err: |
| 163 | _PrintError("Failed to remove dir '%s'" % dirpath, err) |
Steven Bennetts | 62fd725 | 2011-11-03 20:56:09 | [diff] [blame] | 164 | return False |
| 165 | return True |
| 166 | |
| 167 | |
| 168 | def _DevUser(): |
| 169 | """Extract the user name from lsb-release.""" |
Steven Bennetts | 26178d9 | 2011-11-22 18:54:41 | [diff] [blame] | 170 | # TODO(stevenjb): Refactor this using python re. |
Steven Bennetts | 62fd725 | 2011-11-03 20:56:09 | [diff] [blame] | 171 | awk_expr = """/CHROMEOS_RELEASE_DESCRIPTION/ {""" |
Steven Bennetts | b28276a | 2011-11-29 20:29:31 | [diff] [blame] | 172 | awk_expr += """ sub(/.*Build - /,"");""" |
Steven Bennetts | 62fd725 | 2011-11-03 20:56:09 | [diff] [blame] | 173 | awk_expr += """ sub(/\).*/,"");""" |
| 174 | awk_expr += """ print; }""" |
| 175 | return _GetCommandOutput(["awk", awk_expr, "/etc/lsb-release"]) |
| 176 | |
| 177 | |
| 178 | def _DevHost(): |
| 179 | """Extract the host name from lsb-release.""" |
Steven Bennetts | 26178d9 | 2011-11-22 18:54:41 | [diff] [blame] | 180 | # TODO(stevenjb): Refactor this using python re. |
Steven Bennetts | 62fd725 | 2011-11-03 20:56:09 | [diff] [blame] | 181 | awk_expr = """/CHROMEOS_DEVSERVER/ {""" |
| 182 | awk_expr += """ sub(/.*http:\/\//,"");""" |
| 183 | awk_expr += """ sub(/:8080.*/,"");""" |
| 184 | awk_expr += """ print; }""" |
| 185 | return _GetCommandOutput(["awk", awk_expr, "/etc/lsb-release"]) |
| 186 | |
Steven Bennetts | 26178d9 | 2011-11-22 18:54:41 | [diff] [blame] | 187 | |
| 188 | def _DevBoard(): |
| 189 | """Extract the board from lsb-release.""" |
| 190 | # TODO(stevenjb): Refactor this using python re. |
| 191 | awk_expr = """/CHROMEOS_RELEASE_BOARD/ {""" |
| 192 | awk_expr += """ sub(/.*=/,"");""" |
| 193 | awk_expr += """ print; }""" |
| 194 | return _GetCommandOutput(["awk", awk_expr, "/etc/lsb-release"]) |
| 195 | |
| 196 | |
| 197 | def _GetChrootDir(prompt_for_dir=False): |
| 198 | """Get the name for the chrome directory on the host.""" |
Steven Bennetts | b28276a | 2011-11-29 20:29:31 | [diff] [blame] | 199 | if os.path.isfile(_HOST_CHROOT_DIR_FILENAME): |
| 200 | chromedir = _ReadFile(_HOST_CHROOT_DIR_FILENAME) |
| 201 | else: |
Steven Bennetts | 26178d9 | 2011-11-22 18:54:41 | [diff] [blame] | 202 | chromedir = _DEFAULT_HOST_CHROOT_DIR |
| 203 | |
| 204 | if prompt_for_dir: |
| 205 | host = _DevHost() |
Steven Bennetts | b28276a | 2011-11-29 20:29:31 | [diff] [blame] | 206 | prompt = ("Chroot directory on %s [ %s ]: " % (host, chromedir)) |
Steven Bennetts | 26178d9 | 2011-11-22 18:54:41 | [diff] [blame] | 207 | inputdir = raw_input(prompt).rstrip() |
| 208 | if inputdir: |
| 209 | chromedir = inputdir |
| 210 | _WriteFile(_HOST_CHROOT_DIR_FILENAME, chromedir) |
| 211 | |
| 212 | return chromedir |
| 213 | |
| 214 | |
Chris Masone | 32ee201 | 2011-12-13 16:48:21 | [diff] [blame] | 215 | def _DaemonizeAndReRunAsRoot(cmd): |
| 216 | """Double-fork to become owned by init, then re-exec this tool as root. |
| 217 | |
| 218 | Double-forking is the standard way to detach yourself from a |
| 219 | process tree and become owned by init. By doing this, you get to |
| 220 | live on even if your parent goes away.""" |
| 221 | try: |
| 222 | pid = os.fork() |
| 223 | if pid > 0: |
| 224 | sys.exit(0) # Just want to go away silently. |
| 225 | except OSError, e: |
| 226 | return False |
| 227 | try: |
| 228 | pid = os.fork() |
| 229 | if pid > 0: |
| 230 | sys.exit(0) # Just want to go away silently. |
| 231 | except OSError, e: |
| 232 | return False |
| 233 | |
| 234 | # re-run self as root. |
| 235 | try: |
| 236 | os.execlp('sudo', sys.executable, __file__, cmd) |
| 237 | except OSError, e: |
| 238 | _PrintError("Unable to exec self as root: %s", str(e)) |
| 239 | return False |
| 240 | |
| 241 | |
Steven Bennetts | 62fd725 | 2011-11-03 20:56:09 | [diff] [blame] | 242 | ############################################################################### |
| 243 | # Other Commands |
| 244 | |
| 245 | def TestCommand(args): |
| 246 | """Test command.""" |
Steven Bennetts | 26178d9 | 2011-11-22 18:54:41 | [diff] [blame] | 247 | _WriteFile("/foo/test", "test") |
Steven Bennetts | 62fd725 | 2011-11-03 20:56:09 | [diff] [blame] | 248 | if len(args) == 0: |
| 249 | args = ["sudo", "ls", "/"] |
| 250 | return _RunCommand(args) |
| 251 | return False |
| 252 | |
| 253 | |
Steven Bennetts | 26178d9 | 2011-11-22 18:54:41 | [diff] [blame] | 254 | def GetBoard(unused_args=0): |
| 255 | """Gets the board name from /etc/lsb-release.""" |
| 256 | print _DevBoard() |
| 257 | return True |
| 258 | |
| 259 | |
Steven Bennetts | 62fd725 | 2011-11-03 20:56:09 | [diff] [blame] | 260 | def GetUser(unused_args=0): |
| 261 | """Gets the user name from /etc/lsb-release.""" |
| 262 | print _DevUser() |
| 263 | return True |
| 264 | |
| 265 | |
| 266 | def GetHost(unused_args=0): |
| 267 | """Gets the host name from /etc/lsb-release.""" |
| 268 | print _DevHost() |
| 269 | return True |
| 270 | |
| 271 | |
| 272 | def MountWriteable(unused_args=0): |
| 273 | """Remounts / as rw.""" |
| 274 | return _RunCommand(["sudo", "mount", "-o", "remount,rw", "/"]) |
| 275 | |
| 276 | |
| 277 | def ShowIP(unused_args=0): |
| 278 | """Shows the IP address of the device.""" |
| 279 | proc1 = subprocess.Popen(["/sbin/ifconfig", "eth0"], stdout=subprocess.PIPE) |
| 280 | awk_cmd = """/inet addr/ {""" |
| 281 | awk_cmd += """ sub(/.*inet addr:/,""); sub(/ Bcast:.*/,"");""" |
| 282 | awk_cmd += """ print; }""" |
| 283 | proc2 = subprocess.Popen( |
| 284 | ["awk", awk_cmd], stdin=proc1.stdout, stdout=subprocess.PIPE) |
| 285 | proc1.stdout.close() |
| 286 | result = proc2.communicate()[0].rstrip('\n') |
| 287 | print "IP: ", result |
| 288 | return True |
| 289 | |
| 290 | |
| 291 | def KillChrome(unused_args=0): |
| 292 | """Kills all chrome processes and prevents restarting of chrome.""" |
| 293 | res = True |
Chris Masone | 649df54 | 2012-02-03 21:41:14 | [diff] [blame] | 294 | res &= _RunCommand(["touch", "/var/run/disable_chrome_restart"]) |
Steven Bennetts | 62fd725 | 2011-11-03 20:56:09 | [diff] [blame] | 295 | res &= _RunCommand(["sudo", "pkill", "-9", "chrome"]) |
| 296 | return res |
| 297 | |
| 298 | |
Chris Masone | 32ee201 | 2011-12-13 16:48:21 | [diff] [blame] | 299 | def ClearOwnership(unused_args=0): |
| 300 | """Clears any state related to the device Ownership (NOT TPM ownership).""" |
Steven Bennetts | 62fd725 | 2011-11-03 20:56:09 | [diff] [blame] | 301 | res = True |
Chris Masone | 32ee201 | 2011-12-13 16:48:21 | [diff] [blame] | 302 | res &= _RunCommand(["sudo", "stop", "ui"]) |
| 303 | |
| 304 | whitelist_dir = "/var/lib/whitelist" |
| 305 | for file in os.listdir(whitelist_dir): |
| 306 | res &= _RemoveFile(os.path.join(whitelist_dir, file)) |
| 307 | |
Steven Bennetts | 62fd725 | 2011-11-03 20:56:09 | [diff] [blame] | 308 | res &= _RemoveDirectory("/home/chronos/Local State") |
Chris Masone | 32ee201 | 2011-12-13 16:48:21 | [diff] [blame] | 309 | res &= _RemoveFile("/home/chronos/Consent To Send Stats") |
| 310 | res &= _RunCommand(["sudo", "start", "ui"]) |
Steven Bennetts | 62fd725 | 2011-11-03 20:56:09 | [diff] [blame] | 311 | |
| 312 | if not res: |
Chris Masone | 32ee201 | 2011-12-13 16:48:21 | [diff] [blame] | 313 | _PrintError("Errors encountered while clearing ownership state.") |
Steven Bennetts | 62fd725 | 2011-11-03 20:56:09 | [diff] [blame] | 314 | return False |
Steven Bennetts | 62fd725 | 2011-11-03 20:56:09 | [diff] [blame] | 315 | return True |
| 316 | |
Chris Masone | 32ee201 | 2011-12-13 16:48:21 | [diff] [blame] | 317 | |
| 318 | def ShowOobe(unused_args=0): |
| 319 | """Removes .oobe_completed and Local State directory.""" |
| 320 | res = True |
| 321 | res &= _RemoveFile("/home/chronos/.oobe_completed") |
| 322 | res &= ClearOwnership() |
| 323 | |
| 324 | if not res: |
| 325 | _PrintError("Errors encountered while clearing setting up OOBE mode.") |
| 326 | return False |
| 327 | return _RunCommand(["sudo", "reboot"]) |
| 328 | |
| 329 | |
Steven Bennetts | 62fd725 | 2011-11-03 20:56:09 | [diff] [blame] | 330 | ############################################################################### |
| 331 | # Setup Commands |
| 332 | |
| 333 | def SetBash(unused_args): |
| 334 | """Sets the default shell to bash.""" |
| 335 | if not _Sudo(): |
| 336 | return False |
| 337 | if not MountWriteable(): |
| 338 | return False |
| 339 | res = True |
| 340 | res &= _RunCommand(["chsh", "-s", "/bin/bash"]) |
| 341 | res &= _RunCommand(["chsh", "-s", "/bin/bash", "chronos"]) |
| 342 | return res |
| 343 | |
| 344 | |
| 345 | def SetupBashrc(unused_args): |
| 346 | """Sets up .bashrc.""" |
| 347 | filepath = os.path.expanduser("~/.bashrc") |
| 348 | if not _CheckOverwriteFile(filepath): |
Steven Bennetts | 26178d9 | 2011-11-22 18:54:41 | [diff] [blame] | 349 | return True |
Steven Bennetts | 62fd725 | 2011-11-03 20:56:09 | [diff] [blame] | 350 | |
| 351 | print "Writing to: ", filepath |
| 352 | bashrc = "#!/bin/bash\n" |
| 353 | bashrc += "# .bashrc file set by %s\n" % _PROG |
| 354 | bashrc += "export DISPLAY=:0.0\n" |
| 355 | bashrc += "export PATH=$PATH:/sbin:/usr/sbin:/usr/local/sbin\n" |
| 356 | bashrc += "/sbin/ifconfig eth0 | grep 'inet addr'\n" |
| 357 | if not _WriteFile(filepath, bashrc): |
| 358 | return False |
| 359 | |
| 360 | filepath = os.path.expanduser("~/.bash_profile") |
| 361 | print "Writing to: ", filepath |
| 362 | bashprofile = "#!/bin/bash\n" |
| 363 | bashprofile += ". $HOME/.bashrc\n" |
| 364 | if not _WriteFile(filepath, bashprofile): |
| 365 | return False |
| 366 | return True |
| 367 | |
| 368 | |
| 369 | def SetupDev(unused_args): |
Nirnimesh | 260e806 | 2012-07-13 22:47:08 | [diff] [blame] | 370 | """Developer friendly setup: skip oobe, disable suspend, |
| 371 | \t\tenable ssh and remote debugging, run commands from |
| 372 | \t\t/tmp,/home.""" |
Steven Bennetts | 62fd725 | 2011-11-03 20:56:09 | [diff] [blame] | 373 | if not _Sudo(): |
| 374 | return False |
| 375 | if not MountWriteable(): |
| 376 | return False |
| 377 | res = True |
Steven Bennetts | 26178d9 | 2011-11-22 18:54:41 | [diff] [blame] | 378 | res &= _WriteFile("/home/chronos/.oobe_completed", "1\n") |
Steven Bennetts | 62fd725 | 2011-11-03 20:56:09 | [diff] [blame] | 379 | res &= _MakeDirectory("/usr/share/power_manager") |
Steven Bennetts | 26178d9 | 2011-11-22 18:54:41 | [diff] [blame] | 380 | res &= _WriteFile("/tmp/disable_idle_suspend", "1\n") |
| 381 | res &= _RunCommand(["sudo", "cp", "/tmp/disable_idle_suspend", |
| 382 | "/usr/share/power_manager/"]) |
Steven Bennetts | 62fd725 | 2011-11-03 20:56:09 | [diff] [blame] | 383 | # Enable iptables and system-services for remote debugging |
| 384 | for filename in ["iptables", "saft"]: |
| 385 | res &= _RunCommand(["sudo", "sed", "-i", "-e", |
| 386 | "s/#for_test //", "/etc/init/%s.conf" % filename]) |
| 387 | # Allow commands to be run from /home and /tmp |
| 388 | res &= _RunCommand(["sudo", "sed", "-i", "-e", |
| 389 | "s/#mod_for_test#//g", "/sbin/chromeos_startup"]) |
| 390 | return res |
| 391 | |
| 392 | |
| 393 | def SetupSsh(unused_args): |
| 394 | """Sets up ssh configuration so that the dev host can ssh to the device.""" |
| 395 | if not MountWriteable(): |
| 396 | return False |
| 397 | |
| 398 | user = _DevUser() |
| 399 | host = _DevHost() |
| 400 | |
Steven Bennetts | 62fd725 | 2011-11-03 20:56:09 | [diff] [blame] | 401 | res = True |
Steven Bennetts | 26178d9 | 2011-11-22 18:54:41 | [diff] [blame] | 402 | if _CheckOverwriteFile(_SSH_KEY_FILEPATH): |
| 403 | res &= _RemoveFile(_SSH_KEY_FILEPATH) |
| 404 | # Generate an ssh key |
| 405 | if _RunCommand(["ssh-keygen", "-f", _SSH_KEY_FILEPATH, "-N", "", "-q"]): |
| 406 | host_source_path = "%s@%s:%s" % (user, host, _PUB_KEY_FILENAME) |
| 407 | # Copy the ssh key to the host |
| 408 | res &= _RunCommand(["scp", host_source_path, _AUTH_KEYS_FILEPATH]) |
| 409 | |
Steven Bennetts | 62fd725 | 2011-11-03 20:56:09 | [diff] [blame] | 410 | # Enable ssh to device |
| 411 | res &= _RunCommand( |
| 412 | ["sudo", "sed", "-i", "s/#for_test //", "/etc/init/openssh-server.conf"]) |
Steven Bennetts | 62fd725 | 2011-11-03 20:56:09 | [diff] [blame] | 413 | |
| 414 | return res |
| 415 | |
| 416 | |
| 417 | def AuthorizeSsh(unused_args): |
| 418 | """Authorizes this netbook to connect to your dev host. |
| 419 | \t\t*Only use this on a device in a secure location!*""" |
| 420 | |
| 421 | user = _DevUser() |
| 422 | host = _DevHost() |
| 423 | |
Steven Bennetts | 26178d9 | 2011-11-22 18:54:41 | [diff] [blame] | 424 | if not os.path.isdir(os.path.expanduser("~/.ssh")): |
| 425 | print "Run '%s ssh' to set up .ssh directory first." % _PROG |
| 426 | return False |
| 427 | |
| 428 | if not _Confirm("This will append %s to authorized_keys on %s. " |
| 429 | "Are you sure?" % (_PUB_KEY_FILENAME, host)): |
Steven Bennetts | 62fd725 | 2011-11-03 20:56:09 | [diff] [blame] | 430 | return False |
| 431 | |
| 432 | proc1 = subprocess.Popen(["cat", _PUB_KEY_FILEPATH], stdout=subprocess.PIPE) |
| 433 | try: |
| 434 | ssh_args = ["ssh", user+"@"+host, "cat >> ~/.ssh/authorized_keys"] |
| 435 | proc2 = subprocess.Popen( |
| 436 | ssh_args, stdin=proc1.stdout, stdout=subprocess.PIPE) |
Steven Bennetts | 26178d9 | 2011-11-22 18:54:41 | [diff] [blame] | 437 | except EnvironmentError as err1: |
| 438 | _PrintError("Error executing '%s'" % ' '.join(ssh_args), err1) |
Steven Bennetts | 62fd725 | 2011-11-03 20:56:09 | [diff] [blame] | 439 | return False |
| 440 | try: |
| 441 | proc1.stdout.close() |
Steven Bennetts | 26178d9 | 2011-11-22 18:54:41 | [diff] [blame] | 442 | result, err2 = proc2.communicate() |
Steven Bennetts | 62fd725 | 2011-11-03 20:56:09 | [diff] [blame] | 443 | except EnvironmentError: |
Steven Bennetts | 26178d9 | 2011-11-22 18:54:41 | [diff] [blame] | 444 | _PrintError("Error completing ssh command '%s'" % result, err2) |
Steven Bennetts | 62fd725 | 2011-11-03 20:56:09 | [diff] [blame] | 445 | return False |
| 446 | return True |
| 447 | |
| 448 | |
| 449 | def SetupSshfsForChrome(unused_args): |
| 450 | """<chrome-drir> Sets up sshfs mount to chrome directory on host.""" |
| 451 | |
| 452 | user = _DevUser() |
| 453 | host = _DevHost() |
| 454 | |
Steven Bennetts | 26178d9 | 2011-11-22 18:54:41 | [diff] [blame] | 455 | chrootdir = _GetChrootDir(True) |
Steven Bennetts | 62fd725 | 2011-11-03 20:56:09 | [diff] [blame] | 456 | |
Steven Bennetts | 26178d9 | 2011-11-22 18:54:41 | [diff] [blame] | 457 | target = ("%s@%s:%s/var/lib/portage/distfiles-target/chrome-src" |
| 458 | % (user, host, chrootdir)) |
Steven Bennetts | 62fd725 | 2011-11-03 20:56:09 | [diff] [blame] | 459 | print "Setting up sshfs mount to: ", target |
| 460 | |
| 461 | res = True |
| 462 | res &= _RunCommand(["sudo", "modprobe", "fuse"]) |
| 463 | if os.path.isdir(_CHROME_MOUNT_PATH): |
Steven Bennetts | 26178d9 | 2011-11-22 18:54:41 | [diff] [blame] | 464 | res &= _RunCommand(["fusermount", "-q", "-u", _CHROME_MOUNT_PATH]) |
Steven Bennetts | 62fd725 | 2011-11-03 20:56:09 | [diff] [blame] | 465 | res &= _RemoveDirectory(_CHROME_MOUNT_PATH) |
| 466 | res &= _MakeDirectory(_CHROME_MOUNT_PATH) |
| 467 | res &= _RunCommand(["sshfs", target, _CHROME_MOUNT_PATH]) |
| 468 | res &= _RunCommand(["sudo", "/sbin/iptables", |
| 469 | "-A", "INPUT", "-p", "tcp", "--dport", "1234", |
| 470 | "-j", "ACCEPT"]) |
| 471 | return res |
| 472 | |
| 473 | ############################################################################### |
| 474 | # Multi-commands (convenience functions) |
| 475 | |
| 476 | def Setup(args): |
| 477 | """Performs default developer setup (bash,bashrc,dev,ssh).""" |
| 478 | if not SetBash(args): |
Steven Bennetts | 26178d9 | 2011-11-22 18:54:41 | [diff] [blame] | 479 | if not _Confirm("Bash setup failed. Continue?", "y"): |
Steven Bennetts | 62fd725 | 2011-11-03 20:56:09 | [diff] [blame] | 480 | return False |
| 481 | if not SetupBashrc(args): |
Steven Bennetts | 26178d9 | 2011-11-22 18:54:41 | [diff] [blame] | 482 | if not _Confirm(".bashrc setup failed. Continue?", "y"): |
Steven Bennetts | 62fd725 | 2011-11-03 20:56:09 | [diff] [blame] | 483 | return False |
| 484 | if not SetupDev(args): |
Steven Bennetts | 26178d9 | 2011-11-22 18:54:41 | [diff] [blame] | 485 | if not _Confirm("Dev setup failed. Continue?", "y"): |
Steven Bennetts | 62fd725 | 2011-11-03 20:56:09 | [diff] [blame] | 486 | return False |
| 487 | if not SetupSsh(args): |
| 488 | return False |
| 489 | return True |
| 490 | |
| 491 | ############################################################################### |
| 492 | |
| 493 | _SETUP_COMMANDS = { |
| 494 | 'setup': Setup, |
| 495 | 'dev': SetupDev, |
| 496 | 'bash': SetBash, |
| 497 | 'bashrc': SetupBashrc, |
| 498 | 'ssh': SetupSsh, |
| 499 | 'sshauthorize': AuthorizeSsh, |
| 500 | 'sshfs': SetupSshfsForChrome, |
| 501 | } |
| 502 | |
| 503 | |
| 504 | _OTHER_COMMANDS = { |
| 505 | 'mountrw': MountWriteable, |
| 506 | 'ip': ShowIP, |
| 507 | 'test': TestCommand, |
Steven Bennetts | 26178d9 | 2011-11-22 18:54:41 | [diff] [blame] | 508 | 'board': GetBoard, |
Steven Bennetts | 62fd725 | 2011-11-03 20:56:09 | [diff] [blame] | 509 | 'user': GetUser, |
| 510 | 'host': GetHost, |
| 511 | } |
| 512 | |
| 513 | |
Chris Masone | 32ee201 | 2011-12-13 16:48:21 | [diff] [blame] | 514 | _CLEANUP_COMMANDS = { |
| 515 | 'show_oobe': ShowOobe, |
| 516 | 'clear_owner': ClearOwnership, |
| 517 | } |
| 518 | |
| 519 | |
Steven Bennetts | 62fd725 | 2011-11-03 20:56:09 | [diff] [blame] | 520 | def GetUsage(commands): |
| 521 | """Get the docstring for each command.""" |
| 522 | usage = "" |
| 523 | for cmd in commands.items(): |
| 524 | usage += " " |
| 525 | usage += cmd[0] |
| 526 | usage += ":\t" |
| 527 | if len(cmd[0]) < 6: |
| 528 | usage += "\t" |
| 529 | doc = cmd[1].__doc__ |
| 530 | if doc: |
| 531 | usage += doc |
| 532 | usage += "\n" |
| 533 | return usage |
| 534 | |
| 535 | |
| 536 | ############################################################################### |
| 537 | |
| 538 | def main(): |
| 539 | """Main crdev function""" |
| 540 | usage = """usage: crdev command [options] |
| 541 | |
Steven Bennetts | 26178d9 | 2011-11-22 18:54:41 | [diff] [blame] | 542 | Note: Beta! Feature requests / changes can be sent to: |
| 543 | [email protected] (for now) |
Steven Bennetts | 62fd725 | 2011-11-03 20:56:09 | [diff] [blame] | 544 | |
| 545 | """ |
| 546 | |
| 547 | usage += "Setup Commands:\n" |
| 548 | usage += GetUsage(_SETUP_COMMANDS) |
| 549 | usage += "Other Commands:\n" |
| 550 | usage += GetUsage(_OTHER_COMMANDS) |
Chris Masone | 32ee201 | 2011-12-13 16:48:21 | [diff] [blame] | 551 | usage += "Cleanup Commands:\n" |
| 552 | usage += GetUsage(_CLEANUP_COMMANDS) |
Steven Bennetts | 62fd725 | 2011-11-03 20:56:09 | [diff] [blame] | 553 | |
| 554 | parser = optparse.OptionParser(usage) |
| 555 | args = parser.parse_args()[1] |
| 556 | |
| 557 | if not args: |
| 558 | print usage |
| 559 | return |
| 560 | |
Steven Bennetts | 62fd725 | 2011-11-03 20:56:09 | [diff] [blame] | 561 | cmd = args[0] |
Chris Masone | 32ee201 | 2011-12-13 16:48:21 | [diff] [blame] | 562 | root_ok = cmd in _CLEANUP_COMMANDS.keys() |
| 563 | if not root_ok or os.geteuid() != 0: |
| 564 | if os.getenv('USER') != 'chronos': |
| 565 | _PrintError("%s must be run as chronos." % _PROG) |
| 566 | return |
| 567 | |
Steven Bennetts | 62fd725 | 2011-11-03 20:56:09 | [diff] [blame] | 568 | if cmd in _SETUP_COMMANDS.keys(): |
| 569 | res = _SETUP_COMMANDS[cmd](args[1:]) |
| 570 | elif cmd in _OTHER_COMMANDS.keys(): |
| 571 | res = _OTHER_COMMANDS[cmd](args[1:]) |
Chris Masone | 32ee201 | 2011-12-13 16:48:21 | [diff] [blame] | 572 | elif cmd in _CLEANUP_COMMANDS.keys(): |
| 573 | if os.geteuid() != 0: |
| 574 | _DaemonizeAndReRunAsRoot(cmd) |
| 575 | _PrintError("Should never return from DaemonizeAndReRunAsRoot()") |
| 576 | return |
| 577 | res = _CLEANUP_COMMANDS[cmd](args[1:]) |
Steven Bennetts | 62fd725 | 2011-11-03 20:56:09 | [diff] [blame] | 578 | else: |
| 579 | parser.error("Unknown command: " + cmd) |
| 580 | return |
| 581 | |
| 582 | if not res: |
Steven Bennetts | 26178d9 | 2011-11-22 18:54:41 | [diff] [blame] | 583 | _PrintError("Errors encountered when running '%s'" % ' '.join(args)) |
Steven Bennetts | 62fd725 | 2011-11-03 20:56:09 | [diff] [blame] | 584 | else: |
| 585 | print "Success!" |
| 586 | |
| 587 | |
| 588 | if __name__ == '__main__': |
| 589 | main() |