4

Using the fdisk -l command I got the following answer:

   Device Boot      Start         End      Blocks   Id  System
/dev/sda1   *        2048    28266495    14132224   27  Hidden NTFS WinRE
/dev/sda2        28268544    28473343      102400    7  HPFS/NTFS/exFAT
/dev/sda3        28473344   132552703    52039680    7  HPFS/NTFS/exFAT
/dev/sda4   *   132556798   625141759   246292481    5  Extended
/dev/sda5       193996800   198092799     2048000   82  Linux swap / Solaris
/dev/sda6       234960896   625141759   195090432    7  HPFS/NTFS/exFAT
/dev/sda7       198094848   234950316    18427734+  83  Linux
/dev/sda8       132556800   183756018    25599609+  83  Linux

I'd like to copy the three first partitions of my disk in an image using the dd command. So I mounted an external hard drive, entered in its folder and typed:

# dd count=$((132552703-2048)) if=/dev/sda of=./newImage.image

But this command copied all the sda disk to my external hard drive instead of just copying until the end of the sda3 partition.

How can I use the dd to create an image that starts at the beginning of sda1 and finishes at the end of sda3?

4 Answers4

7

first of all, here's how:


  1. First do almost as you did before, but no subtraction - and add one to the count.

    dd  count=132552704 </dev/sda >img
    
  2. Next print the partition table at a sed process which can screen out the ones which you're removing.

    • sed will write a delete command to a second fdisk which has opened your img file for every partition from sda4 and on.

      fdisk -l img | sed -e'/sda4 /,$id' -e'g;$aw' | fdisk img
      
  3. There is no 3. You're done.


secondly, here's why:


  • A Partial Success...

    • I'm pretty sure your command almost worked, but I'm willing to bet that it worked better than you think.

    • I expect that when you say it copied all of sda you believe that because an fdisk -l of that image indicated all of the partitions were included within. Based on the dd command in your question, though, provided /dev/sda's sector size is the fairly standard 512 bytes (and therefore identical to dd's default blocksize) then you should have copied everything from byte 0 of /dev/sda only through to all but the last 2k sectors of /dev/sda3.

  • About Sectors...

    • You can see below where the fdisk output reports on Units. That is the size of each sector that fdisk reports on. A disk sector might be 4096-bytes - if it is a very recently manufactured disk and handles the Advanced Format sector-size - otherwise it is very rare to find a disk not partitioned on a standard logical 512-byte sector-size.

    • This is how fdisk's man page puts it:

    • -u, --units[=unit]

      • When listing partition tables, show sizes in sectors or in cylinders. The default is to show sizes in sectors. For backward compatibility, it is possible to use the option without the unit argument - then the default is used. Note that the optional unit argument cannot be separated from the -u option by a space, the correct form is for example -u=cylinders.
    • There's more on this here.

  • And something about dd, too...

    • dd cannot silently lose data. In fact, if a short read occurs, dd is specified to be very vocal about it:

    • A partial input block is one for which read() returned less than the input block size. A partial output block is one that was written with fewer bytes than specified by the output block size...

    • ...when there is at least one truncated block, the number of truncated blocks shall be written to standard error...

    • "%u truncated %s\n", <number of truncated blocks>, "record[s]"

  • Block i/o...

    • But anyway, that actually can't happen with block-device i/o. It's what makes a block-device a block-device - there's an extra layer (sometimes several) of buffered protection for block-devices as opposed to character devices. It is this distinction which enables POSIX to guarantee lseek() for files existing on block-devices - it's a very basic principle of blocked i/o.
  • To sum up...

    • And so you have copied all of your device up to the point you specified, but the thing is, the first 2k sectors of /dev/sda will contain its entire partition table, and as such you would have copied said partition table to your image, and so an fdisk -l of your image would report for all partitions of /dev/sda, whether or not the data for those partitions actually resides within that image-file. You can, instead, of course, just cat the separate data partitions separately into separate image files if you like - but in that case you lose the partition table entirely. All you really have to do is delete the partitions which you did not copy, and make sure you copy all of those you do.

third, here's how I know:


  • This will create an 4G ./img file full of NULs.

    </dev/zero >./img \
    dd ibs=8k obs=8kx1b count=1kx1b 
    

    524288+0 records in
    1024+0 records out
    4294967296 bytes (4.3 GB) copied, 3.53287 s, 1.2 GB/s
    
  • This will partition ./img to match your disk up to the first three partitions but on a 1/16th scale:

    (set "$((p=0))" 28266495     27 \
          28268544  28473343  2\\n7 \
          28473344 132552703  3\\n7
    while   [ "$#" -ge "$((p+=1))" ]
    do      printf "n\np\n$p\n%.0d\n%d\nt\n%b\n" \
                   "$(($1/16))" "$(($2/16))" "$3"
            shift 3
    done;   echo w
    )| fdisk ./img >/dev/null
    
  • And so now we can look at it.

    fdisk -l ./img
    

    Disk ./img: 4 GiB, 4294967296 bytes, 8388608 sectors
    Units: sectors of 1 * 512 = 512 bytes
    Sector size (logical/physical): 512 bytes / 512 bytes
    I/O size (minimum/optimal): 512 bytes / 512 bytes
    Disklabel type: dos
    Disk identifier: 0x5659b81c
    
    Device     Boot   Start     End Sectors   Size Id Type
    ./img1             2048 1766655 1764608 861.6M 27 Hidden NTFS WinRE
    ./img2          1766784 1779583   12800   6.3M  7 HPFS/NTFS/exFAT
    ./img3          1779584 8284543 6504960   3.1G  7 HPFS/NTFS/exFAT
    
  • I'll also put some actual filesystems and files on the three partitions.

    sudo sh -c ' trap "$1" 0
        cd /tmp; mkdir -p mnt
        for p in "$(losetup --show -Pf "$0")p"*
        do    mkfs.vfat "$p"
              mount "$p" mnt
              echo  "my part# is ${p##*p}" \
                     >./mnt/"part${p##*p}"
              sync; umount mnt
        done' "$PWD/img" 'losetup -D'
    
  • Here are the byte offsets for where it all wound up...

    grep -Ebao '(my[^0-9]*|PART)[123]' <./img
    

    2826272:PART1
    2830336:my part# is 1
    904606240:PART2
    904624640:my part# is 2
    917656608:PART3
    917660672:my part# is 3
    

But did you notice that fdisk was perfectly happy to report on the partitions' sizes before ever we formatted them with filesystems? This is because the partition table lies at the very head of the disk - it's only a layout and nothing more. None of the partitions need actually exist to be reported. They're only logically mapped out within the first 1M of ./img. Watch:

  • Let's try getting only the first two partitions off of ./img...

    <./img >./img2 dd count=1779583
    

    1779583+0 records in
    1779583+0 records out
    911146496 bytes (911 MB) copied, 1.84985 s, 493 MB/s
    
  • We'll grep it again...

    grep -Ebao '(my[^0-9]*|PART)[123]' <./img2
    

    2826272:PART1
    2830336:my part# is 1
    904606240:PART2
    904624640:my part# is 2
    
  • And get an fdisk report...

    fdisk -l ./img2
    

    Disk ./img2: 869 MiB, 911146496 bytes, 1779583 sectors
    Units: sectors of 1 * 512 = 512 bytes
    Sector size (logical/physical): 512 bytes / 512 bytes
    I/O size (minimum/optimal): 512 bytes / 512 bytes
    Disklabel type: dos
    Disk identifier: 0xcbcab4d8
    
    Device     Boot   Start     End Sectors   Size Id Type
    ./img2p1           2048 1766655 1764608 861.6M 27 Hidden NTFS WinRE
    ./img2p2        1766784 1779583   12800   6.3M  7 HPFS/NTFS/exFAT
    ./img2p3        1779584 8284543 6504960   3.1G  7 HPFS/NTFS/exFAT
    

Now that is curious. fdisk still seems to believe there's a third partition extending as far out as 4G for a disk which it also seems to believe is only 869M in size!

  • Probably we should remove that third partition from the partition table.

    printf %s\\n d 3 w |
    fdisk ./img2 >/dev/null
    
  • And now lets see if we can mount the partitions we copied and if our files remain in tact...

    sudo sh -c ' trap "$1" 0
        cd /tmp; mkdir -p mnt
        for p in "$(losetup --show -Pf "$0")p"*
        do    mount "$p" mnt
              grep . /dev/null ./mnt/*
              umount mnt
        done' "$PWD/img2" 'losetup -D'
    

    ./mnt/part1:my part# is 1
    ./mnt/part2:my part# is 2
    

Apparently it's not impossible.

mikeserv
  • 58,310
0

It isn't possible because dd is only direct 1 input to 1 output --the restoration would be damage because you merged 3 partitions in one and this isn't a backup and dd is only for identical copies.

Your answer would be possible:

dd if=/dev/sda1 of=~/hdadisk1.img; 
dd if=/dev/sda2 of=~/hdadisk2.img
dd if=/dev/sda3 of=~/hdadisk3.img 

(In a script if you want) and finally, you can to create an image with the hdadisk{1,3,3}.img although is a better practice you save these images in a partition for backups.

Archemar
  • 31,554
0

dd count=$((132552703-2048)) copies 132552703-2048 blocks of 512 bytes from the beginning of the input. The block size in fdisk is 1 kB = 1024 bytes. So you have three problems:

  • You specified a size that's half what you wanted.
  • You didn't indicate that you wanted to start the copy at an offset.
  • Your subtraction has a fencepost error: it misses the last block — the number of blocks is (end block offset) - (start block offset) + 1.

So you can do that copy with

dd bs=1k skip=2048 count=$((132552703-2048+1)) if=/dev/sda of=./newImage.image

I think this will work — dd can silently lose data, but I think that 1kB blocks on a block device or regular file on Linux is fine. But it's slow.

The most straightforward way to copy a single partition would be to just copy it.

cat /dev/sda1 >sda1.image
cat /dev/sda2 >sda2.image
cat /dev/sda3 >sda3.image

It would be better to copy the partitions to separate files, because otherwise the partitions that aren't at the beginning of the file will be hard to use. If you really want the three partitions in the same file, you can concatenate them:

cat /dev/sda1 /dev/sda2 /dev/sda3 >newImage.image
0

The Easy quick answer is :

dd skip=2048 count=132552703 status=progress if=/dev/sda of=./newImage.image

fdisk -l by default returns partitions size in sectors of 512 bytes per sector

you can confirm that in the fdisk output it should show something like this :

Disk /dev/sda: 256 GiB, 274877906944 bytes, 536870912 sectors
Disk model: Virtual Disk
Units: sectors of 1 * 512 = 512 bytes
Sector size (logical/physical): 512 bytes / 512 bytes
I/O size (minimum/optimal): 512 bytes / 512 bytes

dd also uses 512 bytes as the default value for the switches "bs", "cbs", "ibs" and "obs"

  bs=BYTES        read and write up to BYTES bytes at a time (default: 512);
                  overrides ibs and obs
  cbs=BYTES       convert BYTES bytes at a time
  conv=CONVS      convert the file as per the comma separated symbol list
  count=N         copy only N input blocks
  ibs=BYTES       read up to BYTES bytes at a time (default: 512)
  if=FILE         read from FILE instead of stdin
  iflag=FLAGS     read as per the comma separated symbol list
  obs=BYTES       write BYTES bytes at a time (default: 512)
  of=FILE         write to FILE instead of stdout
  oflag=FLAGS     write as per the comma separated symbol list
  seek=N          skip N obs-sized blocks at start of output
  skip=N          skip N ibs-sized blocks at start of input
  status=LEVEL    The LEVEL of information to print to stderr;
                  'none' suppresses everything but error messages,
                  'noxfer' suppresses the final transfer statistics,
                  'progress' shows periodic transfer statistics

to confirm that you can use dd itself to create a one block file like this :

dd if=/dev/urandom of=test count=1

The file size should be 512 bytes

so all you have to do to create an image of a partition or group of partitions is to get the number of sectors for the start of the partition or first partition from the output of fdisk and use it as the value of the dd parameter "skip" and then the number of sectors for the End of the partition or last partition and set it as the value for the dd parameter "count".

If there is a block size difference between fdisk and dd you can always specify the block size in dd using the parameter "bs" to make sure the block size matches between fdisk output and what dd is going to use.