Raspberry PiのMicro SDカードから配布用imageファイルを作る with Ubuntu 18.04 LTS

#はじめに
Raspberry Piでデバイスを開発した！MicroSDの中身をImage ファイルに書き出して配布したい！でもやり方がわからない！そんなお方向けのマニアチックなQiitaです。

なお、MicroSDのバックアップおよびクローン作成にも最適です。

**注意:まずは本内容が動くかどうかテスト用のMicroSDでテストしてから、目的のMicroSDで試してください。本メソッドを用いて生じた損害などについて筆者は一切の責任を持ちません。**

#Material
- 配布用imageを作りたいRaspberry PiのMicroSD (今回はRaspberry Pi3B+のRaspbian Buster, 32GB)
- Ubuntu 18.04 LTS (作業用PC)
- GParted (Linux用パーテション編集ソフト.今回の主役)

#Method

1. GPartedをUbuntuへインストール

    ```Bash
    $ sudo apt update
    $ sudo apt upgrade
    $ sudo apt install gparted
    ```

2. Raspberry Piから取り出したMicroSDを、Ubuntuが入っているPCへ入れる。

3. どのUSBデバイスとして認識されているのか、`$ sudo fdisk -l`で確認する。**ここからの操作を間違えるとデータ全損失につながる可能性があるので注意！**

    ```Bash
    $ sudo fdisk -l
    ...
    Disk /dev/sdc: 29.2 GiB, 31312576512 bytes, 61157376 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: 0x000816c0
    ...
    # 今回は/dev/sdcでした。
    ```

4. `dd`コマンドを用いてブロック単位でバックアップを行います。これでパテーション/ファイルシステムによらず、MicroSDの中身すべてのバックアップが可能になります。**`dd`コマンドを使用する際は、if(input file)とof(output file)の指定に注意してください！間違えると一瞬でデータが飛びます！**(参考: [Arch linux, ディスクのクローン](https://wiki.archlinux.jp/index.php/%E3%83%87%E3%82%A3%E3%82%B9%E3%82%AF%E3%81%AE%E3%82%AF%E3%83%AD%E3%83%BC%E3%83%B3))。

    ```Bash
    $ sudo dd bs=1M if='/dev/sdx' of='/path/to/image/file/hoge.img' status=progress
    # ifはMicroSDのデバイス場所今回は'/dev/sdc'
    # ofはimageファイルのパス。ファイル名は自由。拡張子は'.img'。
    # 終了までしばらく待ちます。
    31301042176 bytes (31 GB, 29 GiB) copied, 
    1469 s, 21.3 MB/s
    29862+0 records in
    29862+0 records out
    31312576512 bytes (31 GB, 29 GiB) copied, 
    1470.23 s, 21.3 MB/s
    ```

5. 吸い出したimgファイルを、/dev/loop(ループバックデバイス)にマウントし、GPartedで編集します。
    
    ```Bash
    $ sudo losetup -f    # /dev/loop (ループバックデバイス)の空きを探します。
    /dev/loop18    # 今回は /dev/loop18 でした。
    $ sudo losetup /dev/loop18 '/path/to/image/file/hoge.img'  # 空いていた/dev/loop (今回は/dev/loop18) に dd で吸い取った img ファイルをマウントします。
    $ sudo partprobe /dev/loop18  # パーティションテーブルを変更したことをOSに知らせます。
    $ sudo gparted /dev/loop18  # GPartedを起動します。
    ```
    
6. GPartedでパーティションの編集を行います。
 1. RaspbianをNOOBSでインストールすると、このように複雑なパーティションに分かれています。Raspbianを直にインストールしていればもっと単純なはずです (参考:[バックアップしたイメージファイルを縮小する](https://nijiota.net/archives/pc/raspberrypi/sd-img-resize/))。 
 ![Screenshot from 2020-02-23 21-37-25.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/588752/8efb3cb4-d6ee-6730-eb32-6dc4442d2b17.png)

 

 2. パーティションが可視化されたバーの白い部分が空きスペース (データは書き込まれていないが容量は食っている部分) なので、ここを減らします。一番下の`/dev/loop18p7`をクリックし、その上で`右クリック --> Resize/Move`を選択し、Resize/Move windowを開きます。
 ![Screenshot from 2020-02-23 21-51-05.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/588752/ba742146-5de2-9895-aace-33a92f2d5469.png)
 ![Screenshot from 2020-02-23 21-52-28.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/588752/14ee09ed-4d1e-0cdd-863f-f88b62b3b47b.png)

 3. スケールバーをドラッグし、白いフリー部分を黄色のデータが存在する領域付近まで持っていきます。なお、このときギリギリまでもってくると失敗します(Trouble-Shooting参照)。その後、`Resize/Move`をクリックし、パーティション変更情報を保存します(まだパーテションの変更処理は行われていません)。
 ![Screenshot from 2020-02-23 21-52-45.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/588752/ce778e43-af10-8c00-1c68-6194bee3f271.png)
 ![Screenshot from 2020-02-23 21-52-56.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/588752/837195fc-8dad-45cf-1deb-02bf525d0f7a.png)

 4. `/dev/loop18p7`の領域は変更されましたが、親である`/dev/loop18p2`はまだ変更されていません。`/dev/loop18p2`を選択し、その上で`右クリック --> Resize/Move`を選択し、Resize/Move windowを開きます。先ほどと同様、スケールバーをドラッグし、unallocated部分(灰色)を減らしますが、今回はピッチリ黄色の`/dev/loop18p7`へ寄せます。その後、`Resize/Move`をクリックし、パーティション変更情報を保存します(まだパーテションの変更処理は行われていません)。
 ![Screenshot from 2020-02-23 21-53-06.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/588752/0d817c09-519f-1b03-7747-db2b30a01d3a.png)
 ![Screenshot from 2020-02-23 21-53-02.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/588752/31fa82b6-7d12-7a71-87db-458e519a6117.png)

 5. パーティション変更情報がこの状態になったことを確認し、GParted window上部中央やや左の緑の✔マークをクリックし、プロセスを開始します。
 ![Screenshot from 2020-02-23 21-53-12.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/588752/c5ce02f2-69af-645c-e207-8e7cf18a169e.png)

 6. 警告画面が表示されますが、`Apply`をクリックしてパーティションの編集処理をスタートします。
 ![Screenshot from 2020-02-23 21-54-05.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/588752/8f41d822-a885-e35c-6f16-e143031eb21c.png)
 ![Screenshot from 2020-02-23 21-56-27.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/588752/50bb7952-0d6d-27f4-eb5b-2108af34bd7e.png)

 7. 処理が終了したのを確認後、`Close`をクリックして画面を閉じ、編集後のパーティションの"unallocated"が`/dev/loop18p2`から独立し、分かれて存在していることを確認します。
 ![Screenshot from 2020-02-23 21-57-43.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/588752/a3687b23-321a-a1ad-6747-041f16ce374b.png)
 ![Screenshot from 2020-02-23 21-57-48.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/588752/bdb82e37-8812-2aa8-b99b-e976758dfac9.png)

 8. GPartedを終了します。

7. GPartedで編集したパーティションの"unallocated"部分を```fdisk```を用いて削除します。

    ```Bash
    $ sudo losetup -d /dev/loop18  # /dev/loop18をunmountします。
    $ sudo fdisk -l '/path/to/image/file/hoge.img'  # fdisk -l を用いてGPatedで編集したパーティションを見ます。

    Disk /path/to/image/file/hoge.img: 29.2 GiB, 31312576512 bytes, 61157376 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: 0x000816c0
    
    Device                     Boot    Start    End     Sectors  Size Id Type
/path/to/image/file/hoge.img1         8192  4994140  4985949  2.4G  e W95 FAT16 (LBA)
/path/to/image/file/hoge.img2      4994141 31594495 26600355 12.7G  5 Extended
/path/to/image/file/hoge.img5      4997120  5062653    65534   32M 83 Linux
/path/to/image/file/hoge.img6      5062656  5586941   524286  256M  c W95 FAT32 (LBA)
/path/to/image/file/hoge.img7      5586944 31594495 26007552 12.4G 83 Linux
    ```

8. `truncate`コマンドでhoge.imgのフリースペースを削除し、最終的な配布用imgファイルを作ります。このとき、セクターの最大値(今回は"31594495")に1を足し、それを512倍したもののサイズを指定します。

    ```Bash
    $ sudo truncate --size=$[(31594495+1)*512] '/path/to/image/file/hoge.img'
    ```

9. 無事にファイルサイズが小さくなった配布用のimageファイルが作成されました! ```sudo chown```でパーミッションを変更し完成です!

    ```Bash
    $ ls -lh
    ...
    -rw-r--r-- 1 root     root     25G Feb 23 20:00  hgoe.img
    ...
    $ sudo chown hoge:hoge ./hoge.img
    ...
    -rw-r--r-- 1 hoge     hoge     25G Feb 23 20:00  hgoe.img
    ...
    ```

10. おつかれさまでした !!

#作成したimgファイルを元にしたクローンの作成
今回作成した img ファイルを元に新たな MicroSD を作成するには、再び`dd`コマンドを使用します。**ifとofの指定に気をつけてください！特にofの指定を誤ると他の補助記憶装置の中身が全削除されます！**

```Bash
$ sudo dd bs=1M if='/path/to/image/file/hoge.img' of=/dev/sdx status=progress
# MicroSDのデバイスIDは、`fdisk -l`などで調べられます。
```

#Trouble-Shooting
1. GPatedで`/dev/loop18p7`(今回の場合)のパテーションを変更する際、あまりにもギリギリまで攻めすぎると、以下のエラー画面が出ます。この画面が出ましたら、少し余裕を持ってフリースペースを設定してみてください。

　　![Screenshot from 2020-02-23 21-55-52.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/588752/29592709-8d72-5de6-1ae4-74367bc4fbe8.png)


#References
以下のサイトを参考にさせていただきました。大変、ありがとうございました。
1. [Arch linux: GParted](https://wiki.archlinux.jp/index.php/GParted)
2. [NIJIOTA.NET: バックアップしたイメージファイルを縮小する](https://nijiota.net/archives/pc/raspberrypi/sd-img-resize/)
3. [Arch linux, ディスクのクローン](https://wiki.archlinux.jp/index.php/%E3%83%87%E3%82%A3%E3%82%B9%E3%82%AF%E3%81%AE%E3%82%AF%E3%83%AD%E3%83%BC%E3%83%B3)