-
Notifications
You must be signed in to change notification settings - Fork 11
Expand file tree
/
Copy pathlinuxrc
More file actions
377 lines (326 loc) · 11.2 KB
/
linuxrc
File metadata and controls
377 lines (326 loc) · 11.2 KB
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
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
356
357
358
359
360
361
362
363
364
365
366
367
368
369
370
371
372
373
374
375
376
377
#!/bin/sh
# SPDX-License-Identifier: BSD-3-Clause
# SPDX-FileCopyrightText: Copyright (c) 2009-2023, NVIDIA CORPORATION. All rights reserved.
# See /etc/LICENSE file for details.
VERSION="TINYLINUX_VERSION"
CONSOLE="/dev/console"
ROOTFS="/mnt/root"
MNT_TIMEOUT="10"
MNTNV="mnt/nv"
MNTSQUASH="mnt/squash"
MNTETC="mnt/etc"
SQUASHFS_BIN="tiny/squash.bin"
NFSSHARE=""
NET="eth0"
MAC=""
OVRCFG="1"
READONLY=""
COLDPLUG="1"
CONSOLE_TTYS=""
# Clear input and output
exec >${CONSOLE} <${CONSOLE} 2>&1
# Display startup info
echo -e "\033[1mBooting TinyLinux $VERSION\033[0m"
# Mount basic filesystems
mount -t proc proc /proc
mount -t sysfs sysfs /sys
mount -t devtmpfs devtmpfs /dev
# Install busybox symbolic links
/bin/busybox --install -s
# Save kernel boot time for later
KERNEL_BOOT_TIME=$(awk '{print $1*1000}' /proc/uptime)
# Prevent kernel logs from being sent to the console
dmesg -n 3
# Setup hotplug
# Use modprobe from busybox to avoid genkernel's modprobe sript
# which does not process module aliases.
echo '#!/bin/sh
[ "$ACTION" = "add" ] && busybox modprobe "$MODALIAS"' > /tmp/hotplug
chmod 755 /tmp/hotplug
echo /tmp/hotplug > /proc/sys/kernel/hotplug
# Parse kernel command line
for ARG in $(cat /proc/cmdline); do
case "$ARG" in
squash\=*) SQUASHFS_BIN="${ARG#*=}" ;;
partno\=*) PARTNUMBER="${ARG#*=}" ;;
nfsshare\=*) NFSSHARE="${ARG#*=}" ;;
net\=*) NET="${ARG#*=}" ;;
BOOTIF\=*) MAC="${ARG#*=}" ;;
ovrcfg\=*) OVRCFG="${ARG#*=}" ;;
mount_timeout\=*) MNT_TIMEOUT="${ARG#*=}" ;;
nocoldplug) COLDPLUG="" ;;
console\=*) CONSOLE_TTYS="$CONSOLE_TTYS ${ARG#*=}" ;;
ro) READONLY="-o ro" ;;
esac
done
# Create root filesystem
mkdir -p "${ROOTFS}"
mount -t tmpfs tmpfs "${ROOTFS}"
# Coldplug
if [ "$COLDPLUG" = "1" ]; then
ls /sys/bus/pci/devices/*/uevent /sys/bus/usb/devices/*/uevent /sys/block/*/uevent /sys/block/*/*/uevent | while read UEVENT; do
echo "add" > "$UEVENT"
done
fi
# Mounts squashed root filesystem and checks TinyLinux version
mount_squash()
{
if ! mount -t squashfs -o loop,ro "${ROOTFS}/${MNTNV}/${SQUASHFS_BIN}" "${ROOTFS}/${MNTSQUASH}"; then
echo "Error: Failed to mount ${1}/${SQUASHFS_BIN}"
return 1
fi
# Check TinyLinux version in the squashed root filesystem
SQUASHFS_VERSION=$(head -n 1 "${ROOTFS}/${MNTSQUASH}/etc/release" | sed "s/.*version //")
if [ "$VERSION" != "$SQUASHFS_VERSION" ]; then
echo "Error: initrd version $VERSION does not match TinyLinux version $SQUASHFS_VERSION"
echo " found in ${1}/${SQUASHFS_BIN}"
umount "${ROOTFS}/${MNTSQUASH}"
return 1
fi
}
find_net_dev_from_mac()
{
# Skip if BOOTIF was not specified
[ -n "$MAC" ] || return 0
# Turn requested MAC address to lowercase
MAC=$(echo "$MAC" | tr '[A-Z]' '[a-z]')
local LOOP=0
while true; do
local IIFACE
for IIFACE in $(ls /sys/class/net); do
[ -f "/sys/class/net/$IIFACE/address" ] || continue
local CURMAC=$(cat "/sys/class/net/$IIFACE/address" | tr '[A-Z]' '[a-z]')
if [ "$CURMAC" = "$MAC" ]; then
NET="$IIFACE"
echo "Found network interface $NET with MAC address $MAC"
return 0
fi
done
[ $LOOP -eq 1 ] && echo "Waiting for network interface with MAC address $MAC"
LOOP=$(($LOOP + 1))
local WAITTIME=$(($(awk '{print $1*1000}' /proc/uptime) - $KERNEL_BOOT_TIME))
[ $WAITTIME -gt $((MNT_TIMEOUT * 1000)) ] && break
done
echo "Network interface with MAC address $MAC not found!"
}
# Mount non-volatile volume or NFS share
mkdir -p "${ROOTFS}/${MNTNV}" "${ROOTFS}/${MNTSQUASH}"
RETRYCOUNT=0
TRIEDDEVS=""
FOUNDDEV=""
while true; do
if [ "$NFSSHARE" ]; then
find_net_dev_from_mac
if [ -e "/sys/class/net/$NET" ]; then
echo "Obtaining DHCP lease for $NET..."
FOUNDDEV="$NET"
ifconfig "$NET" up || exec /bin/sh
udhcpc -n -T 1 -t 60 -q -i "$NET" || exec /bin/sh
mount -t nfs -o nolock "$NFSSHARE" "${ROOTFS}/${MNTNV}" || exec /bin/sh
mount_squash "$NFSSHARE" || exec /bin/sh
fi
else
[ -z "$PARTNUMBER" ] || P_PARTNUMBER="p$PARTNUMBER"
for DEVFILE in $(find /dev/ -name "[sh]d[a-z]${PARTNUMBER}*" \
-o -name "sr${PARTNUMBER}*" \
-o -name "mmcblk*${P_PARTNUMBER}*" \
-o -name "nvme*n*${P_PARTNUMBER}*"); do
echo "$TRIEDDEVS" | grep -q "$DEVFILE\>" && continue
mount $READONLY "$DEVFILE" "${ROOTFS}/${MNTNV}" 2>/dev/null || continue
TRIEDDEVS="$TRIEDDEVS $DEVFILE"
if [ -f "${ROOTFS}/${MNTNV}/${SQUASHFS_BIN}" ] && mount_squash "$DEVFILE"; then
echo "Found root device ${DEVFILE}"
[ -z "$READONLY" ] || echo "Mounted ${DEVFILE} as read-only"
FOUNDDEV="${DEVFILE}"
break
fi
umount "${ROOTFS}/${MNTNV}" || exec /bin/sh
done
fi
[ "$FOUNDDEV" ] && break
if [ $RETRYCOUNT -eq 0 ]; then
[ "$NFSSHARE" ] && echo "Ethernet device $NET not found. Waiting..."
[ -z "$NFSSHARE" ] && echo "Partition with root filesystem not found. Waiting..."
fi
WAITTIME=$(($(awk '{print $1*1000}' /proc/uptime) - $KERNEL_BOOT_TIME))
[ $WAITTIME -gt $(($MNT_TIMEOUT * 1000)) ] && ( echo "Giving up..." && exec /bin/sh )
RETRYCOUNT=$(($RETRYCOUNT+1))
done
# Create symlinks to the squashed root filesystem
cd "${ROOTFS}"
ln -s "${MNTSQUASH}/usr" usr
ln -s "${MNTSQUASH}/usr/bin" bin
ln -s "${MNTSQUASH}/usr/bin" sbin
ln -s "${MNTSQUASH}/usr/lib64" lib
ln -s "${MNTSQUASH}/usr/lib64" lib64
rm -f etc
# Create symlink to home dir
ln -s "${MNTNV}/home" home
# Determine location of upper /etc filesystem for overlayfs
CONFIG_DIR="${ROOTFS}/${MNTNV}/$(dirname "$SQUASHFS_BIN")"
# Mounts /etc using overlayfs
mount_overlay()
{
mount -t overlay -o "noatime,lowerdir=$1,upperdir=$2,workdir=$3" overlay etc
}
# Mounts /etc overlayfs using upper filesystem from config file
mount_overlay_from_config()
{
local ETCOVR
local LOWER
local UPPER
local WORK
if [ -f "$CONFIG_DIR/config" ]; then
ETCOVR="${ROOTFS}/${MNTETC}"
local RO=""
[ -z "$READONLY" ] || RO=",ro"
mkdir -p "$ETCOVR"
mount -o "loop$RO" "$CONFIG_DIR/config" "$ETCOVR" || return $?
if [ -z "$READONLY" ]; then
# config is writeable
LOWER="${ROOTFS}/${MNTSQUASH}/etc"
UPPER="${ETCOVR}/etc"
WORK="${ETCOVR}/work"
else
# config is read-only
LOWER="${ETCOVR}/etc:${ROOTFS}/${MNTSQUASH}/etc"
UPPER="${ROOTFS}/tmp/etc/etc"
WORK="${ROOTFS}/tmp/etc/work"
fi
else
echo "Persistent configuration not found, storing configuration in tmpfs"
LOWER="${ROOTFS}/${MNTSQUASH}/etc"
UPPER="${ROOTFS}/tmp/etc/etc"
WORK="${ROOTFS}/tmp/etc/work"
fi
mkdir -p "$UPPER" "$WORK"
local RET
RET=0
mount_overlay "$LOWER" "$UPPER" "$WORK" || RET=$?
[ $RET -eq 0 ] || umount "$ETCOVR"
return $RET
}
# Creates a clean configuration in upper filesystem
restore_previous_config()
{
if [ -n "$READONLY" ]; then
echo "Unable to restore configuration to a read-only filesystem"
return 1
fi
echo "Restoring previous configuration"
local ETCOVR
ETCOVR="${ROOTFS}/${MNTETC}"
mkdir -p "$ETCOVR"
mount -o loop "$CONFIG_DIR/config" "$ETCOVR" || return $?
mkdir -p /bak
cp -ar "${ETCOVR}/etc" /bak/
rm -rf "${ETCOVR}/etc" "${ETCOVR}/work"
mkdir -p "${ETCOVR}/etc" "${ETCOVR}/work"
local RET
RET=0
mount_overlay "${ROOTFS}/${MNTSQUASH}/etc" "${ETCOVR}/etc" "${ETCOVR}/work" || RET=$?
if [ $RET -ne 0 ]; then
umount "$ETCOVR"
return $RET
fi
cp -arv /bak/etc /
rm -rf /bak
return 0
}
# Set up /etc
OVROK=0
mkdir etc
ln -s /proc/mounts etc/mtab
if [ "$OVRCFG" != "0" ]; then
if [ ! -f "$CONFIG_DIR/config" ] && [ -f "$CONFIG_DIR/config.new" ]; then
cp "$CONFIG_DIR/config.new" "$CONFIG_DIR/config" || echo "Error: Failed to copy config.new"
fi
if mount_overlay_from_config; then
OVROK=1
else
echo "Error: Failed to mount configuration overlay"
if [ -f "$CONFIG_DIR/config" ]; then
if restore_previous_config; then
OVROK=1
else
echo "Error: Failed to restore previous configuration"
mv "$CONFIG_DIR/config" "$CONFIG_DIR/config.bad"
if [ -f "$CONFIG_DIR/config.new" ]; then
echo "Trying config.new"
cp "$CONFIG_DIR/config.new" "$CONFIG_DIR/config"
else
echo "Trying config in ramdisk"
fi
if mount_overlay_from_config; then
OVROK=1
else
echo "Error: Failed to mount backup configuration overlay"
fi
fi
fi
fi
fi
if [ "$OVROK" != "1" ]; then
echo "Copying configuration to ramdisk"
cp -a "${ROOTFS}/${MNTSQUASH}"/etc/* etc/
fi
# Mount boot partition
if [ "$PARTNUMBER" = "2" ] && [ -z "$NFSSHARE" ] && [ ! -f "${CONFIG_DIR}/kernel" ]; then
mkdir "${ROOTFS}/boot"
mount -o ro "${FOUNDDEV%2}1" "${ROOTFS}/boot"
fi
# Copy resolv.conf
[ "$NFSSHARE" ] && [ -f "/etc/resolv.conf" ] && cp /etc/resolv.conf etc/
# Update configuration of TTY based on console= setting
if [ "$CONSOLE_TTYS" != "" ] && grep -q "^::respawn:.*getty.*login_root\>" etc/inittab; then
RESPAWN=""
for TTY in $CONSOLE_TTYS; do
TTY_OPTS="${TTY#*,}"
TTY="${TTY%%,*}"
if echo "$TTY" | grep -q "^tty"; then
BAUD="${TTY_OPTS%%,*}"
echo "$BAUD" | grep -q "^[0-9]\+$" || BAUD=115200
TERM=vt102
CARRIER_DETECT="-L "
if echo "$TTY" | grep -q "^tty[1-9]$"; then
TERM=linux
CARRIER_DETECT=""
fi
[ "$RESPAWN" ] && RESPAWN="$RESPAWN\\n"
RESPAWN="$RESPAWN::respawn:\\/usr\\/bin\\/getty ${CARRIER_DETECT}-n -l \\/usr\\/bin\\/login_root $BAUD $TTY $TERM"
fi
done
if [ "$RESPAWN" ]; then
REPLACE_MATCH="::respawn:.*getty.*login_root"
# Delete duplicate respawn lines
sed -i "/$REPLACE_MATCH/{ x; /^$/! { x; d }; x; h; p; d }" etc/inittab
# Replace existing respawn line
sed -i "/$REPLACE_MATCH/s/.*/$RESPAWN/" etc/inittab
fi
fi
# Create necessary directories
mkdir dev
mkdir proc
mkdir root
mkdir sys
mkdir -p tmp
chmod 1777 tmp
mkdir -p var/tmp
chmod 1777 var/tmp
mkdir var/log
chmod 755 var/log
# Create basic device nodes
mknod dev/null c 1 3
mknod dev/console c 5 1
# Unmount filesystems
umount /dev
umount /sys
rm /etc/mtab
cp /proc/mounts /etc/mtab
umount /proc
# Store kernel boot time for reporting in /usr/bin/rc
echo "$KERNEL_BOOT_TIME" > var/log/kernel_boot_time
# Switch to the new root filesystem
exec /bin/busybox switch_root -c /dev/console "${ROOTFS}" /usr/bin/init
# Fallback - enter shell
exec /bin/busybox sh