-
Notifications
You must be signed in to change notification settings - Fork 15
/
donya.sh
620 lines (398 loc) · 17.9 KB
/
donya.sh
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
596
597
598
599
600
601
602
603
604
605
606
607
608
609
610
611
612
613
614
615
616
617
618
619
620
# shellcheck disable=SC2148
# 1. Configuring the Environment
# turn on Bash hash functions
set +h
# Make sure that newly created files/directories are writable only by the owner (for example, the currently logged in user account)
umask 022
# Use your home directory as the main build directory
# shellcheck disable=SC2155
export donyaOS=$(pwd)/donyaOS
mkdir -pv "${donyaOS}"
export LC_ALL=POSIX
export PATH=${donyaOS}/cross-tools/bin:/bin:/usr/bin
# Create the target image's filesystem hierarchy
# This directory tree is based on the Filesystem Hierarchy Standard (FHS), which is defined and hosted by the Linux Foundation
mkdir -pv "${donyaOS}"/{bin,boot{,grub},dev,{etc/,}opt,home,lib/{firmware,modules},lib64,mnt}
mkdir -pv "${donyaOS}"/{proc,media/{floppy,cdrom},sbin,srv,sys}
mkdir -pv "${donyaOS}"/var/{lock,log,mail,run,spool}
mkdir -pv "${donyaOS}"/var/{opt,cache,lib/{misc,locate},local}
install -dv -m 0750 "${donyaOS}"/root
install -dv -m 1777 "${donyaOS}"{/var,}/tmp
install -dv "${donyaOS}"/etc/init.d
mkdir -pv "${donyaOS}"/usr/{,local/}{bin,include,lib{,64},sbin,src}
mkdir -pv "${donyaOS}"/usr/{,local/}share/{doc,info,locale,man}
mkdir -pv "${donyaOS}"/usr/{,local/}share/{misc,terminfo,zoneinfo}
mkdir -pv "${donyaOS}"/usr/{,local/}share/man/man{1,2,3,4,5,6,7,8}
for dir in ${donyaOS}/usr{,/local}; do
ln -sv share/{man,doc,info} "${dir}"
done
# Create the directory for a cross-compilation toolchain
install -dv "${donyaOS}"/cross-tools{,/bin}
# Use a symlink to /proc/mounts to maintain a list of mounted filesystems properly in the /etc/mtab file
ln -svf /proc/mounts "${donyaOS}"/etc/mtab
# Then create the /etc/passwd file, listing the root user account (note: for now, you won't be setting the account password; you'll do that after booting up into the target image for the first time)
cat > "${donyaOS}"/etc/passwd << "EOF"
root::0:0:root:/root:/bin/ash
EOF
# Create the /etc/group file with the following command:
cat > "${donyaOS}"/etc/group << "EOF"
root:x:0:
bin:x:1:
sys:x:2:
kmem:x:3:
tty:x:4:
daemon:x:6:
disk:x:8:
dialout:x:10:
video:x:12:
utmp:x:13:
usb:x:14:
EOF
# The target system's /etc/fstab
cat > "${donyaOS}"/etc/fstab << "EOF"
# file system mount-point type options dump fsck
# order
rootfs / auto defaults 1 1
proc /proc proc defaults 0 0
sysfs /sys sysfs defaults 0 0
devpts /dev/pts devpts gid=4,mode=620 0 0
tmpfs /dev/shm tmpfs defaults 0 0
EOF
# The target system's /etc/profile to be used by the Almquist shell (ash) once the user is logged in to the target machine
cat > "${donyaOS}"/etc/profile << "EOF"
export PATH=/bin:/usr/bin
if [ `id -u` -eq 0 ] ; then
PATH=/bin:/sbin:/usr/bin:/usr/sbin
unset HISTFILE
fi
# Set up some environment variables.
export USER=`id -un`
export LOGNAME=$USER
export HOSTNAME=`/bin/hostname`
export HISTSIZE=1000
export HISTFILESIZE=1000
export PAGER='/bin/more '
export EDITOR='/bin/vi'
EOF
# The target machine's hostname (you can change this any time):
echo "donyaOS-machine" > "${donyaOS}"/etc/HOSTNAME
# And, /etc/issue, which will be displayed prominently at the login prompt:
cat > "${donyaOS}"/etc/issue<< "EOF"
donyaOS 0.001a
Kernel \r on an \m
EOF
# You won't use systemd here (this wasn't a political decision; it's due to convenience and for simplicity's sake). Instead, you'll use the basic init process provided by BusyBox. This requires that you define an /etc/inittab file:
cat > "${donyaOS}"/etc/inittab<< "EOF"
::sysinit:/etc/rc.d/startup
tty1::respawn:/sbin/getty 38400 tty1
tty2::respawn:/sbin/getty 38400 tty2
tty3::respawn:/sbin/getty 38400 tty3
tty4::respawn:/sbin/getty 38400 tty4
tty5::respawn:/sbin/getty 38400 tty5
tty6::respawn:/sbin/getty 38400 tty6
::shutdown:/etc/rc.d/shutdown
::ctrlaltdel:/sbin/reboot
EOF
# Also as a result of leveraging BusyBox to simplify some of the most common Linux system functionality # you'll use mdev instead of udev, which requires you to define the following /etc/mdev.conf file:
cat > "${donyaOS}"/etc/mdev.conf<< "EOF"
# Devices:
# Syntax: %s %d:%d %s
# devices user:group mode
# null does already exist; therefore ownership has to
# be changed with command
null root:root 0666 @chmod 666 $MDEV
zero root:root 0666
grsec root:root 0660
full root:root 0666
random root:root 0666
urandom root:root 0444
hwrandom root:root 0660
# console does already exist; therefore ownership has to
# be changed with command
console root:tty 0600 @mkdir -pm 755 fd && cd fd && for x in 0 1 2 3 ; do ln -sf /proc/self/fd/$x $x; done
kmem root:root 0640
mem root:root 0640
port root:root 0640
ptmx root:tty 0666
# ram.*
ram([0-9]*) root:disk 0660 >rd/%1
loop([0-9]+) root:disk 0660 >loop/%1
sd[a-z].* root:disk 0660 */lib/mdev/usbdisk_link
hd[a-z][0-9]* root:disk 0660 */lib/mdev/ide_links
tty root:tty 0666
tty[0-9] root:root 0600
tty[0-9][0-9] root:tty 0660
ttyO[0-9]* root:tty 0660
pty.* root:tty 0660
vcs[0-9]* root:tty 0660
vcsa[0-9]* root:tty 0660
ttyLTM[0-9] root:dialout 0660 @ln -sf $MDEV modem
ttySHSF[0-9] root:dialout 0660 @ln -sf $MDEV modem
slamr root:dialout 0660 @ln -sf $MDEV slamr0
slusb root:dialout 0660 @ln -sf $MDEV slusb0
fuse root:root 0666
# misc stuff
agpgart root:root 0660 >misc/
psaux root:root 0660 >misc/
rtc root:root 0664 >misc/
# input stuff
event[0-9]+ root:root 0640 =input/
ts[0-9] root:root 0600 =input/
# v4l stuff
vbi[0-9] root:video 0660 >v4l/
video[0-9] root:video 0660 >v4l/
# load drivers for usb devices
usbdev[0-9].[0-9] root:root 0660 */lib/mdev/usbdev
usbdev[0-9].[0-9]_.* root:root 0660
EOF
# You'll need to create a /boot/grub/grub.cfg for the GRUB bootloader that will be installed on the target machine's physical or virtual HDD (note: the kernel image defined in this file needs to reflect the image built and installed on the target machine):
### This is what I add
mkdir "${donyaOS}"/boot/grub/
###$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$
cat > "${donyaOS}"/boot/grub/grub.cfg<< "EOF"
set default=0
set timeout=5
insmod part_msdos
insmod ext2
set root='hd0,msdos1'
menuentry "donyaOS 0.001a" {
linux /boot/vmlinuz-5.8.0 root=/dev/sdb1 ro quiet
}
EOF
# Finally, initialize the log files and give them proper permissions:
touch "${donyaOS}"/var/run/utmp "${donyaOS}"/var/log/{btmp,lastlog,wtmp}
chmod -v 664 "${donyaOS}"/var/run/utmp "${donyaOS}"/var/log/lastlog
# 2. Build the Cross Compiler
#################################
#Extract#########################
#################################
base_dir=$(pwd)
## Create directories
mkdir -p "$base_dir"/{packages,extracted}
## download dependencies
wget -nc -i packages-list.txt -P packages/
# busybox
tar -xvf "$base_dir/packages/busybox-1.32.0.tar.bz2" -C "$base_dir/extracted"
# linux
tar -xvf "$base_dir/packages/linux-5.8.tar.xz" -C "$base_dir/extracted"
# init
tar -xvf "$base_dir/packages/clfs-embedded-bootscripts-1.0-pre5.tar.bz2" -C "$base_dir/extracted"
# binutils
tar -xvf "$base_dir/packages/binutils-2.35.tar.xz" -C "$base_dir/extracted"
# gcc
tar -xvf "$base_dir/packages/gcc-10.2.0.tar.xz" -C "$base_dir/extracted"
# gmp
tar -xvf "$base_dir/packages/gmp-6.2.0.tar.xz" -C "$base_dir/extracted"
# mpfr
tar -xvf "$base_dir/packages/mpfr-4.1.0.tar.xz" -C "$base_dir/extracted"
# mpc
tar -xvf "$base_dir/packages/mpc-1.1.0.tar.gz" -C "$base_dir/extracted"
# glibc
tar -xvf "$base_dir/packages/glibc-2.32.tar.xz" -C "$base_dir/extracted"
# zlib
tar -xvf "$base_dir/packages/zlib-1.2.11.tar.gz" -C "$base_dir/extracted"
###########################################################################
unset CFLAGS
unset CXXFLAGS
# define the most vital parts of the host/target variables needed to create the cross-compiler toolchain and target image:
# shellcheck disable=SC2155,SC2001
export donyaOS_HOST=$(echo "${MACHTYPE}" | sed "s/-[^-]*/-cross/")
export donyaOS_TARGET=x86_64-unknown-linux-gnu
export donyaOS_CPU=k8
# shellcheck disable=SC2155
export donyaOS_ARCH=$(echo ${donyaOS_TARGET} | sed -e 's/-.*//' -e 's/i.86/i386/')
export donyaOS_ENDIAN=little
###########################################################################
# # Kernel Headers
# # The kernel's standard header files need to be installed for the cross compiler. Uncompress the kernel tarball and change into its directory. Then run:
echo "########Compile linux##########"
cd "$base_dir/extracted" || exit 1
cd linux* || exit 1
## speed Up make
NB_CORES=$(grep -c '^processor' /proc/cpuinfo)
export MAKEFLAGS="-j$((NB_CORES+1)) -l${NB_CORES}"
###Headers
# make clean
make mrproper
make ARCH="${donyaOS_ARCH}" headers_check
make ARCH="${donyaOS_ARCH}" INSTALL_HDR_PATH=dest headers_install
cp -rv dest/include/* "${donyaOS}"/usr/include
############################################
# Binutils
# Binutils contains a linker, assembler and other tools needed to handle compiled object files. Uncompress the tarball. Then create the binutils-build directory and change into it:
cd "$base_dir/extracted" || exit 1
# cd binutils* || exit 1
mkdir binutils-build
cd binutils-build/ || exit
../binutils-2.35/configure --prefix="${donyaOS}"/cross-tools \
--target=${donyaOS_TARGET} --with-sysroot="${donyaOS}" \
--disable-nls --enable-shared --disable-multilib
make configure-host && make
ln -sv lib "${donyaOS}"/cross-tools/lib64
make install
# Copy over the following header file to the target's filesystem:
cp -v ../binutils-2.35/include/libiberty.h "${donyaOS}"/usr/include
#GCC (Static)
# Before building the final cross-compiler toolchain, you first must build a statically compiled toolchain to build the C library (glibc) to which the final GCC cross compiler will link.
# Uncompress the GCC tarball, and then uncompress the following packages and move them into the GCC root directory:
cd "$base_dir/extracted" || exit 1
cp -r gmp* gcc-10.2.0/gmp
cp -r mpfr* gcc-10.2.0/mpfr
cp -r mpc* gcc-10.2.0/mpc
mkdir gcc-static
cd gcc-static/ || exit
AR=ar LDFLAGS="-Wl,-rpath,${donyaOS}/cross-tools/lib" \
../gcc-10.2.0/configure --prefix="${donyaOS}"/cross-tools \
--build="${donyaOS_HOST}" --host="${donyaOS_HOST}" \
--target=${donyaOS_TARGET} \
--with-sysroot="${donyaOS}"/target --disable-nls \
--disable-shared \
--with-mpfr-include=../gcc-10.2.0/mpfr/src \
--with-mpfr-lib=../gcc-10.2.0/mpfr/src/.libs \
--without-headers --with-newlib --disable-decimal-float \
--disable-libgomp --disable-libmudflap --disable-libssp \
--disable-threads --enable-languages=c,c++ \
--disable-multilib --with-arch=${donyaOS_CPU}
make all-gcc all-target-libgcc && \
make install-gcc install-target-libgcc
ln -vs libgcc.a "$(${donyaOS_TARGET}-gcc -print-libgcc-file-name | sed 's/libgcc/&_eh/')"
# Glibc
# Uncompress the glibc tarball. Then create the glibc-build directory and change into it:
cd "$base_dir/extracted" || exit 1
mkdir glibc-build
cd glibc-build/ || exit
# Configure the following build flags:
echo "libc_cv_forced_unwind=yes" > config.cache
# shellcheck disable=SC2129
echo "libc_cv_c_cleanup=yes" >> config.cache
echo "libc_cv_ssp=no" >> config.cache
echo "libc_cv_ssp_strong=no" >> config.cache
BUILD_CC="gcc" CC="${donyaOS_TARGET}-gcc" \
AR="${donyaOS_TARGET}-ar" \
RANLIB="${donyaOS_TARGET}-ranlib" CFLAGS="-O2" \
../glibc-2.32/configure --prefix=/usr \
--host=${donyaOS_TARGET} --build="${donyaOS_HOST}" \
--disable-profile --enable-add-ons --with-tls \
--enable-kernel=2.6.32 --with-__thread \
--with-binutils="${donyaOS}"/cross-tools/bin \
--with-headers="${donyaOS}"/usr/include \
--cache-file=config.cache
make && make install_root="${donyaOS}"/ install
# This part problematic but work if copy paste commands
# GCC (Final)
# As I mentioned previously, you'll now build the final GCC cross compiler that will link to the C library built and installed in the previous step. Create the gcc-build directory and change into it:
cd "$base_dir/extracted" || exit 1
mkdir gcc-build
cd gcc-build/ || exit
AR=ar LDFLAGS="-Wl,-rpath,${donyaOS}/cross-tools/lib" \
../gcc-10.2.0/configure --prefix="${donyaOS}"/cross-tools \
--build="${donyaOS_HOST}" --target=${donyaOS_TARGET} \
--host="${donyaOS_HOST}" --with-sysroot="${donyaOS}" \
--disable-nls --enable-shared \
--enable-languages=c,c++ --enable-c99 \
--enable-long-long \
--with-mpfr-include="$(pwd)"/../gcc-10.2.0/mpfr/src \
--with-mpfr-lib="$(pwd)"/mpfr/src/.libs \
--disable-multilib --with-arch=${donyaOS_CPU}
make && make install
cp -v "${donyaOS}"/cross-tools/${donyaOS_TARGET}/lib64/libgcc_s.so.1 "${donyaOS}"/lib64
###################################################################################################
#3. Building the Target Image
# The hard part is now complete—you have the cross compiler. Now, let's focus on building the components that will be installed on the target image. This includes various libraries and utilities and, of course, the Linux kernel itself.
# BusyBox
# Uncompress the tarball and change into its directory. Then load the default compilation configuration template:
cd "$base_dir/extracted" || exit 1
cd busybox* || exit
make CROSS_COMPILE="${donyaOS_TARGET}-" defconfig
make CROSS_COMPILE="${donyaOS_TARGET}-"
make CROSS_COMPILE="${donyaOS_TARGET}-" CONFIG_PREFIX="${donyaOS}" install
# Install the following Perl script, as you'll need it for the kernel build below:
cp -v examples/depmod.pl "${donyaOS}"/cross-tools/bin
chmod 755 "${donyaOS}"/cross-tools/bin/depmod.pl
## The Linux Kernel
# Change into the kernel package directory and run the following to set the default x86-64 configuration template:
cd "$base_dir/extracted" || exit 1
cd linux* || exit
make ARCH="${donyaOS_ARCH}" \
CROSS_COMPILE=${donyaOS_TARGET}- x86_64_defconfig
make ARCH="${donyaOS_ARCH}" CROSS_COMPILE=${donyaOS_TARGET}-
make ARCH="${donyaOS_ARCH}" CROSS_COMPILE=${donyaOS_TARGET}- \
INSTALL_MOD_PATH="${donyaOS}" modules_install
# You'll need to copy a few files into the /boot directory for GRUB:
cp -v arch/x86/boot/bzImage "${donyaOS}"/boot/vmlinuz-5.8.0
cp -v System.map "${donyaOS}"/boot/System.map-5.8.0
cp -v .config "${donyaOS}"/boot/config-5.8.0
# Then run the previously installed Perl script provided by the BusyBox package:
"${donyaOS}"/cross-tools/bin/depmod.pl \
-F "${donyaOS}"/boot/System.map-5.8.0 \
-b "${donyaOS}"/lib/modules/5.8.0
#####################################################################################
# The Bootscripts
cd "$base_dir/extracted" || exit
cd clfs* || exit
# copy edited Make
cp "$base_dir"/Makefile "$base_dir/extracted"/clfs*
make DESTDIR="${donyaOS}"/ install-bootscripts
ln -sv ../rc.d/startup "${donyaOS}"/etc/init.d/rcS
#####################################################################################
# Zlib
# Uncompress the Zlib tarball and change into its directory. Then configure, build and install the package:
cd "$base_dir/extracted" || exit
cd zlib* || exit
sed -i 's/-O3/-Os/g' configure
./configure --prefix=/usr --shared
make && make DESTDIR="${donyaOS}"/ install
# Now, because some packages may look for Zlib libraries in the /lib directory instead of the /lib64 directory, apply the following changes:
mv -v "${donyaOS}"/usr/lib/libz.so.* "${donyaOS}"/lib
ln -svf ../../lib/libz.so.1 "${donyaOS}"/usr/lib/libz.so
ln -svf ../../lib/libz.so.1 "${donyaOS}"/usr/lib/libz.so.1
ln -svf ../lib/libz.so.1 "${donyaOS}"/lib64/libz.so.1
#####################################################################################
# 4. Installing the Target Image
# All of the cross compilation is complete. Now you have everything you need to install the entire cross-compiled operating system to either a physical or virtual drive, but before doing that, let's not tamper with the original target build directory by making a copy of it:
mkdir -pv "${donyaOS}"-copy
cp -rf "${donyaOS}"/* "${donyaOS}"-copy
rm -rfv "${donyaOS}"-copy/cross-tools
rm -rfv "${donyaOS}"-copy/usr/src/*
# Followed by the now unneeded statically compiled library files (if any):
FILES="$(ls "${donyaOS}"-copy/usr/lib64/*.a)"
for file in $FILES; do
rm -f "$file"
done
# Now strip all debug symbols from the installed binaries. This will reduce overall file sizes and keep the target image's overall footprint to a minimum:
find "${donyaOS}"-copy/{,usr/}{bin,lib,sbin} -type f -exec sudo strip --strip-debug '{}' ';'
find "${donyaOS}"-copy/{,usr/}lib64 -type f -exec sudo strip --strip-debug '{}' ';'
# Finally, change file ownerships and create the following nodes:
sudo chown -R root:root "${donyaOS}"-copy
sudo chgrp 13 "${donyaOS}"-copy/var/run/utmp "${donyaOS}"-copy/var/log/lastlog
sudo mknod -m 0666 "${donyaOS}"-copy/dev/null c 1 3
sudo mknod -m 0600 "${donyaOS}"-copy/dev/console c 5 1
sudo chmod 4755 "${donyaOS}"-copy/bin/busybox
# Change into the target copy directory to create a tarball of the entire operating system image:
cd "${donyaOS}"-copy/ || exit
sudo tar cfJ ../donyaOS-build.tar.xz ./*
#########################################################################################################
# Finish creating donyaOS
#########################################################################################################
# # Notice how the target image is less than 60MB. You built that—a minimal Linux operating system that occupies less than 60MB of disk space:
# sudo du -h|tail -n1
# And, that same operating system compresses to less than 20MB:
# ls -lh ../donyaOS-build*
#####################
# separate last steps
# 5. Create partition and boot
# cat /proc/partitions
# lsblk
# use `/dev/sdb` to boot OS
# Create a partition on it
# sudo fdisk -l /dev/sdb , fdisk or parted
# Format
# sudo umount /dev/sdb1
# sudo mkfs.ext4 /dev/sdb1
# sudo mkdir "$base_dir"/donya_release/
# sudo mount /dev/sdb1 "$base_dir"/donya/
# sudo tar xJf ${base_dir}/donyaOS-build.tar.xz -C "$base_dir"/donya/
# sudo grub-install --root-directory="$base_dir"/donya/ /dev/sdb
# # # Booting Up the OS
# sudo qemu-system-x86_64 /dev/sdb
# username: root