2015-12-26 01:09:45 +01:00
#!/usr/bin/env python
2015-12-26 14:52:04 +01:00
#
# Dump partitions to file.
#
# Copyright (C) 2015 Peter Wu <peter@lekensteyn.nl>
# Licensed under the MIT license <http://opensource.org/licenses/MIT>.
2015-12-26 23:18:35 +01:00
from contextlib import closing
2015-12-26 01:09:45 +01:00
import argparse , logging , os , struct
2015-12-26 23:18:35 +01:00
import lglaf , partitions
2015-12-26 01:09:45 +01:00
2015-12-26 23:18:35 +01:00
_logger = logging . getLogger ( " extract-partitions " )
2015-12-26 01:09:45 +01:00
parser = argparse . ArgumentParser ( )
parser . add_argument ( " -d " , " --outdir " , default = " . " ,
help = " Output directory for disk images. " )
2015-12-26 14:52:04 +01:00
# Do not dump partitions larger than this size
2015-12-26 01:09:45 +01:00
# (userdata 11728 MiB, system 2064 MiB, cache 608 MiB, cust 256 MiB)
2015-12-27 16:37:56 +01:00
parser . add_argument ( " --max-size " , metavar = " kbytes " , type = int , default = 65535 ,
help = " Maximum partition size to dump (in KiB) or 0 to dump all (default %(default)d ) " )
2015-12-26 01:09:45 +01:00
parser . add_argument ( " --debug " , action = ' store_true ' , help = " Enable debug messages " )
2017-10-05 17:19:27 +02:00
parser . add_argument ( " --skip-hello " , action = " store_true " ,
help = " Immediately send commands, skip HELO message " )
2015-12-26 01:09:45 +01:00
2015-12-26 23:18:35 +01:00
def dump_partitions ( comm , disk_fd , outdir , max_size ) :
2017-11-25 23:49:17 +01:00
diskinfo = partitions . get_partitions ( comm , disk_fd )
for part in diskinfo . gpt . partitions :
part_offset = part . first_bla * partitions . BLOCK_SIZE
part_size = ( part . last_lba - part . first_bla ) * partitions . BLOCK_SIZE
part_name = part . name
part_label = " /dev/mmcblk0p %i " % part . index
2015-12-27 16:37:56 +01:00
if max_size and part_size > max_size :
2015-12-27 11:21:32 +01:00
_logger . info ( " Ignoring large partition %s ( %s ) of size %d K " ,
part_label , part_name , part_size / 1024 )
2015-12-26 01:09:45 +01:00
continue
2015-12-27 11:21:32 +01:00
out_path = os . path . join ( outdir , " %s .bin " % part_name )
2015-12-26 23:18:35 +01:00
try :
current_size = os . path . getsize ( out_path )
if current_size > part_size :
_logger . warn ( " %s : unexpected size %d K, larger than %d K " ,
out_path , current_size / 1024 , part_size / 1024 )
continue
elif current_size == part_size :
2015-12-27 11:21:32 +01:00
_logger . info ( " Skipping partition %s ( %s ), already found at %s " ,
part_label , part_name , out_path )
2015-12-26 23:18:35 +01:00
continue
except OSError : pass
2015-12-27 11:21:32 +01:00
_logger . info ( " Dumping partition %s ( %s ) to %s ( %d bytes) " ,
part_label , part_name , out_path , part_size )
2015-12-26 23:18:35 +01:00
partitions . dump_partition ( comm , disk_fd , out_path , part_offset , part_size )
2015-12-26 01:09:45 +01:00
def main ( ) :
args = parser . parse_args ( )
logging . basicConfig ( format = ' %(asctime)s %(name)s : %(levelname)s : %(message)s ' ,
level = logging . DEBUG if args . debug else logging . INFO )
try : os . makedirs ( args . outdir )
except OSError : pass
comm = lglaf . autodetect_device ( )
with closing ( comm ) :
2017-10-05 17:19:27 +02:00
if not args . skip_hello :
lglaf . try_hello ( comm )
2015-12-26 23:18:35 +01:00
with partitions . laf_open_disk ( comm ) as disk_fd :
_logger . debug ( " Opened fd %d for disk " , disk_fd )
dump_partitions ( comm , disk_fd , args . outdir , args . max_size * 1024 )
2015-12-26 01:09:45 +01:00
if __name__ == ' __main__ ' :
main ( )