aboutsummaryrefslogtreecommitdiff
path: root/pistrap-debian
blob: eefaa9a1045965fd3faab3e2862cd62765eba12a (plain) (blame)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
#!/bin/bash
set -e

# Variables set through command-line arguments
# the assigned values are used as defaults if no matching argument is provided
FORCE=0
MIRROR=""
HOSTNAME="pi"
TIMEZONE="UTC"
WPA_ESSID=""
WPA_PSK=""
ROOT_PASSWORD="toor"
SSH_KEY="$HOME/.ssh/id_rsa.pub"

# Paths for installation
DEVICE=/dev/nonexisting
PARTITION1="$DEVICE"p1
PARTITION2="$DEVICE"p2
ROOTFS=/mnt/pi

print_usage() {
    cat 1>&2 <<EOF
Usage: $0 [OPTION]... DEVICE
Create a bootable image for a RaspberryPi 2 on DEVICE.

Options:
  --force				Don't ask for any confirmations.
  --mirror=<$MIRROR>				Use a debian mirror, such as "fr" or "ch"
  --hostname=<$HOSTNAME>			Use a given hostname for the device.
  --timezone=<$TIMEZONE>			Set timezone data as listed in /usr/share/zoneinfo
  --wpa-essid=<$WPA_ESSID>			Use a given wireless ESSID. Sets up wireless networking.
  --wpa-psk=<$WPA_PSK>				Use a given WPA pre-shared key.
  --password=<$ROOT_PASWORD>				Set the given root password.
  --ssh-key=<$SSH_KEY>	Add the given SSH key to root's authorized_keys file. If invalid, password login will be enabled.
  --root-fs=<$ROOTFS>			Use given directory as mount point during installation.
EOF

}


# Process options
while [ $# -gt 1 ]
do
    case "$1" in
	-f|--force)
	    FORCE=1
	    ;;
	--mirror=*)
	    MIRROR=."${1#*=}"
	    ;;
	--hostname=*)
	    HOSTNAME="${1#*=}"
	    ;;
	--timezone=*)
	    TIMEZONE="${1#*=}"
	    ;;
	--wpa-essid=*)
	    WPA_ESSID="${1#*=}"
	    ;;
	--wpa-psk=*)
	    WPA_PSK="${1#*=}"
	    ;;
	--password=*)
	    ROOT_PASSWORD="${1#*=}"
	    ;;
	--ssh-key=*)
	    SSH_KEY="${1#*=}"
	    ;;
	--root-fs=*)
	    ROOTFS="${1#*=}"
	    ;;
	*)
	    echo "Unknown argument: $1" 1>&2
	    exit 1
    esac
    shift
done

# Process last argument, the device to use
if [ -z "$1" ] || [ "$1" = -h ] || [ "$1" = --help ]; then
    print_usage
    exit 1
fi
if [ ! -e "$1" ]; then
    echo "Device not found: $1" 1>&2
    exit 1
fi
if [ ! -b "$1" ]; then
    echo "Specified device is not a block device: $1" 1>&2
    exit 1
fi
DEVICE="$1"
PARTITION1="$DEVICE"p1
PARTITION2="$DEVICE"p2

# Check environment
if [ "$EUID" != 0 ]; then
    echo "This script must be run as root." 1>&2
    exit 1
fi

# Argument processing and enivronment check are done at this point
# Start with actual script

# Setup partitions on SD card
partition() {
    parted "$DEVICE" --script mklabel msdos &&
    parted "$DEVICE" --script mkpart primary fat32 1M 200M &&
    parted "$DEVICE" --script mkpart primary ext4 200M 100% &&
    mkfs.vfat -F 32 "$PARTITION1" &&
    mkfs.ext4 "$PARTITION2"
}

mountrootfs() {
    mkdir "$ROOTFS" &&
    mount "$PARTITION2" "$ROOTFS" &&
    
    mkdir "$ROOTFS"/boot &&
    mount "$PARTITION1" "$ROOTFS"/boot
}

mkrootfs() {
    # Create initial debian filesystem
    qemu-debootstrap --arch=armhf \
		     --include=ssh,sudo,ntpdate,fake-hwclock,openssl,ca-certificates,vim,nano,cryptsetup,lvm2,locales,less,cpufrequtils,wireless-tools,wpasupplicant \
		     jessie \
		     "$ROOTFS" \
		     "http://ftp${MIRROR}.debian.org/debian/"

    # Set package configuration to use raspberrypi.org archive for kernel package
    cat > "$ROOTFS"/etc/apt/sources.list <<EOF
deb http://ftp${MIRROR}.debian.org/debian jessie main contrib non-free
deb http://ftp${MIRROR}.debian.org/debian jessie-updates main contrib non-free
deb http://security.debian.org jessie/updates main contrib non-free
deb http://archive.raspberrypi.org/debian wheezy main
EOF

    cat > "$ROOTFS"/etc/apt/preferences.d/raspberrypi <<EOF
Package: *
Pin: origin archive.raspberrypi.org
Pin-Priority: 1

Package: raspberrypi-bootloader
Pin: origin archive.raspberrypi.org
Pin-Priority: 1000

Package: libraspberrypi0
Pin: origin archive.raspberrypi.org
Pin-Priority: 1000

Package: libraspberrypi-bin
Pin: origin archive.raspberrypi.org
Pin-Priority: 1000
EOF

    chroot "$ROOTFS" /bin/sh -c "wget https://archive.raspberrypi.org/debian/raspberrypi.gpg.key -O - | apt-key add -"
    
    chroot "$ROOTFS" apt-get update

    # libraspberrypi-bin contains kernel, firmware and some binary tools
    chroot "$ROOTFS" apt-get install locales dbus openssh-server dosfstools libraspberrypi-bin

    cat > "$ROOTFS"/boot/config.txt <<EOF
gpu_mem=128
start_file=start_x.elf
fixup_file=fixup_x.dat
EOF

    # Set up network
    if [ -n "$WPA_ESSID" ]; then
	cat > "$ROOTFS"/etc/network/interfaces.d/wlan0 <<EOF
auto wlan0
iface wlan0 inet dhcp
        wpa-essid "$WPA_ESSID"
        wpa-psk "$WPA_PSK"
EOF
	chmod 660 "$ROOTFS"/etc/network/interfaces.d/wlan0
	chroot "$ROOTFS" apt-get install firmware-realtek
    else
	cat > "$ROOTFS"/etc/network/interfaces.d/eth0 <<EOF
auto eth0
iface eth0 inet dhcp
EOF
    fi

    # Set up file mounts
    cat > "$ROOTFS"/etc/fstab <<EOF
UUID=$(blkid -s UUID -o value "$PARTITION1") /boot vfat noatime   0 2
UUID=$(blkid -s UUID -o value "$PARTITION2") /     ext4 noatime   0 1
tmpfs                                        /tmp  tmpfs defaults 0 0
EOF

    # Set timezone
    echo "$TIMEZONE" > "$ROOTFS"/etc/timezone
    ln -sf /usr/share/zoneinfo/"$TIMEZONE" "$ROOTFS"/etc/localtime

    # Set host configuration
    echo "$HOSTNAME" > "$ROOTFS"/etc/hostname
    sed -i "/^127.0.0.1/ s/\$/ $HOSTNAME/" "$ROOTFS"/etc/hosts
    sed -i "/^::1/ s/\$/ $HOSTNAME/" > "$ROOTFS"/etc/hosts

    # Login options
    chroot "$ROOTFS" /bin/sh -c "echo root:$ROOT_PASSWORD | chpasswd"

    if [ -e "$SSH_KEY" ]; then
	mkdir "$ROOTFS"/root/.ssh
	chmod 600 "$ROOTFS"/root/.ssh
	cat "$SSH_KEY" >> "$ROOTFS"/root/.ssh/authorized_keys
	chmod 600 "$ROOTFS"/root/.ssh/authorized_keys
	sed -i 's/#PasswordAuthentication yes/PasswordAuthentication no/g' "$ROOTFS"/etc/ssh/sshd_config
	echo "Success: SSH password login was disabled! Use the key in $SSH_KEY to login." 1>&2
    else
	sed -i 's/PermitRootLogin without-password/PermitRootLogin yes/g' "$ROOTFS"/etc/ssh/sshd_config
	echo "Warning: no SSH key found, SSH password login has been enabled for root! Please enable key-login only as soon as possible." 1>&2
    fi
}

umountrootfs() {
    rm -f "$ROOTFS"/usr/bin/qemu-arm-static
    umount "$ROOTFS"/boot
    umount "$ROOTFS"
    rm -r "$ROOTFS"
}


if [ "$FORCE" != 1 ]; then
    echo "WARNING: The following operations may have destructive consequences." 1>&2
    echo "Partition device $DEVICE and create bootable root file system on $ROOTFS" 1>&2
    read -p "Continue? [Y,n] " yn
    if [ "$yn" != "Y" ] && [ "$yn" != "y" ]; then
	echo "Aborting." 1>&2
	exit 1
    fi
fi

partition && mountrootfs && mkrootfs && umountrootfs