1#!/bin/bash
2set -e
3set -u
4
5### Parameters for the installation.
6export TARGET_NFS_DIR="/srv/nfsroot/"
7export TARGET_TFTP_DIR="/srv/tftp/"
8export MIRROR="http://ftp.debian.org/debian/"
9export ETH="enp0s3"
10
11# Install packages that we need on the host system to install our PXE
12#   environment, which includes dnsmasq as a dhcp-server and tftp-server and
13#   nfs for the network files system.
14apt-get -y install debootstrap zip coreutils util-linux e2fsprogs dnsmasq \
15    nfs-common nfs-kernel-server
16
17mkdir -p ${TARGET_NFS_DIR}
18mkdir -p ${TARGET_TFTP_DIR}
19
20# Build a basic rootfs system (This takes a while)
21debootstrap --arch i386 jessie ${TARGET_NFS_DIR} ${MIRROR}
22
23# Setup apt-get configuration on the new rootfs.
24cat > ${TARGET_NFS_DIR}/etc/apt/sources.list <<-EOT
25deb ${MIRROR} stable main contrib non-free
26deb-src ${MIRROR} stable main contrib non-free
27
28deb http://security.debian.org/ stable/updates main contrib non-free
29deb-src http://security.debian.org/ stable/updates main contrib non-free
30
31EOT
32
33# Setup the PXE network interfaces configuration. This is the configuration the
34#   clients will use to bring up their network. Assumes that they have a single
35#   LAN card.
36cat > ${TARGET_NFS_DIR}/etc/network/interfaces <<-EOT
37auto lo
38iface lo inet loopback
39
40allow-hotplug eth0
41iface eth0 inet dhcp
42EOT
43
44# Setup the nfs root in a way so we can chroot into it.
45mount -t proc none ${TARGET_NFS_DIR}/proc
46mount --bind /sys ${TARGET_NFS_DIR}/sys
47mount --bind /dev ${TARGET_NFS_DIR}/dev
48mount -t tmpfs none ${TARGET_NFS_DIR}/tmp
49
50cp /etc/resolv.conf ${TARGET_NFS_DIR}/etc/resolv.conf
51# Setup a hostname on the NFS root (This might confuse some applications, as
52#   the hostname is random on each read)
53echo "pxeclient" > ${TARGET_NFS_DIR}/etc/hostname
54echo "127.0.0.1 pxeclient" >> ${TARGET_NFS_DIR}/etc/hosts
55# Setup /tmp as tmpfs on the netboot system, so we have a place to write
56#   things to.
57cat > ${TARGET_NFS_DIR}/etc/fstab <<-EOT
58tmpfs /tmp  tmpfs  nodev,nosuid 0  0
59EOT
60
61# Get syslinux/pxelinux, which contains a lot of files, but we need some of
62#   these to get PXE booting to work.
63sudo apt-get -y install pxelinux syslinux-efi
64mkdir -p ${TARGET_TFTP_DIR}/bios
65mkdir -p ${TARGET_TFTP_DIR}/efi32
66mkdir -p ${TARGET_TFTP_DIR}/efi64
67cp /usr/lib/PXELINUX/pxelinux.0 ${TARGET_TFTP_DIR}/bios/
68cp /usr/lib/syslinux/modules/bios/*.c32 ${TARGET_TFTP_DIR}/bios/
69cp /usr/lib/SYSLINUX.EFI/efi32/syslinux.efi ${TARGET_TFTP_DIR}/efi32/
70cp /usr/lib/syslinux/modules/efi32/*.e32 ${TARGET_TFTP_DIR}/efi32/
71cp /usr/lib/SYSLINUX.EFI/efi64/syslinux.efi ${TARGET_TFTP_DIR}/efi64/
72cp /usr/lib/syslinux/modules/efi64/*.e64 ${TARGET_TFTP_DIR}/efi64/
73
74# Setup the pxelinux configuration
75mkdir -p ${TARGET_TFTP_DIR}/pxelinux.cfg
76cat > ${TARGET_TFTP_DIR}/pxelinux.cfg/default <<-EOT
77DEFAULT linux
78LABEL linux
79KERNEL vmlinuz.img
80APPEND ro root=/dev/nfs nfsroot=192.168.55.1:${TARGET_NFS_DIR} initrd=initrd.img
81EOT
82ln -s ${TARGET_TFTP_DIR}/pxelinux.cfg ${TARGET_TFTP_DIR}/bios/pxelinux.cfg
83ln -s ${TARGET_TFTP_DIR}/pxelinux.cfg ${TARGET_TFTP_DIR}/efi32/pxelinux.cfg
84ln -s ${TARGET_TFTP_DIR}/pxelinux.cfg ${TARGET_TFTP_DIR}/efi64/pxelinux.cfg
85
86ln -s ${TARGET_TFTP_DIR}/vmlinuz.img ${TARGET_TFTP_DIR}/bios/vmlinuz.img
87ln -s ${TARGET_TFTP_DIR}/vmlinuz.img ${TARGET_TFTP_DIR}/efi32/vmlinuz.img
88ln -s ${TARGET_TFTP_DIR}/vmlinuz.img ${TARGET_TFTP_DIR}/efi64/vmlinuz.img
89
90ln -s ${TARGET_TFTP_DIR}/initrd.img ${TARGET_TFTP_DIR}/bios/initrd.img
91ln -s ${TARGET_TFTP_DIR}/initrd.img ${TARGET_TFTP_DIR}/efi32/initrd.img
92ln -s ${TARGET_TFTP_DIR}/initrd.img ${TARGET_TFTP_DIR}/efi64/initrd.img
93
94# Setup vmlinuz.img kernel in ${TARGET_TFTP_DIR}
95chroot ${TARGET_NFS_DIR} apt-get update
96chroot ${TARGET_NFS_DIR} apt-get -y install linux-image-686-pae firmware-linux-nonfree
97cp ${TARGET_NFS_DIR}/boot/vmlinuz* ${TARGET_TFTP_DIR}/vmlinuz.img
98cp ${TARGET_NFS_DIR}/boot/initrd.img* ${TARGET_TFTP_DIR}/initrd.img
99
100# Setup the export to the /etc/exports file, this will server our root trough
101#   NFS after rebooting the system later.
102cat > /etc/exports <<-EOT
103${TARGET_NFS_DIR} *(ro,sync,no_root_squash,insecure)
104EOT
105
106# Setup the network interface to a static IP.
107cat > /etc/network/interfaces <<-EOT
108auto lo
109iface lo inet loopback
110
111allow-hotplug ${ETH}
112auto ${ETH}
113iface ${ETH} inet static
114    address 192.168.55.1
115    netmask 255.255.255.0
116    gateway 192.168.55.1
117EOT
118
119# Setup dnsmasq configuration to serve a PXE boot envirnoment, tftp-server, and
120#   to serve as dhcp server (as PXE is handled with DHCP and TFTP)
121cat > /etc/dnsmasq.conf <<-EOT
122interface=${ETH}
123dhcp-range=192.168.55.10,192.168.55.254
124
125dhcp-boot=bios/pxelinux.0
126dhcp-match=set:efi32,option:client-arch,6
127dhcp-match=set:efi64,option:client-arch,7
128dhcp-match=set:efi64,option:client-arch,9
129dhcp-boot=tag:efi32,efi32/syslinux.efi
130dhcp-boot=tag:efi64,efi64/syslinux.efi
131
132enable-tftp
133tftp-root=${TARGET_TFTP_DIR}
134EOT
135
136# Disable some services to decrease boot time
137chroot ${TARGET_NFS_DIR} systemctl disable rsyslog
138
139# Install tools in NFS root required to build EE.
140chroot ${TARGET_NFS_DIR} apt-get update
141chroot ${TARGET_NFS_DIR} apt-get -y install git build-essential libx11-dev \
142    cmake libxrandr-dev mesa-common-dev libglu1-mesa-dev libudev-dev \
143    libglew-dev libjpeg-dev libfreetype6-dev libopenal-dev libsndfile1-dev \
144    libxcb1-dev libxcb-image0-dev
145# Install basic X setup in NFS root to allow us to run EE later on.
146chroot ${TARGET_NFS_DIR} apt-get -y install xserver-xorg-core \
147    xserver-xorg-input-all xserver-xorg-video-all xinit alsa-utils
148
149# Download&install SFML,EE,SP (This takes a while)
150chroot ${TARGET_NFS_DIR} git clone https://github.com/daid/EmptyEpsilon.git /root/EmptyEpsilon
151chroot ${TARGET_NFS_DIR} git clone https://github.com/daid/SeriousProton.git /root/SeriousProton
152chroot ${TARGET_NFS_DIR} apt-get -y install libsfml-*
153mkdir -p ${TARGET_NFS_DIR}/root/EmptyEpsilon/_build
154chroot ${TARGET_NFS_DIR} sh -c 'cd /root/EmptyEpsilon/_build && cmake .. -DSERIOUS_PROTON_DIR=$HOME/SeriousProton/ && make -j 3'
155# Create a symlink for the final executable.
156chroot ${TARGET_NFS_DIR} ln -s _build/EmptyEpsilon /root/EmptyEpsilon/EmptyEpsilon
157# Create a symlink to store the options.ini file in /tmp/, this so the client
158#   can load a custom file.
159chroot ${TARGET_NFS_DIR} ln -s /tmp/options.ini /root/EmptyEpsilon/options.ini
160
161cat > ${TARGET_NFS_DIR}/root/setup_option_file.sh <<-EOT
162#!/bin/sh
163MAC=\$(cat /sys/class/net/eth0/address | sed 's/://g')
164if [ -e /root/configs/\${MAC}.ini ]; then
165    cp /root/configs/\${MAC}.ini /tmp/options.ini
166else
167    echo "instance_name=\${MAC}" > /tmp/options.ini
168fi
169EOT
170chmod +x ${TARGET_NFS_DIR}/root/setup_option_file.sh
171# Create a link to our client configuration tool, which helps in setting up
172#   option files per client.
173ln -s ${TARGET_NFS_DIR}/root/EmptyEpsilon/netboot/config_manager.py ~/config_manager.py
174
175# Create an install a systemd unit that runs EE.
176cat > ${TARGET_NFS_DIR}/etc/systemd/system/emptyepsilon.service <<-EOT
177[Unit]
178Description=EmptyEpsilon
179
180[Service]
181Environment=XAUTHORITY=/tmp/.xauthority
182TimeoutStartSec=0
183WorkingDirectory=/root/EmptyEpsilon
184ExecStartPre=/root/setup_option_file.sh
185ExecStart=/usr/bin/startx /root/EmptyEpsilon/EmptyEpsilon -- -logfile /tmp/x.log
186
187[Install]
188WantedBy=multi-user.target
189EOT
190chroot ${TARGET_NFS_DIR} systemctl enable emptyepsilon.service
191
192# Disable screen standby/blanking
193mkdir -p ${TARGET_NFS_DIR}/etc/X11/xorg.conf.d
194cat > ${TARGET_NFS_DIR}/etc/X11/xorg.conf.d/10-monitor.config <<-EOT
195Section "Monitor"
196    Identifier "LVDS0"
197    Option "DPMS" "false"
198EndSection
199
200Section "ServerLayout"
201    Identifier "ServerLayout0"
202    Option "StandbyTime" "0"
203    Option "SuspendTime" "0"
204    Option "OffTime"     "0"
205    Option "BlankTime"   "0"
206EndSection
207EOT
208
209# Instead of running a login shell on tty1, run a normal shell so we do not
210#   have to login with a username/password are just root. Who cares, we are on
211#   a read only system.
212cat > ${TARGET_NFS_DIR}/etc/systemd/system/shell_on_tty.service <<-EOT
213[Unit]
214Description=Shell on TTY1
215After=getty.target
216Conflicts=getty@tty1.service
217
218[Service]
219Type=simple
220RemainAfterExit=yes
221ExecStart=/bin/bash
222TimeoutStopSec=1
223StandardInput=tty-force
224StandardOutput=inherit
225StandardError=inherit
226
227[Install]
228WantedBy=graphical.target
229EOT
230chroot ${TARGET_NFS_DIR} systemctl enable shell_on_tty.service
231
232# Install the ssh server on the netboot systems, so we can remotely access
233#   them, setup a private key on the server and put the public on as authorized
234#   key in the netboot system. Also install avahi for easier server discovery.
235chroot ${TARGET_NFS_DIR} apt-get install -y openssh-server avahi-daemon avahi-utils libnss-mdns
236echo "PermitRootLogin yes" >> ${TARGET_NFS_DIR}/etc/ssh/sshd_config
237if [[ ! -e $HOME/.ssh/id_rsa ]]; then
238    ssh-keygen -t rsa -f $HOME/.ssh/id_rsa -N ''
239fi
240mkdir -p ${TARGET_NFS_DIR}/root/.ssh/
241cp $HOME/.ssh/id_rsa.pub ${TARGET_NFS_DIR}/root/.ssh/authorized_keys
242cat > ${TARGET_NFS_DIR}/etc/avahi/services/ee.service <<-EOT
243<?xml version="1.0" standalone='no'?>
244<!DOCTYPE service-group SYSTEM "avahi-service.dtd">
245<service-group>
246  <name replace-wildcards="yes">EmptyEpsilon on %h</name>
247  <service>
248    <type>_emptyepsilon._tcp</type>
249    <port>22</port>
250  </service>
251</service-group>
252EOT
253
254# Install distcc, and setup distcc per default on all our netbooted clients.
255#   Meaning we can speed up compiling of EE the more hosts we have.
256chroot ${TARGET_NFS_DIR} apt-get -y install distcc
257# Setup the distcc configuration for the clients.
258sed -ie 's/STARTDISTCC="false"/STARTDISTCC="true"/' ${TARGET_NFS_DIR}/etc/default/distcc
259sed -ie 's/ALLOWEDNETS="127.0.0.1"/ALLOWEDNETS="192.168.0.0\/16 172.16.0.0\/12 10.0.0.0\/8"/' ${TARGET_NFS_DIR}/etc/default/distcc
260sed -ie 's/LISTENER="127.0.0.1"/LISTENER="0.0.0.0"/' ${TARGET_NFS_DIR}/etc/default/distcc
261sed -ie "s/JOBS=\"\"/JOBS=\"2\"/" ${TARGET_NFS_DIR}/etc/default/distcc
262sed -ie 's/ZEROCONF="false"/ZEROCONF="true"/' ${TARGET_NFS_DIR}/etc/default/distcc
263
264# Create extra scripts to ease the maintenance of this machine.
265cat > /etc/network/interfaces.dhcp_client <<-EOT
266auto lo
267iface lo inet loopback
268
269allow-hotplug ${ETH}
270auto ${ETH}
271iface ${ETH} inet dhcp
272EOT
273
274cat > /root/dhcp_client.sh <<-EOT
275#!/bin/bash
276## Script to stop the dhcp server, and use the network port as normal client
277##   port. So we can access other networks.
278systemctl stop dnsmasq
279ifdown -a
280ifup -a -i /etc/network/interfaces.dhcp_client
281EOT
282chmod +x /root/dhcp_client.sh
283
284cat > /root/dhcp_server.sh <<-EOT
285#!/bin/bash
286## Script to start the dhcp server, and use the network port to host the
287##   network boot environment. (useful after switching to client with
288##   dhcp_client.sh)
289systemctl stop dnsmasq
290ifdown -a
291ifup -a
292systemctl start dnsmasq
293EOT
294chmod +x /root/dhcp_server.sh
295
296cat > /root/update.sh <<-EOT
297#!/bin/bash
298## Script to update EE, assumes you have internet on this machine.
299mount -t proc none ${TARGET_NFS_DIR}/proc
300mount --bind /sys ${TARGET_NFS_DIR}/sys
301mount --bind /dev ${TARGET_NFS_DIR}/dev
302mount -t tmpfs none ${TARGET_NFS_DIR}/tmp
303
304cp /etc/resolv.conf ${TARGET_NFS_DIR}/etc/resolv.conf
305chroot ${TARGET_NFS_DIR} sh -c 'cd /root/SeriousProton/ && git pull'
306chroot ${TARGET_NFS_DIR} sh -c 'cd /root/EmptyEpsilon/ && git pull'
307chroot ${TARGET_NFS_DIR} sh -c 'cd /root/EmptyEpsilon/_build && cmake .. -DSERIOUS_PROTON_DIR=/root/SeriousProton/ && make -j 3'
308EOT
309chmod +x /root/update.sh
310