| OLD | NEW |
| 1 #!/bin/sh | 1 #!/bin/sh |
| 2 # | 2 # |
| 3 # Copyright (c) 2010 The Chromium OS Authors. All rights reserved. | 3 # Copyright (c) 2010 The Chromium OS Authors. All rights reserved. |
| 4 # Use of this source code is governed by a BSD-style license that can be | 4 # Use of this source code is governed by a BSD-style license that can be |
| 5 # found in the LICENSE file. | 5 # found in the LICENSE file. |
| 6 # | 6 # |
| 7 # This attempts to guide linux users through the process of putting a recovery | 7 # This attempts to guide linux users through the process of putting a recovery |
| 8 # image onto a removeable USB drive. | 8 # image onto a removeable USB drive. |
| 9 # | 9 # |
| 10 # We may not need root privileges if we have the right permissions. | 10 # We may not need root privileges if we have the right permissions. |
| (...skipping 10 matching lines...) Expand all Loading... |
| 21 | 21 |
| 22 # Where do we look for the config file? Note that we can override this by just | 22 # Where do we look for the config file? Note that we can override this by just |
| 23 # specifying the config file URL on the command line. | 23 # specifying the config file URL on the command line. |
| 24 CONFIGURL="${1:-https://dl.google.com/dl/edgedl/chromeos/recovery/recovery.conf}
" | 24 CONFIGURL="${1:-https://dl.google.com/dl/edgedl/chromeos/recovery/recovery.conf}
" |
| 25 | 25 |
| 26 # Device to put this stuff on, perhaps the user knows best? | 26 # Device to put this stuff on, perhaps the user knows best? |
| 27 DEVICE="${DEVICE:-}" | 27 DEVICE="${DEVICE:-}" |
| 28 | 28 |
| 29 # What version is this script? It must match the 'recovery_tool_version=' value | 29 # What version is this script? It must match the 'recovery_tool_version=' value |
| 30 # in the config file that we'll download. | 30 # in the config file that we'll download. |
| 31 MYVERSION='0.9.1' | 31 MYVERSION='0.9.2' |
| 32 | 32 |
| 33 | 33 |
| 34 ############################################################################## | 34 ############################################################################## |
| 35 # Some temporary filenames | 35 # Some temporary filenames |
| 36 debug='debug.log' | 36 debug='debug.log' |
| 37 tmpfile='tmp.txt' | 37 tmpfile='tmp.txt' |
| 38 config='config.txt' | 38 config='config.txt' |
| 39 version='version.txt' | 39 version='version.txt' |
| 40 | 40 |
| 41 ############################################################################## | 41 ############################################################################## |
| (...skipping 59 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 101 # | 101 # |
| 102 # This also sets the following global variables to select alternative utilities | 102 # This also sets the following global variables to select alternative utilities |
| 103 # when there is more than one equivalent tool available: | 103 # when there is more than one equivalent tool available: |
| 104 # | 104 # |
| 105 # FETCH = name of utility used to download files from the web | 105 # FETCH = name of utility used to download files from the web |
| 106 # CHECK = command to invoke to generate checksums on a file | 106 # CHECK = command to invoke to generate checksums on a file |
| 107 # CHECKTYPE = type of checksum generated | 107 # CHECKTYPE = type of checksum generated |
| 108 # DISKUTIL = set if we have 'diskutil' (for Macs) | 108 # DISKUTIL = set if we have 'diskutil' (for Macs) |
| 109 # | 109 # |
| 110 require_utils() { | 110 require_utils() { |
| 111 local external | 111 local extern |
| 112 local errors | 112 local errors |
| 113 local tool | 113 local tool |
| 114 local tmp | 114 local tmp |
| 115 | 115 |
| 116 external='cat cut dd grep ls mkdir mount readlink sed sync umount unzip wc' | 116 extern='awk cat cut dd grep ls mkdir mount readlink sed sync umount unzip wc' |
| 117 if [ -z "$WORKDIR" ]; then | 117 if [ -z "$WORKDIR" ]; then |
| 118 external="$external mktemp" | 118 extern="$extern mktemp" |
| 119 fi | 119 fi |
| 120 errors= | 120 errors= |
| 121 | 121 |
| 122 for tool in $external ; do | 122 for tool in $extern ; do |
| 123 if ! type "$tool" >/dev/null 2>&1 ; then | 123 if ! type "$tool" >/dev/null 2>&1 ; then |
| 124 warn "ERROR: need \"$tool\"" | 124 warn "ERROR: need \"$tool\"" |
| 125 errors=yes | 125 errors=yes |
| 126 fi | 126 fi |
| 127 done | 127 done |
| 128 | 128 |
| 129 # We also need to a way to fetch files from teh internets. Note that the args | 129 # We also need to a way to fetch files from teh internets. Note that the args |
| 130 # are different depending on which utility we find. We'll use two variants, | 130 # are different depending on which utility we find. We'll use two variants, |
| 131 # one to fetch fresh every time and one to try again from where we left off. | 131 # one to fetch fresh every time and one to try again from where we left off. |
| 132 FETCH= | 132 FETCH= |
| (...skipping 98 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 231 openssl md5 < "$filename" | 231 openssl md5 < "$filename" |
| 232 else | 232 else |
| 233 $CHECK "$zipfile" | cut -d' ' -f1 | 233 $CHECK "$zipfile" | cut -d' ' -f1 |
| 234 fi | 234 fi |
| 235 } | 235 } |
| 236 | 236 |
| 237 | 237 |
| 238 ############################################################################## | 238 ############################################################################## |
| 239 # Helper functions to handle the config file and image zipfile. | 239 # Helper functions to handle the config file and image zipfile. |
| 240 | 240 |
| 241 # Convert bytes to MB, rounding up to determine storage needed to hold bytes. |
| 242 roundup() { |
| 243 local num=$1 |
| 244 local div=$(( 1024 * 1024 )) |
| 245 local rem=$(( $num % $div )) |
| 246 |
| 247 if [ $rem -ne 0 ]; then |
| 248 num=$(($num + $div - $rem)) |
| 249 fi |
| 250 echo $(( $num / $div )) |
| 251 } |
| 252 |
| 253 |
| 254 # Die unless the filesystem containing the current directory has enough free |
| 255 # space. The argument is the number of MB required. |
| 256 verify_tmp_space() { |
| 257 local need |
| 258 local got |
| 259 need="$1" |
| 260 |
| 261 # The output of "df -m ." could take two forms: |
| 262 # |
| 263 # Filesystem 1M-blocks Used Available Use% Mounted on |
| 264 # /some/really/long/path/to/some/where |
| 265 # 37546 11118 24521 32% / |
| 266 # |
| 267 # Filesystem 1048576-blocks Used Available Capacity Mounted on |
| 268 # /some/short/path 37546 11118 24521 32% / |
| 269 # |
| 270 got=$(df -m . | awk '/^\/[^ ]+ +[0-9]/ {print $4} /^ +[0-9]/ {print $3}') |
| 271 |
| 272 if [ "$need" -gt "$got" ]; then |
| 273 fatal " There is not enough free space in ${WORKDIR}" \ |
| 274 "(it has ${got}MB, we need ${need}MB). |
| 275 |
| 276 Please free up some space on that filesystem, or specify a temporary directory |
| 277 on the commandline like so: |
| 278 |
| 279 WORKDIR=/path/to/some/dir $0 |
| 280 " |
| 281 fi |
| 282 } |
| 283 |
| 284 |
| 241 # Each paragraph in the config file should describe a new image. Let's make | 285 # Each paragraph in the config file should describe a new image. Let's make |
| 242 # sure it follows all the rules. This scans the config file and returns success | 286 # sure it follows all the rules. This scans the config file and returns success |
| 243 # if it looks valid. As a side-effect, it lists the line numbers of the start | 287 # if it looks valid. As a side-effect, it lists the line numbers of the start |
| 244 # and end of each stanza in the global variables 'start_lines' and 'end_lines' | 288 # and end of each stanza in the global variables 'start_lines' and 'end_lines' |
| 245 # and saves the total number of images in the global variable 'num_images'. | 289 # and saves the total number of images in the global variable 'num_images'. |
| 246 good_config() { | 290 good_config() { |
| 247 local line | 291 local line |
| 248 local key | 292 local key |
| 249 local val | 293 local val |
| 250 local name | 294 local name |
| (...skipping 195 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 446 fi | 490 fi |
| 447 done | 491 done |
| 448 echo | 492 echo |
| 449 | 493 |
| 450 # global | 494 # global |
| 451 user_choice="$num" | 495 user_choice="$num" |
| 452 } | 496 } |
| 453 | 497 |
| 454 # Fetch and verify the user's chosen image. On success, it sets the global | 498 # Fetch and verify the user's chosen image. On success, it sets the global |
| 455 # variable 'image_file' to indicate the local name of the unpacked binary that | 499 # variable 'image_file' to indicate the local name of the unpacked binary that |
| 456 # should be written to the USB drive. | 500 # should be written to the USB drive. It also sets the global variable |
| 501 # 'disk_needed' to the minimum capacity of the USB drive required (in MB). |
| 457 fetch_image() { | 502 fetch_image() { |
| 458 local start | 503 local start |
| 459 local end | 504 local end |
| 460 local line | 505 local line |
| 461 local key | 506 local key |
| 462 local val | 507 local val |
| 463 local file | 508 local file |
| 464 local zipfilesize | 509 local zipfilesize |
| 465 local filesize | 510 local filesize |
| 466 local url | 511 local url |
| (...skipping 43 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 510 filesize) | 555 filesize) |
| 511 filesize="$val" | 556 filesize="$val" |
| 512 ;; | 557 ;; |
| 513 md5) | 558 md5) |
| 514 md5="$val" | 559 md5="$val" |
| 515 ;; | 560 ;; |
| 516 sha1) | 561 sha1) |
| 517 sha1="$val" | 562 sha1="$val" |
| 518 ;; | 563 ;; |
| 519 url) | 564 url) |
| 565 # Make sure we have enough temp space available. Die if we don't. |
| 566 verify_tmp_space $(roundup $(( $zipfilesize + $filesize ))) |
| 520 # Try to download each url until one works. | 567 # Try to download each url until one works. |
| 521 if [ -n "$url" ]; then | 568 if [ -n "$url" ]; then |
| 522 # We've already got one (it's very nice). | 569 # We've already got one (it's very nice). |
| 523 continue; | 570 continue; |
| 524 fi | 571 fi |
| 525 warn "Downloading image zipfile from $val" | 572 warn "Downloading image zipfile from $val" |
| 526 warn "" | 573 warn "" |
| 527 zipfile=${val##*/} | 574 zipfile=${val##*/} |
| 528 if fetch_url "$val" "$zipfile" "resumeok"; then | 575 if fetch_url "$val" "$zipfile" "resumeok"; then |
| 529 # Got it. | 576 # Got it. |
| (...skipping 32 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 562 return 1 | 609 return 1 |
| 563 fi | 610 fi |
| 564 | 611 |
| 565 if ! ls -l "$file" | grep -q "$filesize"; then | 612 if ! ls -l "$file" | grep -q "$filesize"; then |
| 566 DEBUG "unpacked filesize is wrong" | 613 DEBUG "unpacked filesize is wrong" |
| 567 return 1 | 614 return 1 |
| 568 fi | 615 fi |
| 569 | 616 |
| 570 # global | 617 # global |
| 571 image_file="$file" | 618 image_file="$file" |
| 619 disk_needed=$(roundup "$filesize") |
| 572 } | 620 } |
| 573 | 621 |
| 574 ############################################################################## | 622 ############################################################################## |
| 575 # Helper functions to manage USB drives. | 623 # Helper functions to manage USB drives. |
| 576 | 624 |
| 577 # Return a list of base device names ("sda sdb ...") for all USB drives | 625 # Return a list of base device names ("sda sdb ...") for all USB drives |
| 578 get_devlist() { | 626 get_devlist() { |
| 579 local dev | 627 local dev |
| 580 local t | 628 local t |
| 581 local r | 629 local r |
| (...skipping 16 matching lines...) Expand all Loading... |
| 598 t=$(cat "/sys/block/$dev/device/type") && | 646 t=$(cat "/sys/block/$dev/device/type") && |
| 599 [ "$t" = "0" ] && | 647 [ "$t" = "0" ] && |
| 600 r=$(cat "/sys/block/$dev/removable") && | 648 r=$(cat "/sys/block/$dev/removable") && |
| 601 [ "$r" = "1" ] && | 649 [ "$r" = "1" ] && |
| 602 readlink -f "/sys/block/$dev" | grep -q -i usb && | 650 readlink -f "/sys/block/$dev" | grep -q -i usb && |
| 603 echo "$dev" || true | 651 echo "$dev" || true |
| 604 done | 652 done |
| 605 fi | 653 fi |
| 606 } | 654 } |
| 607 | 655 |
| 656 # Return the raw size in MB of each provided base device name ("sda sdb ...") |
| 657 get_devsize() { |
| 658 local dev |
| 659 local bytes |
| 660 local sectors |
| 661 |
| 662 # Are we on a mac? |
| 663 if [ -n "$DISKUTIL" ]; then |
| 664 for dev in $1; do |
| 665 bytes=$(diskutil info $dev | \ |
| 666 awk '/\([0-9]+ Bytes\)/' | sed -E 's/.*\(([0-9]+) Bytes\).*/\1/') |
| 667 echo $(( $bytes / 1024 / 1024)) |
| 668 done |
| 669 else |
| 670 for dev in $1; do |
| 671 sectors=$(cat "/sys/block/$dev/size") |
| 672 echo $(( $sectors * 512 / 1024 / 1024 )) |
| 673 done |
| 674 fi |
| 675 } |
| 676 |
| 677 |
| 608 # Return descriptions for each provided base device name ("sda sdb ...") | 678 # Return descriptions for each provided base device name ("sda sdb ...") |
| 609 get_devinfo() { | 679 get_devinfo() { |
| 610 local dev | 680 local dev |
| 611 local v | 681 local v |
| 612 local m | 682 local m |
| 613 local s | 683 local s |
| 614 local ss | 684 local ss |
| 615 | 685 |
| 616 # Are we on a mac? | 686 # Are we on a mac? |
| 617 if [ -n "$DISKUTIL" ]; then | 687 if [ -n "$DISKUTIL" ]; then |
| (...skipping 45 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 663 while true; do | 733 while true; do |
| 664 if [ -n "$show" ]; then | 734 if [ -n "$show" ]; then |
| 665 devlist=$(get_devlist) | 735 devlist=$(get_devlist) |
| 666 choices=$(get_choices "$devlist") | 736 choices=$(get_choices "$devlist") |
| 667 if [ -z "$devlist" ]; then | 737 if [ -z "$devlist" ]; then |
| 668 num_drives="0" | 738 num_drives="0" |
| 669 msg="I can't seem to find a valid USB drive." | 739 msg="I can't seem to find a valid USB drive." |
| 670 else | 740 else |
| 671 num_drives=$(echo "$devlist" | wc -l) | 741 num_drives=$(echo "$devlist" | wc -l) |
| 672 if [ "$num_drives" != "1" ]; then | 742 if [ "$num_drives" != "1" ]; then |
| 673 msg="I found $num_drives USB drives" | 743 msg="I found $num_drives USB drives." |
| 674 else | 744 else |
| 675 msg="I found $num_drives USB drive" | 745 msg="I found $num_drives USB drive." |
| 676 fi | 746 fi |
| 677 fi | 747 fi |
| 678 echo " | 748 echo " |
| 679 | 749 |
| 680 $msg | 750 $msg We need one with at least ${disk_needed}MB capacity. |
| 681 | 751 |
| 682 $choices | 752 $choices |
| 753 |
| 683 " | 754 " |
| 684 show= | 755 show= |
| 685 fi | 756 fi |
| 686 prompt "Tell me what to do (or just press Enter to scan again): " | 757 prompt "Tell me what to do (or just press Enter to scan again): " |
| 687 read num | 758 read num |
| 688 if [ -z "$num" ] || [ "$num" = "?" ]; then | 759 if [ -z "$num" ] || [ "$num" = "?" ]; then |
| 689 show=yes | 760 show=yes |
| 690 elif echo "$num" | grep -q '[^0-9]'; then | 761 elif echo "$num" | grep -q '[^0-9]'; then |
| 691 echo "Sorry, I didn't understand that." | 762 echo "Sorry, I didn't understand that." |
| 692 else | 763 else |
| (...skipping 83 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 776 if [ -n "$DEVICE" ]; then | 847 if [ -n "$DEVICE" ]; then |
| 777 user_choice="${DEVICE#/dev/}" | 848 user_choice="${DEVICE#/dev/}" |
| 778 dev_desc="${DEVICE}" | 849 dev_desc="${DEVICE}" |
| 779 else | 850 else |
| 780 # Make the user pick a USB drive, or exit. | 851 # Make the user pick a USB drive, or exit. |
| 781 choose_drive | 852 choose_drive |
| 782 | 853 |
| 783 # Be sure | 854 # Be sure |
| 784 dev_desc=$(get_devinfo "$user_choice") | 855 dev_desc=$(get_devinfo "$user_choice") |
| 785 fi | 856 fi |
| 857 |
| 858 # Start asking for confirmation |
| 859 dev_size=$(get_devsize "$user_choice") |
| 860 if [ "$dev_size" -lt "$disk_needed" ]; then |
| 861 echo " |
| 862 |
| 863 WARNING: This drive seems too small (${dev_size}MB)." \ |
| 864 "The recovery image is ${disk_needed}MB." |
| 865 fi |
| 786 echo " | 866 echo " |
| 787 Is this the device you want to put the recovery image on? | 867 Is this the device you want to put the recovery image on? |
| 788 | 868 |
| 789 $dev_desc | 869 $dev_desc |
| 790 " | 870 " |
| 791 prompt "You must enter 'YES' (all uppercase) to continue: " | 871 prompt "You must enter 'YES' (all uppercase) to continue: " |
| 792 read tmp | 872 read tmp |
| 793 if [ "$tmp" != "YES" ]; then | 873 if [ "$tmp" != "YES" ]; then |
| 794 quit | 874 quit |
| 795 fi | 875 fi |
| (...skipping 45 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 841 prompt "Shall I remove the temporary files now? [y/n] " | 921 prompt "Shall I remove the temporary files now? [y/n] " |
| 842 read tmp | 922 read tmp |
| 843 case $tmp in | 923 case $tmp in |
| 844 [Yy]*) | 924 [Yy]*) |
| 845 cd | 925 cd |
| 846 \rm -rf ${WORKDIR} | 926 \rm -rf ${WORKDIR} |
| 847 ;; | 927 ;; |
| 848 esac | 928 esac |
| 849 | 929 |
| 850 exit 0 | 930 exit 0 |
| OLD | NEW |