Skip to content

Instantly share code, notes, and snippets.

@htruong
Last active August 28, 2024 12:58
Show Gist options
  • Save htruong/7df502fb60268eeee5bca21ef3e436eb to your computer and use it in GitHub Desktop.
Save htruong/7df502fb60268eeee5bca21ef3e436eb to your computer and use it in GitHub Desktop.
Chroot to pi sd card
#!/bin/bash
# This script allows you to chroot ("work on")
# the raspbian sd card as if it's the raspberry pi
# on your Ubuntu desktop/laptop
# just much faster and more convenient
# credits: https://gist.github.com/jkullick/9b02c2061fbdf4a6c4e8a78f1312a689
# make sure you have issued
# (sudo) apt install qemu qemu-user-static binfmt-support
# Write the raspbian image onto the sd card,
# boot the pi with the card once
# so it expands the fs automatically
# then plug back to your laptop/desktop
# and chroot to it with this script.
# Invoke:
# (sudo) ./chroot-to-pi.sh /dev/sdb
# assuming /dev/sdb is your sd-card
# if you don't know, when you plug the card in, type:
# dmesg | tail -n30
# Note: If you have an image file instead of the sd card,
# you will need to issue
# (sudo) apt install kpartx
# (sudo) kpartx -v -a 2017-11-29-raspbian-stretch-lite.img
# then
# (sudo) ./chroot-to-pi.sh /dev/mapper/loop0p
# With the vanilla image, you have very little space to work on
# I have not figured out a reliable way to resize it
# Something like this should work, but it didn't in my experience
# https://gist.github.com/htruong/0271d84ae81ee1d301293d126a5ad716
# so it's better just to let the pi resize the partitions
mkdir -p /mnt/raspbian
# mount partition
mount -o rw ${1}2 /mnt/raspbian
mount -o rw ${1}1 /mnt/raspbian/boot
# mount binds
mount --bind /dev /mnt/raspbian/dev/
mount --bind /sys /mnt/raspbian/sys/
mount --bind /proc /mnt/raspbian/proc/
mount --bind /dev/pts /mnt/raspbian/dev/pts
# ld.so.preload fix
sed -i 's/^/#CHROOT /g' /mnt/raspbian/etc/ld.so.preload
# copy qemu binary
cp /usr/bin/qemu-arm-static /mnt/raspbian/usr/bin/
echo "You will be transferred to the bash shell now."
echo "Issue 'exit' when you are done."
echo "Issue 'su pi' if you need to work as the user pi."
# chroot to raspbian
chroot /mnt/raspbian /bin/bash
# ----------------------------
# Clean up
# revert ld.so.preload fix
sed -i 's/^#CHROOT //g' /mnt/raspbian/etc/ld.so.preload
# unmount everything
umount /mnt/raspbian/{dev/pts,dev,sys,proc,boot,}
@akhepcat
Copy link

Just in case somebody has previously commented out a line in /etc/ld.so.preload, you should change your prefixing:

sed -i 's/^/#CHROOT /g' /mnt/raspbian/etc/ld.so.preload
and
sed -i 's/^#CHROOT //g' /mnt/raspbian/etc/ld.so.preload

so that only your specific changes get unwrapped - and if there's an issue, it's obvious what was touched.

@htruong
Copy link
Author

htruong commented Jan 25, 2018

@akhepcat: Great idea, added to the script. Thanks!

@simspace-dev
Copy link

simspace-dev commented Jul 25, 2018

Thanks for the script. I've been looking into emulation. This seems so much easier and it worked first time.

I need to install some packages, but I can't get WIFI to work.
When I ping google.com, I get this message ...

Unsupported setsockopt level=41 optname=25
WARNING: your kernel is veeery old. No problems.
Unsupported setsockopt level=255 optname=7
setsockopt(RAW_CHECKSUM) failed - try to continue.Unsupported setsockopt level=58 optname=1
setsockopt(ICMP6_FILTER): Protocol not available

I did install the latest Stretch-Lite image

I did add cp -L /etc/resolv.conf /mnt/raspbian/etc/resolv.conf to the script, based on some posts I found regarding chroot and network connections, but still no luck.

Do you have any ideas how I can get the WIFI connection working, so I can install some packages and build a couple of apps?

Thanks,
Chris

@simspace-dev
Copy link

I found another post and it looks like mounting the resolv.conf file (not copying) is what was needed.

I changed cp -L /etc/resolv.conf /mnt/raspbian/etc/resolv.conf to mount --bind /etc/resolv.conf /mnt/raspbian/etc/resolv.conf and I can now ping sites from my chrooted Raspbian SD card.

Now, can I get an app to build? We'll find out. On to the next challenge.

Thanks again for the script!

@dimitry-ishenko
Copy link

FYI, if you install qemu-user-static on the host machine, there is no need to copy anything into the chroot.

@cinderblock
Copy link

@dimitry-ishenko what do you mean exactly? It is installed on the host machine. Is there a way to run the chroot so that you don't need to copy qemu-arm-static?

@dimitry-ishenko
Copy link

dimitry-ishenko commented Apr 10, 2020

@cinderblock pretty much what I said.

Linux has a feature called binfmt_misc. After you sudo apt install qemu-user-static package on the host machine, it will register a number of binary formats to allow execution of foreign binaries.

From the package description (note the last paragraph):

 QEMU is a fast processor emulator: currently the package supports
 ARM, CRIS, i386, M68k (ColdFire), MicroBlaze, MIPS, PowerPC, SH4,
 SPARC and x86-64 emulation. By using dynamic translation it achieves
 reasonable speed while being easy to port on new host CPUs.
 .
 This package provides the user mode emulation binaries, built
 statically. In this mode QEMU can launch Linux processes compiled for
 one CPU on another CPU.
 .
 qemu-user-static package will register binary formats which the provided
 emulators can handle, so that it will be possible to run foreign binaries
 directly.

No need to copy anything anywhere.

@cinderblock
Copy link

@dimitry-ishenko Wow! So everyone that's copying that binary over is just wasting time?

@dimitry-ishenko
Copy link

dimitry-ishenko commented Apr 11, 2020

@dimitry-ishenko Wow! So everyone that's copying that binary over is just wasting time?

Yep. Imagine the amount of time and electricity wasted on needlessly copying this file by millions of people... Trees that are cut down for no reason... Melting ice... Rising water levels... Bush fires in California... So... I figured I'll chime in and let everyone know. 🤣

@cinderblock
Copy link

@dimitry-ishenko So, I finally actually got around to trying this. It does not seem to work for me unless I copy the qemu binary to the chroot. I'm working over here: https://gist.github.com/cinderblock/20952a653989e55f8a7770a0ca2348a8

@ikidd
Copy link

ikidd commented Aug 12, 2020

I had to export PATH=/sbin:/usr/sbin:/usr/bin:/bin in the chroot, might want to add that to the comments in script for newish users so they can use common bash commands from the start.

@TheSeriousProgrammer
Copy link

Hi, so whenever I chroot into raspberry pi IMG , the processor arch is always armv7 .. Anyway I could select armv6??

@combs
Copy link

combs commented Dec 2, 2020

wow, this will save me some time, thank you!

Might be worth adding a 'set -e' or individual error handling to lines like chroot, mount, etc in case of typos or other errors... It could make changes to the host machine without?

edit: I guess it would just leave stray files in /mnt/raspbian. shrug!

@cinderblock
Copy link

cinderblock commented Dec 4, 2020

@combs Check out my version of this script that adds a trap to automatically cleanup no matter where the error happened.

@AgentCasey
Copy link

I've been chrooting into my raspberry pi's sdcard for a while now however, my method isn't so complicated. First after I boot the sdcard once, I make a directory called chroot-debian, then I use a sdcard-usb adapter so the sdcard appears as a usb device with two partitions, namely /dev/sdb1 which has the /boot/ and then /dev/sdb2 which is the /root partition. I issue these commands:
sudo mount -o bind /dev chroot-debian/dev
sudo mount -o bind /proc chroot-debian/proc
sudo chroot chroot-debian /bin/bash. Wonderful things happen after that I can issue apt update -y && apt upgrade -y and have it done. I have Debian Sid on that sdcard so if I need to build a package using debuild -uc -us to upgrade some of my aging apps in buster I can do it all on the same machine, all in my home directory. As I said my way is less complicated but I will study this method and see what wisdom I can gleam.

@Robokishan
Copy link

Is there any way we can get kernel version of img file i just have to copy .ko compiled files for linux kernel into system. but rather than hard coding kernel version like /lib/modules/5.10.11-v7l+/ i would like to get kernel version dynamically so in future it would be easy. but the problem is uname -r provides kernel version of host os any help please

@Robokishan
Copy link

Robokishan commented Feb 17, 2021

https://gist.github.com/Robokishan/8ffb8acec88fbbaf6c6c857d9c4ffe6a made a simple script for operation
How to do

  1. Download chroot-to-pi.sh
  2. in the same directory download above script
  3. Download img file of raspberrypi
  4. bash setup-chroot.sh
  5. Once work finished type exit and all the loop device will be deleted and mounted dir will be unmounted

Expand img file

https://gist.github.com/Robokishan/4dc13947b980bdcdfc20543b75c1f0fb using this script

@gnthibault
Copy link

It might seem obvious to some, but this method work wonderfull for very simple task, but due to the very nature of systemd and the way that chroot is working, you cannot get anything related to systemd done, you will get something like this:

Running in chroot, ignoring request: start
Running in chroot, ignoring request: restart
Running in chroot, ignoring request: reload
Running in chroot, ignoring request: daemon-reload
Running in chroot, ignoring request: is-active

@cinderblock
Copy link

@gnthibault Those methods indead do not work because they do not make sense to run when the Pi is offline.

However systemctl enable ... and related configuration commands work just fine.

PS, I've combined some of the ideas here with some others into a full repo. I'd love for others to check it out!

https://github.com/cinderblock/RaspberryPi-Image-Generator

@dmuiX
Copy link

dmuiX commented Dec 4, 2022

I would add something like to establish internet connection:

# establish internet connection
mv /mnt/raspbian/etc/resolv.conf /mnt/raspbian/etc/resolv.conf_bak
cp /etc/resolv.conf /mnt/raspbian/etc/

And in the cleanup section:

# revert /etc/resolv.conf_bak
rm /mnt/raspbian/etc/resolv.conf 
mv /mnt/raspbian/etc/resolv.conf_bak /mnt/raspbian/etc/resolv.conf

Just saw that somebody above already suggested adding resolv.conf as a mount bind. I will test if this is the better way.

@SX-9
Copy link

SX-9 commented Apr 16, 2023

sudo ./pi-chroot /dev/sdc

You will be transferred to the bash shell now.
Issue 'exit' when you are done.
Issue 'su pi' if you need to work as the user pi.
chroot: failed to run command ‘/bin/bash’: Exec format error

i have a feeling i got this error since im running it on arch linux and binfmt-support is not avaible in arch

@cinderblock
Copy link

@SX-9 Are you sure you got qemu working? There are some checks you can use here to see some more about what isn't setup properly.

@kelvie
Copy link

kelvie commented Jul 17, 2023

If anyone on arch is trying this, you can basically just install qemu-user-static-binfmt and just run sudo arch-chroot . on the rootfs (optionally mounting boot first).

@viniciusbo
Copy link

For those using Gentoo, make sure you've built qemu package with static-user and QEMU_SOFTMMU_TARGETS: arm QEMU_USER_TARGETS: arm. Further info in the official handbook: https://wiki.gentoo.org/wiki/Embedded_Handbook/General/Compiling_with_QEMU_user_chroot

@BoManev
Copy link

BoManev commented Feb 8, 2024

Alternative to dmesg | tail -n30

  • lsblk -o NAME,MOUNTPOINT
  • check the mount in /media/<user_name>/

@patrickelectric
Copy link

You rock! Just tested the script in a Rasp Pi 4 and it worked like magic!

@htruong
Copy link
Author

htruong commented Jun 8, 2024

Alternative to dmesg | tail -n30

  • lsblk -o NAME,MOUNTPOINT
  • check the mount in /media/<user_name>/

I learned this neat trick, if you do dmesg -w and then plug the drive in, you'll be able to watch the dmesg in real-time!

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment