-
Notifications
You must be signed in to change notification settings - Fork 4
/
Copy pathmake-lfs-iso
executable file
·595 lines (484 loc) · 18.9 KB
/
make-lfs-iso
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
378
379
380
381
382
383
384
385
386
387
388
389
390
391
392
393
394
395
396
397
398
399
400
401
402
403
404
405
406
407
408
409
410
411
412
413
414
415
416
417
418
419
420
421
422
423
424
425
426
427
428
429
430
431
432
433
434
435
436
437
438
439
440
441
442
443
444
445
446
447
448
449
450
451
452
453
454
455
456
457
458
459
460
461
462
463
464
465
466
467
468
469
470
471
472
473
474
475
476
477
478
479
480
481
482
483
484
485
486
487
488
489
490
491
492
493
494
495
496
497
498
499
500
501
502
503
504
505
506
507
508
509
510
511
512
513
514
515
516
517
518
519
520
521
522
523
524
525
526
527
528
529
530
531
532
533
534
535
536
537
538
539
540
541
542
543
544
545
546
547
548
549
550
551
552
553
554
555
556
557
558
559
560
561
562
563
564
565
566
567
568
569
570
571
572
573
574
575
576
577
578
579
580
581
582
583
584
585
586
587
588
589
590
591
592
593
594
595
#!/bin/bash -e
#*** CHANGE THIS VARIABLE EVERY TIME THE CLASS IS OFFERED ***
#This variable holds the name of the current release of the LFS book. The book
#will be installed on the CD for offline reading by the students.
export BOOK_ZIP='LFS-BOOK-7.4.tar.bz2'
#*** CHANGE THIS VARIABLE EVERY TIME THE CLASS IS OFFERED ***
#These are extra packages that make using the USB far
#easier. It also include the list of packages found in
#the LFS "Host System Requirements" section in the preface.
#Many of these are installed by default they are listed
#here for clarity. This leaves out *glibc* and the *kernel*
#because they are part of the base install and have no
#separate pacakges.
export EXTRAS='lxde-common lxterminal lxsession lxappearance lxrandr lxtask \
xorg tango-icon-theme iceweasel slim \
squashfs-tools build-essential bootcd syslinux network-manager \
bash binutils bison bzip2 coreutils diffutils findutils \
gawk gcc grep gzip m4 make patch perl sed tar texinfo \
xz-utils'
#This variable sets where the initial system files will be temporarily
#installed
export CHROOT='/media/chroot'
#This variable sets a directory that will temporarily hold the ISO system
#just before the file is built.
export ISO_BUILD='/media/iso'
#This is the final location for the ISO file
export ISO="$PWD/lfs-cd.iso"
#This variable sets the location of the default files directory which
#holds settings files for the new system. It is set relative to the
#directory containing this script.
export DEFFILES='def-files'
#This should be the architecture the new system
export ARCH='i386'
#The Ubuntu "code name" to use for setting up apt (leave it as is)
export CODE_NAME='saucy'
#The mirror to use for fetching the initial system files and for apt to use
#when installing packages
export MIRROR='http://archive.ubuntu.com/ubuntu'
#This mirror host security updates
export SEC_MIRROR="${MIRROR/archive/security}"
#This is the package name for the kernel the LiveCD will use
export KERNEL="linux-image-generic"
#These are the header files for the above kernel
export HEADERS="$(echo $KERNEL | sed 's/image/headers/')"
export LOG="$PWD/lfs-cd.log"
if [ -f $LOG ] ; then rm -f $LOG ; fi
#This function displays information messages using a green font.
#param: The message to display.
#usage: info "This is some information"
function info {
echo -e "\033[1;32m$@\033[0;49m"
echo "INFO: $@" >> $LOG
}
#This function displays warnings in a yellow font.
#param: The message to display.
#usage: warn "This is a warning"
function warn {
echo -e "\033[1;33mWARNING: $@\033[0;49m"
echo "WARNING: $@" >> $LOG
}
#This function is used to cleanly exit the script. It does this by unmounting
#all devices, displaying a given error message, and exiting with an error
#code.
#param: The error message to display.
#usage: die "This is an error"
function error_exit {
unmount_all
#Create the line of asterisks
stars=$( printf '%0.1s' "*"{1..75} )
printf "\n\033[1;31m$stars\n\n"
#Print out message, limit the line length to 70 chars
echo -e "$@" | fold -s -w 70
echo "DIE: $@" >> $LOG
printf "\n$stars\033[0;49m\n"
exit 1
}
#Trap the killer signals so that we can exit with a good message
trap "error_exit 'Received signal SIGHUP, exiting.'" SIGHUP
trap "error_exit 'Received signal SIGINT, exiting.'" SIGINT
trap "error_exit 'Received signal SIGTERM, exiting.'" SIGTERM
#Alias the function so that it will print a message with the following format:
#prog-name(@line#): message
#We have to explicitly allow aliases, we do this because they make calling the
#function much easier (see example)
shopt -s expand_aliases
alias die='error_exit "Error ${0}(@`echo $(( $LINENO - 1 ))`):"'
#This function checks that a given device or path is mounted, and if the
#parameter is, this function then unmounts it.
#param: A mount point or device file
#usage: unmount /some/directory
function unmount {
if grep -q $1 /etc/mtab ; then
if ! umount -v -f $1 ; then
warn "Failed to unmount $1, trying last resort unmount"
#Try lazy unmounting as a last resort
if ! umount -v -l $1 ; then
warn "Failed to unmount $1!"
else
warn "Lazy unmounted $1"
fi
else
info "Unmounted $1"
fi
else
info "$1 is not mounted"
fi
}
#This function unmounts all the mount-points created in this script.
#It is used to clean-up at the end or after an error occurs. This
#function does not check "devices" it instead calls the unmount
#function using mount points.
function unmount_all {
unmount $CHROOT/sys
unmount $CHROOT/proc
unmount $CHROOT/dev/pts
unmount $CHROOT/dev
unmount $CHROOT/tmp
if [[ ! -z "$MNT" ]] ; then
unmount "$MNT"
rmdir -v "$MNT" #MNT is a mktemp directory so get rid of it
fi
}
#See if we are the root user
if [[ "$UID" != "0" ]] ; then
die 'This script can only be run as root'
fi
#Set the build mode
BUILD="iso"
info "Will build the iso file: $ISO"
#Change the DEFFILES variable to an absolute directory
export DEFFILES="$(cd "$( dirname "${BASH_SOURCE[0]}" )" && pwd)/$DEFFILES"
if [[ ! -d $DEFFILES ]] ; then
die "The $DEFFILES directory does not exist, try changing the configuration value at the top of the script."
else
info "Will look for default files in $DEFFILES"
fi
if false ; then #DEBUG
#Make sure the mkisofs program is available so we can create the ISO file
if ! which mkisofs > /dev/null ; then
warn "The mkisofs program is not installed, installing it..."
if ! apt-get install -y genisoimage ; then
die "Could not install the genisoimage package (to get mkisofs)"
fi
fi
#Clear out the ISO build directory if it exists
if [[ -e "$ISO_BUILD" ]] ; then
info "Removing old ISO build directory"
rm -rf "$ISO_BUILD"
fi
info "Checking that the main apt mirror is working"
if ! wget "$MIRROR" -O /dev/null ; then
die "The mirror $MIRROR appears to be down or invalid"
else
info "Apt mirror is working"
fi
info "Checking the security updates mirror is working"
if ! wget "$SEC_MIRROR" -O /dev/null ; then
die "The mirror $SEC_MIRROR appears to be down or invalid"
else
info "Security mirror is working"
fi
info "Unmounting pseudo-filesystems if they are mounted from previous attempt"
unmount_all
#If the $CHROOT directory exits, destroy it so we have a clean slate.
if [ -d $CHROOT ] ; then
info "Clearing $CHROOT for a clean slate ..."
if ! rm -rf "$CHROOT" ; then
die "Could not remove the directory"
fi
fi
info "Creating the $CHROOT directory"
if ! mkdir -p "$CHROOT" ; then
die "Could not create the chroot directory at $CHROOT"
fi
#This program creates a minimal linux system
if [ ! -f /usr/sbin/debootstrap ] ; then
warn "Installing deboostrap so we can create a minimal system"
if ! apt-get -y install debootstrap ; then
die "Could not install debootstrap"
fi
fi
#Syslinux is going to be the boot loader, make sure it is available
if [ ! -e /usr/lib/syslinux/isolinux.bin ] ; then
warn "The syslinux package is not installed, installing it..."
if ! apt-get -y install syslinux; then
die "Could not install the syslinux package"
fi
fi
#Extlinux is the boot loader for USB installs
if ! which extlinux > /dev/null ; then
warn "The extlinux package is not installed, installing it..."
if ! apt-get -y install extlinux; then
die "Could not install the extlinux package"
fi
fi
info 'Bootstrapping in a basic system'
if ! /usr/sbin/debootstrap --arch "$ARCH" "$CODE_NAME" "$CHROOT" "$MIRROR" ; then
die 'Failed to bootstrap'
fi
#Copy the timezone info from the system to the new USB drive
if ! cp /etc/timezone "$CHROOT/etc/timezone" ; then
die 'Failed to update the /etc/timezone file'
fi
#Set some important networking configuration files
info "Set $CHROOT/etc/hostname"
HOST="usb"
if ! echo -n $HOST > $CHROOT/etc/hostname ; then
die "Failed to update the /etc/hostname file"
fi
if ! echo "127.0.0.1 localhost $HOST" > $CHROOT/etc/hosts ; then
die 'Failed to create the /etc/hosts file'
fi
info 'Creating the sources.list file for apt'
cat >$CHROOT/etc/apt/sources.list <<EOF
deb $MIRROR ${CODE_NAME} main restricted universe multiverse
deb $SEC_MIRROR ${CODE_NAME}-security main restricted universe multiverse
EOF
if [[ ! -e $CHROOT/etc/apt/sources.list ]] ; then
die "Failed to create $CHROOT/etc/apt/sources.list file"
fi
info "Installing root's bashrc file"
if ! sed "s|HTTP_CLIENT_SCRIPT|$HTTP_CLIENT_SCRIPT|" \
$DEFFILES/bashrc > $CHROOT/root/.bashrc ; then
die "Could not install the bashrc file"
#Double check sed worked correctly
elif ! grep -q "$HTTP_CLIENT_SCRIPT" $CHROOT/root/.bashrc ; then
die "Failed to add the mirror \"$HTTP_CLIENT_SCRIPT\" to the bashrc script"
fi
info "Mounting the needed directories under $CHROOT"
if ! (mount -v --bind /dev $CHROOT/dev &&
mount -vt devpts devpts $CHROOT/dev/pts -o gid=5,mode=620 &&
mount -vt proc proc $CHROOT/proc &&
mount -vt sysfs sysfs $CHROOT/sys &&
mount -vt tmpfs tmpfs $CHROOT/tmp ) ; then
die 'A mount failed!'
fi
fi #DEBUG
info "Copying over needed files from $DEFFILES"
if ! cp -v $DEFFILES/fstab $CHROOT/etc/fstab ; then
die "Failed to create $CHROOT/etc/fstab file"
elif ! cp -v $DEFFILES/kernel-img.conf $CHROOT/etc/kernel-img.conf ; then
die "Failed to copy the $CHROOT/etc/kernel-img.conf file"
elif ! cp -v $DEFFILES/vimrc $CHROOT/root/.vimrc ; then
die "Failed to copy the $CHROOT/root/.vimrc file"
elif ! cp $CHROOT/root/.vimrc $CHROOT/etc/skel/ ; then
die "Failed to copy the .vimrc file to $CHROOT/etc/skel"
elif ! cp -v $DEFFILES/preselects $CHROOT/root/conf ; then
die "Failed to copy the pre-selections file."
fi
info 'Creating an installer script for chroot'
if ! cat > $CHROOT/chroot-install <<EOF
#!/bin/bash -e
function info {
echo -e "\033[1;34m\$@\033[0;49m"
}
function die {
echo -e "\n\033[1;31m\$@\033[0;49m"
exit 128
}
info "Beginning chroot install"
#Unmount the directories when exiting out
trap "{ umount -lv /proc /sys /tmp /dev; exit 255 }" SIGINT SIGTERM
info "Setting local time"
ln -svf /usr/share/zoneinfo/US/Central /etc/localtime
info 'Setting up the root user'
if grep -q admin /etc/group ; then
sed -i '/^admin.*$/d' /etc/group
fi
groupadd admin
usermod -a -G 'users,plugdev,audio,cdrom,admin,disk' root
passwd -d root #Make root have no password
info 'Preseeding for apt'
if ! debconf-set-selections /root/conf ; then
die "Failed to preseed apt"
fi
rm -v /root/conf
#export DEBIAN_FRONTEND=noninteractive
apt-get clean
apt-get update || apt-get update
if ! apt-get -y --no-install-recommends install $KERNEL ; then
die "Failed to install the kernel"
fi
if ! apt-get -y install $HEADERS dhcpcd squashfs-tools \
dialog mingetty vim-nox wget jfsutils \
parted gpm laptop-detect debootstrap less \
initramfs-tools live-boot locales \
debconf-utils hicolor-icon-theme $EXTRAS ; then
die "Failed to install all of the required software"
fi
#Try installing Virtualbox's Guest additions in case
#we use the system in a VM
info "Installing Virtualbox's Guest Additions"
wget -q http://download.virtualbox.org/virtualbox/debian/oracle_vbox.asc -O- | sudo apt-key add - && apt-get update && apt-get -y install virtualbox-guest-utils
info "Updating the system"
apt-get -y dist-upgrade && apt-get -y autoremove
info "Cleaning up after apt"
apt-get -y clean
#Force a black listing of the old pc-speaker driver
echo blacklist snd-pcsp >> /etc/modprobe.d/blacklist.conf
info Fixing sudoers file
if ! cp -v /etc/sudoers /tmp/sudoers.tmp ; then
die 'Could not copy sudoers to begin no password change'
elif ! sed -i 's/^%admin.*$/%admin ALL=NOPASSWD:ALL/' /tmp/sudoers.tmp ; then
die 'Could not replace ALL with NOPASSWD field in admin.'
elif ! sed -i 's/^%sudo.*$/%sudo ALL=NOPASSWD:ALL/' /tmp/sudoers.tmp ; then
die 'Could not replace ALL with NOPASSWD field in sudoers.'
elif ! mv -v /tmp/sudoers.tmp /etc/sudoers ; then
die 'Could not replace sudoers file with new one.'
fi
info "Making root own /root"
chown -R root:root /root
info "Fixing the path"
#Make mingetty auto-login on tty1
sed 's|^exec.*$|exec /sbin/mingetty --autologin root --noclear tty1|' -i /etc/init/tty1.conf
info "Finished chroot script sucessfully"
exit 0
EOF
then
die "Could not create the script that manages the chroot install."
fi
#Make the install script executable
if ! chmod u+x $CHROOT/chroot-install ; then
die "Could not make the chroot install script executable."
fi
info 'Performing chroot install ...'
if ! LANG=C chroot $CHROOT /chroot-install ; then
die "Chroot install failed!"
fi
#For some reason the chroot changes the host environment's hostname
#value. This is to change it back.
info "Fixing host's hostname"
if ! hostname $( cat /etc/hostname ) ; then
warn "Could not fix host environment's hostname"
fi
#Cleanup the install script
if ! rm $CHROOT/chroot-install ; then
warn "Failed to remove the chroot-install script"
fi
info 'Setting up the defults for the LXDE desktop'
if [ ! -d "$CHROOT/root/.config" ] ; then
if ! mkdir -vp "$CHROOT/root/.config" ; then
die "Failed to make the desktop setup directory $CHROOT/root/.config"
fi
fi
if ! tar xf "$DEFFILES/lxconfig.tar.bz2" -C "$CHROOT/root/.config" ; then
die "Could not install the desktop configuration files"
fi
info Setting slim to auto-login
cat >> $CHROOT/etc/slim.conf <<EOF
default_user root
auto_login yes
EOF
#Switch the the root user's desktop to make things easier
if [ ! -d $CHROOT/root/Desktop ] ; then
mkdir -p $CHROOT/root/Desktop
fi
pushd $CHROOT/root/Desktop > /dev/null
if [ -d './LFS' ] ; then
rm -rf './LFS'
fi
info 'Downloading and installing the LFS book for off line reading.'
if ! wget "http://www.linuxfromscratch.org/lfs/downloads/stable/$BOOK_ZIP" ;
then
die 'Failed to download the LFS book'
fi
if ! tar xf "$BOOK_ZIP"; then
die 'Failed to unarchive the book file'
fi
if ! rm -vf "$BOOK_ZIP" ; then
warn "Could not remove the $BOOK_ZIP file."
fi
if ! mv "$(find . -maxdepth 1 -type d | tail -n 1)" "LFS" ; then
warn 'Failed to rename the unzipped book directory to LFS'
fi
info "Creating a webpage that redirects to the class' Notes website"
if ! cp -v "$DEFFILES/notes.html" "Class Notes.html" ; then
die "Could not place the Class Notes.html file on the desktop"
fi
#Return to the original directory
popd > /dev/null
#udev is attached to *this* machine's network card now.
#Get rid of this rule to make udev think it is a brand new install
info 'Fixing udev network card rules'
if [ -e /media/chroot/etc/udev/rules.d/70-persistent-net.rules ] && \
! rm /media/chroot/etc/udev/rules.d/70-persistent-net.rules ; then
warn "Could not fix network card udev rules"
fi
#By default the interfaces file has allow-hotplug instead of
#the auto keyword. The allow-hotplug won't allow the network
#card to start. We need the interfaces file to be modified
#before ifup is executed. So we will rewrite part of the
#networking startup script to fix the interfaces file
#just before ifup is executed.
info "Fixing network startup script"
awk "
/ifup -a/ {
print \"\tsed 's/allow-hotplug/auto/' /etc/network/interfaces > /tmp/interfaces\" ;
print \"\tmv /tmp/interfaces /etc/network/interfaces\"
}
{print \$0}" "$CHROOT/etc/init.d/networking" > /tmp/networking
mv -v "/tmp/networking" "$CHROOT/etc/init.d/networking"
chmod -v 755 "$CHROOT/etc/init.d/networking"
#We will shrink the size of the ISO by zeroing out documentation
#and log files.
info 'Discovering what files to zero out...'
if ! (find $CHROOT/usr/share/doc -type f -size +1b > /tmp/commit_zerosize &&
find $CHROOT/usr/share/man -type f -size +1b >> /tmp/commit_zerosize &&
find $CHROOT/usr/share/info -type f -size +1b >> /tmp/commit_zerosize &&
find $CHROOT/var/log -type f -size +1b >> /tmp/commit_zerosize ) ; then
die "Could not find files to zero out"
fi
info 'Making the man, doc, and info files have zero size ...'
NFILES="$(wc -l /tmp/commit_zerosize | awk '{ print $1 }')"
i=1
cat /tmp/commit_zerosize | while read file ; do
echo -n -e "\tZeroing $i/$NFILES files\r"
rm $file
touch $file
i=$[i + 1]
done ; echo
#Get rid of any left over deb files to further reduce the ISO size
info 'Getting rid of any left over deb files'
rm -rf $CHROOT/var/cache/apt/archives/*
info "Creating the root user's Desktop directory"
if [ ! -d "$CHROOT/root/Desktop" ] ; then
mkdir "$CHROOT/root/Desktop"
fi
#Tell squashfs not to include these files or directories
info 'Creating directory-exclusion file'
if ! cp -v "$DEFFILES/exclude" "$CHROOT/tmp/exclude" ; then
die 'Could not install the squashfs exclusion file'
fi
info 'Creating the file system file.'
if ! chroot "$CHROOT" /usr/bin/mksquashfs / /filesystem.squashfs -noappend -always-use-fragments -wildcards -ef /tmp/exclude -processors 4; then
die "Failed to squash the file system."
fi
#fi #DEBUG
##########################################################################
#
# Create ISO Image File
#
##########################################################################
info "Creating directories for the ISO image."
if ! mkdir -pv "$ISO_BUILD"/{isolinux,live,boot} ; then
die "Could not create directories for ISO filesystem at $ISO_BUILD"
fi
info "Installing $ISO files for booting"
if ! cp -v "$CHROOT/filesystem.squashfs" "$ISO_BUILD/live/" ; then
die "Could not copy the filesystem.squashfs file to the CD."
elif ! cp -vR "$CHROOT/boot" "$ISO_BUILD/" ; then
die "Could not copy the boot directory."
fi
#Install the boot loader
info 'Installing the bootloader files'
if ! cp -v /usr/lib/syslinux/isolinux.bin "$ISO_BUILD/isolinux" ; then
die "Could not install the isolinux bootloader"
fi
#mkisofs borks file names with hyphens, it silently changes them to
#underscore characters. We have to take this into account below.
#That is the reason for the sed pipeline in this config file.
info "Creating the isolinux configuration file"
pushd $CHROOT > /dev/null
info "Install the isolinux.cfg file"
if ! cp -v "$DEFFILES/isolinux.cfg" "$ISO_BUILD/isolinux/isolinux.cfg" ; then
die "Could not install the boot loader configuration file"
fi
info "Puting actual file names in isolinux.cfg"
sed -i -e "s/vmlinuz/$(basename $ISO_BUILD/boot/vmlinuz* | tr - _)/" \
-e "s/initrd/$(basename $ISO_BUILD/boot/initrd* | tr - _)/" \
"$ISO_BUILD/isolinux/isolinux.cfg"
ISOTMP="$(dirname $ISO)/temp-$(basename $ISO)"
info "Creating the iso file $ISOTMP"
if mkisofs -o "$ISOTMP" -allow-multidot \
-l -b isolinux/isolinux.bin -c isolinux/boot.cat \
-no-emul-boot -boot-load-size 4 -boot-info-table \
"$ISO_BUILD" ; then
info "Created the ISO file"
else
die "Failed to create the ISO file"
fi
info "Installing ISO at the final location"
mv -v "$ISOTMP" "$ISO"
info 'Installation Finished Successfully!!!'
info "ISO file $ISO"