OSDN Git Service

Merge branch 'i3' into dev
[alterlinux/alterlinux.git] / build.sh
1 #!/usr/bin/env bash
2 #
3 # Yamada Hayao
4 # Twitter: @Hayao0819
5 # Email  : hayao@fascode.net
6 #
7 # (c) 2019-2020 Fascode Network.
8 #
9 # build.sh
10 #
11 # The main script that runs the build
12 #
13
14 set -e
15 set -u
16
17 # Internal config
18 # Do not change these values.
19 script_path="$(readlink -f ${0%/*})"
20 defaultconfig="${script_path}/default.conf"
21 rebuild=false
22 customized_username=false
23
24
25 # Load config file
26 if [[ -f "${defaultconfig}" ]]; then
27     source "${defaultconfig}"
28 else
29     echo "${defaultconfig} was not found."
30     exit 1
31 fi
32
33
34 umask 0022
35
36
37 # Color echo
38 # usage: echo_color -b <backcolor> -t <textcolor> -d <decoration> [Text]
39 #
40 # Text Color
41 # 30 => Black
42 # 31 => Red
43 # 32 => Green
44 # 33 => Yellow
45 # 34 => Blue
46 # 35 => Magenta
47 # 36 => Cyan
48 # 37 => White
49 #
50 # Background color
51 # 40 => Black
52 # 41 => Red
53 # 42 => Green
54 # 43 => Yellow
55 # 44 => Blue
56 # 45 => Magenta
57 # 46 => Cyan
58 # 47 => White
59 #
60 # Text decoration
61 # You can specify multiple decorations with ;.
62 # 0 => All attributs off (ノーマル)
63 # 1 => Bold on (太字)
64 # 4 => Underscore (下線)
65 # 5 => Blink on (点滅)
66 # 7 => Reverse video on (色反転)
67 # 8 => Concealed on
68
69 echo_color() {
70     local backcolor textcolor decotypes echo_opts arg OPTIND OPT
71     echo_opts="-e"
72     while getopts 'b:t:d:n' arg; do
73         case "${arg}" in
74             b) backcolor="${OPTARG}" ;;
75             t) textcolor="${OPTARG}" ;;
76             d) decotypes="${OPTARG}" ;;
77             n) echo_opts="-n -e"     ;;
78         esac
79     done
80     shift $((OPTIND - 1))
81     if [[ "${nocolor}" = false ]]; then
82         echo ${echo_opts} "\e[$([[ -v backcolor ]] && echo -n "${backcolor}"; [[ -v textcolor ]] && echo -n ";${textcolor}"; [[ -v decotypes ]] && echo -n ";${decotypes}")m${*}\e[m"
83     else
84         echo ${echo_opts} "${@}"
85     fi
86 }
87
88
89 # Show an INFO message
90 # $1: message string
91 _msg_info() {
92     if [[ "${msgdebug}" = false ]]; then
93         set +xv
94     else
95         set -xv
96     fi
97     local echo_opts="-e" arg OPTIND OPT
98     while getopts 'n' arg; do
99         case "${arg}" in
100             n) echo_opts="${echo_opts} -n" ;;
101         esac
102     done
103     shift $((OPTIND - 1))
104     echo ${echo_opts} "$( echo_color -t '36' '[build.sh]')    $( echo_color -t '32' 'Info') ${*}"
105     if [[ "${bash_debug}" = true ]]; then
106         set -xv
107     else
108         set +xv
109     fi
110 }
111
112
113 # Show an Warning message
114 # $1: message string
115 _msg_warn() {
116     if [[ "${msgdebug}" = false ]]; then
117         set +xv
118     else
119         set -xv
120     fi
121     local echo_opts="-e" arg OPTIND OPT
122     while getopts 'n' arg; do
123         case "${arg}" in
124             n) echo_opts="${echo_opts} -n" ;;
125         esac
126     done
127     shift $((OPTIND - 1))
128     echo ${echo_opts} "$( echo_color -t '36' '[build.sh]') $( echo_color -t '33' 'Warning') ${*}" >&2
129     if [[ "${bash_debug}" = true ]]; then
130         set -xv
131     else
132         set +xv
133     fi
134 }
135
136
137 # Show an debug message
138 # $1: message string
139 _msg_debug() {
140     if [[ "${msgdebug}" = false ]]; then
141         set +xv
142     else
143         set -xv
144     fi
145     local echo_opts="-e" arg OPTIND OPT
146     while getopts 'n' arg; do
147         case "${arg}" in
148             n) echo_opts="${echo_opts} -n" ;;
149         esac
150     done
151     shift $((OPTIND - 1))
152     if [[ ${debug} = true ]]; then
153         echo ${echo_opts} "$( echo_color -t '36' '[build.sh]')   $( echo_color -t '35' 'Debug') ${*}"
154     fi
155     if [[ "${bash_debug}" = true ]]; then
156         set -xv
157     else
158         set +xv
159     fi
160 }
161
162
163 # Show an ERROR message then exit with status
164 # $1: message string
165 # $2: exit code number (with 0 does not exit)
166 _msg_error() {
167     if [[ "${msgdebug}" = false ]]; then
168         set +xv
169     else
170         set -xv
171     fi
172     local echo_opts="-e" arg OPTIND OPT
173     while getopts 'n' arg; do
174         case "${arg}" in
175             n) echo_opts="${echo_opts} -n" ;;
176         esac
177     done
178     shift $((OPTIND - 1))
179     echo ${echo_opts} "$( echo_color -t '36' '[build.sh]')   $( echo_color -t '31' 'Error') ${1}" >&2
180     if [[ -n "${2:-}" ]]; then
181         exit ${2}
182     fi
183     if [[ "${bash_debug}" = true ]]; then
184         set -xv
185     else
186         set +xv
187     fi
188 }
189
190
191 _usage () {
192     echo "usage ${0} [options] [channel]"
193     echo
194     echo " General options:"
195     echo
196     echo "    -b | --boot-splash           Enable boot splash"
197     echo "                                  Default: disable"
198     echo "    -j | --japanese              Enable Japanese mode."
199     echo "                                  Default: disable"
200     echo "    -l | --cleanup               Enable post-build cleaning."
201     echo "                                  Default: disable"
202     echo "    -d | --debug                 Enable debug messages."
203     echo "                                  Default: disable"
204     echo "    -x | --bash-debug            Enable bash debug mode.(set -xv)"
205     echo "                                  Default: disable"
206     echo "    -h | --help                  This help message and exit."
207     echo
208     echo "    -a | --arch <arch>           Set iso architecture."
209     echo "                                  Default: ${arch}"
210     echo "    -c | <comp_type>             Set SquashFS compression type (gzip, lzma, lzo, xz, zstd)"
211     echo "                                  Default: ${sfs_comp}"
212     echo "    -g | --gpgkey <key>          Set gpg key"
213     echo "                                  Default: ${gpg_key}"
214     echo "    -k | --kernel <kernel>       Set special kernel type.See below for available kernels."
215     echo "                                  Default: ${kernel}"
216     echo "    -o | --out <out_dir>         Set the output directory"
217     echo "                                  Default: ${out_dir}"
218     echo "    -p | --password <password>   Set a live user password"
219     echo "                                  Default: ${password}"
220     echo "    -t | --comp-opts <options>   Set compressor-specific options."
221     echo "                                  Default: empty"
222     echo "    -u | --user <username>        Set user name."
223     echo "                                  Default: ${username}"
224     echo "    -w | --work <work_dir>       Set the working directory"
225     echo "                                  Default: ${work_dir}"
226     echo
227     echo "    --gitversion                 Add Git commit hash to image file version"
228     echo "    --msgdebug                   Enables output debugging."
229     echo "    --nocolor                    No output colored output."
230     echo "    --noconfirm                  No check the settings before building."
231     echo "    --noloopmod                  No check and load kernel module automatically."
232     echo "    --nodepend                   No check package dependencies before building."
233     echo "    --shmkalteriso               Use the shell script version of mkalteriso."
234     echo
235     echo "A list of kernels available for each architecture."
236     echo
237     local kernel
238     local list
239     for list in ${script_path}/system/kernel_list-* ; do
240         echo " ${list#${script_path}/system/kernel_list-}:"
241         echo -n "    "
242         for kernel in $(grep -h -v ^'#' ${list}); do
243             echo -n "${kernel} "
244         done
245         echo
246     done
247     echo
248     echo "You can switch between installed packages, files included in images, etc. by channel."
249     echo
250     echo " Channel:"
251     for i in $(ls -l "${script_path}"/channels/ | awk '$1 ~ /d/ {print $9 }'); do
252         if [[ -n $(ls "${script_path}"/channels/${i}) ]]; then
253             if [[ ! ${i} = "share" ]]; then
254                 if [[ ! $(echo "${i}" | sed 's/^.*\.\([^\.]*\)$/\1/') = "add" ]]; then
255                     if [[ ! -d "${script_path}/channels/${i}.add" ]]; then
256                         channel_list="${channel_list[@]} ${i}"
257                     fi
258                 else
259                     channel_list="${channel_list[@]} ${i}"
260                 fi
261             fi
262         fi
263     done
264     channel_list="${channel_list[@]} rebuild"
265     local blank="33"
266
267     for _channel in ${channel_list[@]}; do
268         if [[ -f "${script_path}/channels/${_channel}/description.txt" ]]; then
269             description=$(cat "${script_path}/channels/${_channel}/description.txt")
270         elif [[ "${_channel}" = "rebuild" ]]; then
271             description="Rebuild using the settings of the previous build."
272         else
273             description="This channel does not have a description.txt."
274         fi
275         if [[ $(echo "${_channel}" | sed 's/^.*\.\([^\.]*\)$/\1/') = "add" ]]; then
276             echo -ne "    $(echo ${_channel} | sed 's/\.[^\.]*$//')"
277             for i in $( seq 1 $(( ${blank} - ${#_channel} )) ); do
278                 echo -ne " "
279             done
280         else
281             echo -ne "    ${_channel}"
282             for i in $( seq 1 $(( ${blank} - 4 - ${#_channel} )) ); do
283                 echo -ne " "
284             done
285         fi
286         echo -ne "${description}\n"
287     done
288
289     if [[ -n "${1:-}" ]]; then
290         exit "${1}"
291     fi
292 }
293
294
295 # Unmount chroot dir
296 umount_chroot () {
297     local mount
298     for mount in $(mount | awk '{print $3}' | grep $(realpath ${work_dir}) | tac); do
299         _msg_info "Unmounting ${mount}"
300         umount -lf "${mount}"
301     done
302 }
303
304 # Helper function to run make_*() only one time.
305 run_once() {
306     if [[ ! -e "${work_dir}/build.${1}_${arch}" ]]; then
307         _msg_debug "Running $1 ..."
308         "$1"
309         touch "${work_dir}/build.${1}_${arch}"
310         umount_chroot
311     else
312         _msg_debug "Skipped because ${1} has already been executed."
313     fi
314 }
315
316
317 # rm helper
318 # Delete the file if it exists.
319 # For directories, rm -rf is used.
320 # If the file does not exist, skip it.
321 # remove <file> <file> ...
322 remove() {
323     local _list=($(echo "$@")) _file
324     for _file in "${_list[@]}"; do
325         if [[ -f ${_file} ]]; then
326             _msg_debug "Removeing ${_file}"
327             rm -f "${_file}"
328         elif [[ -d ${_file} ]]; then
329             _msg_debug "Removeing ${_file}"
330             rm -rf "${_file}"
331         fi
332     done
333 }
334
335
336 # 強制終了時にアンマウント
337 umount_trap() {
338     local status=${?}
339     umount_chroot
340     _msg_error "It was killed by the user."
341     _msg_error "The process may not have completed successfully."
342     exit ${status}
343 }
344
345 # 設定ファイルを読み込む
346 # load_config [file1] [file2] ...
347 load_config() {
348     local file
349     for file in ${@}; do
350         if [[ -f "${file}" ]]; then
351             source "${file}"
352             _msg_debug "The settings have been overwritten by the ${file}"
353         fi
354     done
355 }
356
357
358 # 作業ディレクトリを削除
359 remove_work() {
360     if [[ -d "${work_dir}" ]]; then
361         remove "$(ls ${work_dir}/* | grep "build.make")"
362         remove "${work_dir}"/pacman-*.conf
363         remove "${work_dir}/efiboot"
364         remove "${work_dir}/iso"
365         remove "${work_dir}/${arch}"
366         remove "${work_dir}/packages.list"
367         remove "${work_dir}/packages-full.list"
368         #remove "${rebuildfile}"
369         if [[ -z $(ls $(realpath "${work_dir}")/* 2>/dev/null) ]]; then
370             remove ${work_dir}
371         fi
372     fi
373 }
374
375
376 # Display channel list
377 show_channel_list() {
378     local i
379     for i in $(ls -l "${script_path}"/channels/ | awk '$1 ~ /d/ {print $9 }'); do
380         if [[ -n $(ls "${script_path}"/channels/${i}) ]] && [[ ! ${i} = "share" ]]; then
381             if [[ ! $(echo "${i}" | sed 's/^.*\.\([^\.]*\)$/\1/') = "add" ]]; then
382                 if [[ ! -d "${script_path}/channels/${i}.add" ]]; then
383                     echo -n "${i} "
384                 fi
385             else
386                 echo -n "${i} "
387             fi
388         fi
389     done
390     echo
391     exit 0
392 }
393
394
395 # Preparation for build
396 prepare_build() {
397     # Build mkalteriso
398     if [[ "${shmkalteriso}" = false ]]; then
399         mkalteriso="${script_path}/system/mkalteriso"
400         cd "${script_path}"
401         _msg_info "Building mkalteriso..."
402         if [[ "${debug}" = true ]]; then
403             make mkalteriso
404             echo
405         else
406             make mkalteriso > /dev/null 2>&1
407         fi
408         cd - > /dev/null 2>&1
409     else
410         mkalteriso="${script_path}/system/mkalteriso.sh"
411     fi
412
413     # Create a working directory.
414     [[ ! -d "${work_dir}" ]] && mkdir -p "${work_dir}"
415
416
417     # Check work dir
418     if [[ -n $(ls -a "${work_dir}" 2> /dev/null | grep -xv ".." | grep -xv ".") ]] && [[ ! "${rebuild}" = true ]]; then
419         umount_chroot
420         _msg_info "Deleting the contents of ${work_dir}..."
421         remove "${work_dir%/}"/*
422     fi
423
424
425     # 強制終了時に作業ディレクトリを削除する
426     local trap_remove_work
427     trap_remove_work() {
428         local status=${?}
429         echo
430         remove_work
431         exit ${status}
432     }
433     trap 'trap_remove_work' 1 2 3 15
434
435     # Save build options
436     local save_var
437     save_var() {
438         local out_file="${rebuildfile}"
439         local i
440         echo "#!/usr/bin/env bash" > "${out_file}"
441         echo "# Build options are stored here." >> "${out_file}"
442         for i in ${@}; do
443             echo -n "${i}=" >> "${out_file}"
444             echo -n '"' >> "${out_file}"
445             eval echo -n '$'{${i}} >> "${out_file}"
446             echo '"' >> "${out_file}"
447         done
448     }
449     if [[ ${rebuild} = false ]]; then
450         # If there is pacman.conf for each channel, use that for building
451         if [[ -f "${script_path}/channels/${channel_name}/pacman-${arch}.conf" ]]; then
452             build_pacman_conf="${script_path}/channels/${channel_name}/pacman-${arch}.conf"
453         fi
454
455         # If there is config for share channel. load that.
456         load_config "${script_path}/channels/share/config.any"
457         load_config ${script_path}/channels/share/config.${arch}
458
459         # If there is config for each channel. load that.
460         load_config "${script_path}/channels/${channel_name}/config.any"
461         load_config "${script_path}/channels/${channel_name}/config.${arch}"
462
463         # Set username
464         if [[ "${customized_username}" = false ]]; then
465             username="${defaultusername}"
466         fi
467
468         # gitversion
469         if [[ "${gitversion}" = true ]]; then
470             cd ${script_path}
471             iso_version=${iso_version}-$(git rev-parse --short HEAD)
472             cd - > /dev/null 2>&1
473         fi
474     
475         # Generate iso file name.
476         local _channel_name
477         if [[ $(echo "${channel_name}" | sed 's/^.*\.\([^\.]*\)$/\1/') = "add" ]]; then
478             _channel_name="$(echo ${channel_name} | sed 's/\.[^\.]*$//')"
479         else
480             _channel_name="${channel_name}"
481         fi
482         if [[ "${japanese}" = true ]]; then
483             _channel_name="${_channel_name}-jp"
484         fi
485         if [[ "${nochname}" = true ]]; then
486             iso_filename="${iso_name}-${iso_version}-${arch}.iso"
487         else
488             iso_filename="${iso_name}-${_channel_name}-${iso_version}-${arch}.iso"
489         fi
490         _msg_debug "Iso filename is ${iso_filename}"
491
492         # Save the value of the variable for use in rebuild.
493         save_var \
494             arch \
495             os_name \
496             iso_name \
497             iso_label \
498             iso_publisher \
499             iso_application \
500             iso_version \
501             iso_filename \
502             install_dir \
503             work_dir \
504             out_dir \
505             gpg_key \
506             mkalteriso_option \
507             password \
508             boot_splash \
509             kernel \
510             theme_name \
511             theme_pkg \
512             sfs_comp \
513             sfs_comp_opt \
514             debug \
515             japanese \
516             channel_name \
517             cleaning \
518             username \
519             mkalteriso \
520             usershell \
521             shmkalteriso \
522             nocolor \
523             build_pacman_conf \
524             defaultconfig \
525             msgdebug \
526             defaultusername \
527             customized_username \
528             gitversion \
529             noloopmod
530     else
531         # Load rebuild file
532         load_config "${rebuildfile}"
533         _msg_debug "Iso filename is ${iso_filename}"
534
535         # Delete the lock file.
536         # remove "$(ls ${work_dir}/* | grep "build.make")"
537     fi
538
539     # Unmount
540     local mount
541     for mount in $(mount | awk '{print $3}' | grep $(realpath ${work_dir})); do
542         _msg_info "Unmounting ${mount}"
543         umount "${mount}"
544     done
545
546      # Check packages
547     if [[ "${nodepend}" = false ]] && [[ "${arch}" = $(uname -m) ]] ; then
548         local installed_pkg
549         local installed_ver
550         local check_pkg
551         local check_failed=false
552         local pkg
553
554         installed_pkg=($(pacman -Q | awk '{print $1}'))
555         installed_ver=($(pacman -Q | awk '{print $2}'))
556
557         check_pkg() {
558             local i
559             local ver
560             for i in $(seq 0 $(( ${#installed_pkg[@]} - 1 ))); do
561                 if [[ "${installed_pkg[${i}]}" = ${1} ]]; then
562                     ver=$(pacman -Sp --print-format '%v' --config ${build_pacman_conf} ${1} 2> /dev/null)
563                     if [[ "${installed_ver[${i}]}" = "${ver}" ]]; then
564                         echo -n "installed"
565                         return 0
566                     elif [[ -z ${ver} ]]; then
567                         echo "norepo"
568                         return 0
569                     else
570                         echo -n "old"
571                         return 0
572                     fi
573                 fi
574             done
575             echo -n "not"
576             return 0
577         }
578         if [[ ${debug} = false ]]; then
579             _msg_info "Checking dependencies ..."
580         else
581             echo
582         fi
583         for pkg in ${dependence[@]}; do
584             _msg_debug -n "Checking ${pkg} ..."
585             case $(check_pkg ${pkg}) in
586                 "old") 
587                     [[ "${debug}" = true ]] && echo -ne " $(pacman -Q ${pkg} | awk '{print $2}')\n"
588                     _msg_warn "${pkg} is not the latest package."
589                     _msg_warn "Local: $(pacman -Q ${pkg} 2> /dev/null | awk '{print $2}') Latest: $(pacman -Sp --print-format '%v' --config ${build_pacman_conf} ${pkg} 2> /dev/null)"
590                     ;;
591                 "not")
592                     [[ "${debug}" = true ]] && echo
593                     _msg_error "${pkg} is not installed." ; check_failed=true
594                     ;;
595                 "norepo") 
596                     [[ "${debug}" = true ]] && echo
597                     _msg_warn "${pkg} is not a repository package."
598                     ;;
599                 "installed") [[ ${debug} = true ]] && echo -ne " $(pacman -Q ${pkg} | awk '{print $2}')\n" ;;
600             esac
601         done
602
603         if [[ "${check_failed}" = true ]]; then
604             exit 1
605         fi
606     fi
607
608     # Load loop kernel module
609     if [[ "${noloopmod}" = false ]]; then
610         if [[ ! -d "/usr/lib/modules/$(uname -r)" ]]; then
611             _msg_error "The currently running kernel module could not be found."
612             _msg_error "Probably the system kernel has been updated."
613             _msg_error "Reboot your system to run the latest kernel." "1"
614         fi
615         if [[ -z $(lsmod | awk '{print $1}' | grep -x "loop") ]]; then
616             sudo modprobe loop
617         fi
618     fi
619 }
620
621
622 # Show settings.
623 show_settings() {
624     _msg_info "mkalteriso path is ${mkalteriso}"
625     echo
626     if [[ "${boot_splash}" = true ]]; then
627         _msg_info "Boot splash is enabled."
628         _msg_info "Theme is used ${theme_name}."
629     fi
630     _msg_info "Use the ${kernel} kernel."
631     _msg_info "Live username is ${username}."
632     _msg_info "Live user password is ${password}."
633     _msg_info "The compression method of squashfs is ${sfs_comp}."
634     if [[ $(echo "${channel_name}" | sed 's/^.*\.\([^\.]*\)$/\1/') = "add" ]]; then
635         _msg_info "Use the $(echo ${channel_name} | sed 's/\.[^\.]*$//') channel."
636     else
637         _msg_info "Use the ${channel_name} channel."
638     fi
639     [[ "${japanese}" = true ]] && _msg_info "Japanese mode has been activated."
640     _msg_info "Build with architecture ${arch}."
641     echo
642     if [[ ${noconfirm} = false ]]; then
643         echo "Press Enter to continue or Ctrl + C to cancel."
644         read
645     fi
646     trap 1 2 3 15
647     trap 'umount_trap' 1 2 3 15
648 }
649
650
651 # Setup custom pacman.conf with current cache directories.
652 make_pacman_conf() {
653     _msg_debug "Use ${build_pacman_conf}"
654     local _cache_dirs
655     _cache_dirs=($(pacman -v 2>&1 | grep '^Cache Dirs:' | sed 's/Cache Dirs:\s*//g'))
656     sed -r "s|^#?\\s*CacheDir.+|CacheDir = $(echo -n ${_cache_dirs[@]})|g" ${build_pacman_conf} > "${work_dir}/pacman-${arch}.conf"
657 }
658
659 # Base installation, plus needed packages (airootfs)
660 make_basefs() {
661     ${mkalteriso} ${mkalteriso_option} -w "${work_dir}/${arch}" -C "${work_dir}/pacman-${arch}.conf" -D "${install_dir}" init
662     # ${mkalteriso} ${mkalteriso_option} -w "${work_dir}/${arch}" -C "${work_dir}/pacman-${arch}.conf" -D "${install_dir}" -p "haveged intel-ucode amd-ucode memtest86+ mkinitcpio-nfs-utils nbd zsh efitools" install
663     ${mkalteriso} ${mkalteriso_option} -w "${work_dir}/${arch}" -C "${work_dir}/pacman-${arch}.conf" -D "${install_dir}" -p "bash haveged intel-ucode amd-ucode mkinitcpio-nfs-utils nbd efitools" install
664
665     # Install plymouth.
666     if [[ "${boot_splash}" = true ]]; then
667         if [[ -n "${theme_pkg}" ]]; then
668             ${mkalteriso} ${mkalteriso_option} -w "${work_dir}/${arch}" -C "${work_dir}/pacman-${arch}.conf" -D "${install_dir}" -p "plymouth ${theme_pkg}" install
669         else
670             ${mkalteriso} ${mkalteriso_option} -w "${work_dir}/${arch}" -C "${work_dir}/pacman-${arch}.conf" -D "${install_dir}" -p "plymouth" install
671         fi
672     fi
673
674     # Install kernel.
675     if [[ ! "${kernel}" = "core" ]]; then
676         ${mkalteriso} ${mkalteriso_option} -w "${work_dir}/${arch}" -C "${work_dir}/pacman-${arch}.conf" -D "${install_dir}" -p "linux-${kernel} linux-${kernel}-headers broadcom-wl-dkms" install
677     else
678         ${mkalteriso} ${mkalteriso_option} -w "${work_dir}/${arch}" -C "${work_dir}/pacman-${arch}.conf" -D "${install_dir}" -p "linux linux-headers broadcom-wl" install
679     fi
680 }
681
682 # Additional packages (airootfs)
683 make_packages() {
684     # インストールするパッケージのリストを読み込み、配列pkglistに代入します。
685     installpkglist() {
686         set +e
687         local _loadfilelist _pkg _file jplist excludefile excludelist _pkglist
688
689         #-- Detect package list to load --#
690         # Append the file in the share directory to the file to be read.
691
692         # Package list for Japanese
693         jplist="${script_path}/channels/share/packages.${arch}/jp.${arch}"
694
695         # Package list for non-Japanese
696         nojplist="${script_path}/channels/share/packages.${arch}/non-jp.${arch}"
697
698         if [[ "${japanese}" = true ]]; then
699             _loadfilelist=($(ls "${script_path}"/channels/share/packages.${arch}/*.${arch} | grep -xv "${nojplist}"))
700         else
701             _loadfilelist=($(ls "${script_path}"/channels/share/packages.${arch}/*.${arch} | grep -xv "${jplist}"))
702         fi
703
704
705         # Add the files for each channel to the list of files to read.
706
707         # Package list for Japanese
708         jplist="${script_path}/channels/${channel_name}/packages.${arch}/jp.${arch}"
709
710         # Package list for non-Japanese
711         nojplist="${script_path}/channels/${channel_name}/packages.${arch}/non-jp.${arch}"
712
713         if [[ "${japanese}" = true ]]; then
714             # If Japanese is enabled, add it to the list of files to read other than non-jp.
715             _loadfilelist=(${_loadfilelist[@]} $(ls "${script_path}"/channels/${channel_name}/packages.${arch}/*.${arch} | grep -xv "${nojplist}"))
716         else
717             # If Japanese is disabled, add it to the list of files to read other than jp.
718             _loadfilelist=(${_loadfilelist[@]} $(ls "${script_path}"/channels/${channel_name}/packages.${arch}/*.${arch} | grep -xv ${jplist}))
719         fi
720
721
722         #-- Read package list --#
723         # Read the file and remove comments starting with # and add it to the list of packages to install.
724         for _file in ${_loadfilelist[@]}; do
725             _msg_debug "Loaded package file ${_file}"
726             pkglist=( ${pkglist[@]} "$(grep -h -v ^'#' ${_file})" )
727         done
728         if [[ ${debug} = true ]]; then
729             sleep 3
730         fi
731
732         # Exclude packages from the share exclusion list
733         excludefile="${script_path}/channels/share/packages.${arch}/exclude"
734         if [[ -f "${excludefile}" ]]; then
735             excludelist=( $(grep -h -v ^'#' "${excludefile}") )
736
737             # 現在のpkglistをコピーする
738             _pkglist=(${pkglist[@]})
739             unset pkglist
740             for _pkg in ${_pkglist[@]}; do
741                 # もし変数_pkgの値が配列excludelistに含まれていなかったらpkglistに追加する
742                 if [[ ! $(printf '%s\n' "${excludelist[@]}" | grep -qx "${_pkg}"; echo -n ${?} ) = 0 ]]; then
743                     pkglist=(${pkglist[@]} "${_pkg}")
744                 fi
745             done
746         fi
747
748         if [[ -n "${excludelist}" ]]; then
749             _msg_debug "The following packages have been removed from the installation list."
750             _msg_debug "Excluded packages:" "${excludelist[@]}"
751         fi
752
753         # Exclude packages from the exclusion list for each channel
754         excludefile="${script_path}/channels/${channel_name}/packages.${arch}/exclude"
755         if [[ -f "${excludefile}" ]]; then
756             excludelist=( $(grep -h -v ^'#' "${excludefile}") )
757         
758             # 現在のpkglistをコピーする
759             _pkglist=(${pkglist[@]})
760             unset pkglist
761             for _pkg in ${_pkglist[@]}; do
762                 # もし変数_pkgの値が配列excludelistに含まれていなかったらpkglistに追加する
763                 if [[ ! $(printf '%s\n' "${excludelist[@]}" | grep -qx "${_pkg}"; echo -n ${?} ) = 0 ]]; then
764                     pkglist=(${pkglist[@]} "${_pkg}")
765                 fi
766             done
767         fi
768         
769         # Sort the list of packages in abc order.
770         pkglist=(
771             "$(
772                 for _pkg in ${pkglist[@]}; do
773                     echo "${_pkg}"
774                 done \
775                 | sort
776             )"
777         )
778
779         set -e
780     }
781
782     installpkglist
783
784     # _msg_debug "${pkglist[@]}"
785
786     # Create a list of packages to be finally installed as packages.list directly under the working directory.
787     echo "# The list of packages that is installed in live cd." > ${work_dir}/packages.list
788     echo "#" >> ${work_dir}/packages.list
789     echo >> ${work_dir}/packages.list
790     for _pkg in ${pkglist[@]}; do
791         echo ${_pkg} >> ${work_dir}/packages.list
792     done
793
794     # Install packages on airootfs
795     ${mkalteriso} ${mkalteriso_option} -w "${work_dir}/${arch}" -C "${work_dir}/pacman-${arch}.conf" -D "${install_dir}" -p "${pkglist[@]}" install
796 }
797
798 # Customize installation (airootfs)
799 make_customize_airootfs() {
800     # Overwrite airootfs with customize_airootfs.
801     local copy_airootfs
802
803     copy_airootfs() {
804         local i 
805         for i in "${@}"; do
806             local _dir="${i%/}"
807             if [[ -d "${_dir}" ]]; then
808                 cp -af "${_dir}"/* "${work_dir}/${arch}/airootfs"
809             fi
810         done
811     }
812
813     copy_airootfs "${script_path}/channels/share/airootfs.any"
814     copy_airootfs "${script_path}/channels/share/airootfs.${arch}"
815     copy_airootfs "${script_path}/channels/${channel_name}/airootfs.any"
816     copy_airootfs "${script_path}/channels/${channel_name}/airootfs.${arch}"
817
818     # Replace /etc/mkinitcpio.conf if Plymouth is enabled.
819     if [[ "${boot_splash}" = true ]]; then
820         cp "${script_path}/mkinitcpio/mkinitcpio-plymouth.conf" "${work_dir}/${arch}/airootfs/etc/mkinitcpio.conf"
821     fi
822
823     # Code to use common pacman.conf in archiso.
824     # cp "${script_path}/pacman.conf" "${work_dir}/${arch}/airootfs/etc"
825     # cp "${build_pacman_conf}" "${work_dir}/${arch}/airootfs/etc"
826
827     # Get the optimal mirror list.
828     local mirrorlisturl mirrorlisturl_all  mirrorlisturl_jp
829
830     case "${arch}" in
831         "x86_64")
832             mirrorlisturl_jp='https://www.archlinux.org/mirrorlist/?country=JP'
833             mirrorlisturl_all='https://www.archlinux.org/mirrorlist/?country=all'
834             ;;
835         "i686")
836             mirrorlisturl_jp='https://archlinux32.org/mirrorlist/?country=jp'
837             mirrorlisturl_all='https://archlinux32.org/mirrorlist/?country=all'
838             ;;
839     esac
840
841     if [[ "${japanese}" = true ]]; then
842         mirrorlisturl="${mirrorlisturl_jp}"
843     else
844         mirrorlisturl="${mirrorlisturl_all}"
845     fi
846     curl -o "${work_dir}/${arch}/airootfs/etc/pacman.d/mirrorlist" "${mirrorlisturl}"
847
848     # Add install guide to /root (disabled)
849     # lynx -dump -nolist 'https://wiki.archlinux.org/index.php/Installation_Guide?action=render' >> ${work_dir}/${arch}/airootfs/root/install.txt
850
851
852     # customize_airootfs.sh options
853     # -b            : Enable boot splash.
854     # -d            : Enable debug mode.
855     # -i <inst_dir> : Set install dir
856     # -j            : Enable Japanese.
857     # -k <kernel>   : Set kernel name.
858     # -o <os name>  : Set os name.
859     # -p <password> : Set password.
860     # -s <shell>    : Set user shell.
861     # -t            : Set plymouth theme.
862     # -u <username> : Set live user name.
863     # -x            : Enable bash debug mode.
864     # -r            : Enable rebuild.
865
866
867     # Generate options of customize_airootfs.sh.
868     local addition_options
869     local share_options
870     addition_options=
871     if [[ ${boot_splash} = true ]]; then
872         if [[ -z ${theme_name} ]]; then
873             addition_options="${addition_options} -b"
874         else
875             addition_options="${addition_options} -b -t ${theme_name}"
876         fi
877     fi
878     if [[ ${debug} = true ]]; then
879         addition_options="${addition_options} -d"
880     fi
881     if [[ ${bash_debug} = true ]]; then
882         addition_options="${addition_options} -x"
883     fi
884     if [[ ${japanese} = true ]]; then
885         addition_options="${addition_options} -j"
886     fi
887     if [[ ${rebuild} = true ]]; then
888         addition_options="${addition_options} -r"
889     fi
890
891     share_options="-p '${password}' -k '${kernel}' -u '${username}' -o '${os_name}' -i '${install_dir}' -s '${usershell}' -a '${arch}'"
892
893
894     # X permission
895     if [[ -f ${work_dir}/${arch}/airootfs/root/customize_airootfs.sh ]]; then
896         chmod 755 "${work_dir}/${arch}/airootfs/root/customize_airootfs.sh"
897     fi
898     if [[ -f "${work_dir}/${arch}/airootfs/root/customize_airootfs.sh" ]]; then
899         chmod 755 "${work_dir}/${arch}/airootfs/root/customize_airootfs.sh"
900     fi
901     if [[ -f "${work_dir}/${arch}/airootfs/root/customize_airootfs_${channel_name}.sh" ]]; then
902         chmod 755 "${work_dir}/${arch}/airootfs/root/customize_airootfs_${channel_name}.sh"
903     elif [[ -f "${work_dir}/${arch}/airootfs/root/customize_airootfs_$(echo ${channel_name} | sed 's/\.[^\.]*$//').sh" ]]; then
904         chmod 755 "${work_dir}/${arch}/airootfs/root/customize_airootfs_$(echo ${channel_name} | sed 's/\.[^\.]*$//').sh"
905     fi
906
907     # Execute customize_airootfs.sh.
908     if [[ -z ${addition_options} ]]; then
909         ${mkalteriso} ${mkalteriso_option} \
910             -w "${work_dir}/${arch}" \
911             -C "${work_dir}/pacman-${arch}.conf" \
912             -D "${install_dir}" \
913             -r "/root/customize_airootfs.sh ${share_options}" \
914             run
915         if [[ -f "${work_dir}/${arch}/airootfs/root/customize_airootfs_${channel_name}.sh" ]]; then
916             ${mkalteriso} ${mkalteriso_option} \
917                 -w "${work_dir}/${arch}" \
918                 -C "${work_dir}/pacman-${arch}.conf" \
919                 -D "${install_dir}" \
920                 -r "/root/customize_airootfs_${channel_name}.sh ${share_options}" \
921                 run
922         elif [[ -f "${work_dir}/${arch}/airootfs/root/customize_airootfs_$(echo ${channel_name} | sed 's/\.[^\.]*$//').sh" ]]; then
923             ${mkalteriso} ${mkalteriso_option} \
924                 -w "${work_dir}/${arch}" \
925                 -C "${work_dir}/pacman-${arch}.conf" \
926                 -D "${install_dir}" \
927                 -r "/root/customize_airootfs_$(echo ${channel_name} | sed 's/\.[^\.]*$//').sh ${share_options}" \
928                 run
929         fi
930     else
931         ${mkalteriso} ${mkalteriso_option} \
932             -w "${work_dir}/${arch}" \
933             -C "${work_dir}/pacman-${arch}.conf" \
934             -D "${install_dir}" \
935             -r "/root/customize_airootfs.sh ${share_options} ${addition_options}" \
936             run
937
938         if [[ -f "${work_dir}/${arch}/airootfs/root/customize_airootfs_${channel_name}.sh" ]]; then
939             ${mkalteriso} ${mkalteriso_option} \
940                 -w "${work_dir}/${arch}" \
941                 -C "${work_dir}/pacman-${arch}.conf" \
942                 -D "${install_dir}" \
943                 -r "/root/customize_airootfs_${channel_name}.sh ${share_options} ${addition_options}" \
944                 run
945         elif [[ -f "${work_dir}/${arch}/airootfs/root/customize_airootfs_$(echo ${channel_name} | sed 's/\.[^\.]*$//').sh" ]]; then
946             ${mkalteriso} ${mkalteriso_option} \
947                 -w "${work_dir}/${arch}" \
948                 -C "${work_dir}/pacman-${arch}.conf" \
949                 -D "${install_dir}" \
950                 -r "/root/customize_airootfs_$(echo ${channel_name} | sed 's/\.[^\.]*$//').sh ${share_options} ${addition_options}" \
951                 run
952         fi
953     fi
954
955
956     # Delete customize_airootfs.sh.
957     remove "${work_dir}/${arch}/airootfs/root/customize_airootfs.sh"
958     remove "${work_dir}/${arch}/airootfs/root/customize_airootfs_${channel_name}.sh"
959 }
960
961 # Copy mkinitcpio archiso hooks and build initramfs (airootfs)
962 make_setup_mkinitcpio() {
963     local _hook
964     mkdir -p "${work_dir}/${arch}/airootfs/etc/initcpio/hooks"
965     mkdir -p "${work_dir}/${arch}/airootfs/etc/initcpio/install"
966     for _hook in "archiso" "archiso_shutdown" "archiso_pxe_common" "archiso_pxe_nbd" "archiso_pxe_http" "archiso_pxe_nfs" "archiso_loop_mnt"; do
967         cp "${script_path}/system/initcpio/hooks/${_hook}" "${work_dir}/${arch}/airootfs/etc/initcpio/hooks"
968         cp "${script_path}/system/initcpio/install/${_hook}" "${work_dir}/${arch}/airootfs/etc/initcpio/install"
969     done
970     sed -i "s|/usr/lib/initcpio/|/etc/initcpio/|g" "${work_dir}/${arch}/airootfs/etc/initcpio/install/archiso_shutdown"
971     cp "${script_path}/system/initcpio/install/archiso_kms" "${work_dir}/${arch}/airootfs/etc/initcpio/install"
972     cp "${script_path}/system/initcpio/archiso_shutdown" "${work_dir}/${arch}/airootfs/etc/initcpio"
973     if [[ "${boot_splash}" = true ]]; then
974         cp "${script_path}/mkinitcpio/mkinitcpio-archiso-plymouth.conf" "${work_dir}/${arch}/airootfs/etc/mkinitcpio-archiso.conf"
975     else
976         cp "${script_path}/mkinitcpio/mkinitcpio-archiso.conf" "${work_dir}/${arch}/airootfs/etc/mkinitcpio-archiso.conf"
977     fi
978     gnupg_fd=
979     if [[ "${gpg_key}" ]]; then
980       gpg --export "${gpg_key}" >"${work_dir}/gpgkey"
981       exec 17<>$"{work_dir}/gpgkey"
982     fi
983
984     if [[ ! ${kernel} = "core" ]]; then
985         ARCHISO_GNUPG_FD=${gpg_key:+17} ${mkalteriso} ${mkalteriso_option} -w "${work_dir}/${arch}" -C "${work_dir}/pacman-${arch}.conf" -D "${install_dir}" -r "mkinitcpio -c /etc/mkinitcpio-archiso.conf -k /boot/vmlinuz-linux-${kernel} -g /boot/archiso.img" run
986     else
987         ARCHISO_GNUPG_FD=${gpg_key:+17} ${mkalteriso} ${mkalteriso_option} -w "${work_dir}/${arch}" -C "${work_dir}/pacman-${arch}.conf" -D "${install_dir}" -r 'mkinitcpio -c /etc/mkinitcpio-archiso.conf -k /boot/vmlinuz-linux -g /boot/archiso.img' run
988     fi
989
990     if [[ "${gpg_key}" ]]; then
991       exec 17<&-
992     fi
993 }
994
995 # Prepare kernel/initramfs ${install_dir}/boot/
996 make_boot() {
997     mkdir -p "${work_dir}/iso/${install_dir}/boot/${arch}"
998     cp "${work_dir}/${arch}/airootfs/boot/archiso.img" "${work_dir}/iso/${install_dir}/boot/${arch}/archiso.img"
999
1000     if [[ ! "${kernel}" = "core" ]]; then
1001         cp "${work_dir}/${arch}/airootfs/boot/vmlinuz-linux-${kernel}" "${work_dir}/iso/${install_dir}/boot/${arch}/vmlinuz-linux-${kernel}"
1002     else
1003         cp "${work_dir}/${arch}/airootfs/boot/vmlinuz-linux" "${work_dir}/iso/${install_dir}/boot/${arch}/vmlinuz"
1004     fi
1005 }
1006
1007 # Add other aditional/extra files to ${install_dir}/boot/
1008 make_boot_extra() {
1009     cp "${work_dir}/${arch}/airootfs/boot/intel-ucode.img" "${work_dir}/iso/${install_dir}/boot/intel_ucode.img"
1010     cp "${work_dir}/${arch}/airootfs/usr/share/licenses/intel-ucode/LICENSE" "${work_dir}/iso/${install_dir}/boot/intel_ucode.LICENSE"
1011     cp "${work_dir}/${arch}/airootfs/boot/amd-ucode.img" "${work_dir}/iso/${install_dir}/boot/amd_ucode.img"
1012     cp "${work_dir}/${arch}/airootfs/usr/share/licenses/amd-ucode/LICENSE" "${work_dir}/iso/${install_dir}/boot/amd_ucode.LICENSE"
1013 }
1014
1015 # Prepare /${install_dir}/boot/syslinux
1016 make_syslinux() {
1017     if [[ ! ${kernel} = "core" ]]; then
1018         _uname_r="$(file -b ${work_dir}/${arch}/airootfs/boot/vmlinuz-linux-${kernel} | awk 'f{print;f=0} /version/{f=1}' RS=' ')"
1019     else
1020         _uname_r="$(file -b ${work_dir}/${arch}/airootfs/boot/vmlinuz-linux | awk 'f{print;f=0} /version/{f=1}' RS=' ')"
1021     fi
1022     mkdir -p "${work_dir}/iso/${install_dir}/boot/syslinux"
1023
1024     for _cfg in ${script_path}/syslinux/${arch}/*.cfg; do
1025         sed "s|%ARCHISO_LABEL%|${iso_label}|g;
1026              s|%OS_NAME%|${os_name}|g;
1027              s|%INSTALL_DIR%|${install_dir}|g" "${_cfg}" > "${work_dir}/iso/${install_dir}/boot/syslinux/${_cfg##*/}"
1028     done
1029
1030     if [[ ${boot_splash} = true ]]; then
1031         sed "s|%ARCHISO_LABEL%|${iso_label}|g;
1032              s|%OS_NAME%|${os_name}|g;
1033              s|%INSTALL_DIR%|${install_dir}|g" \
1034              "${script_path}/syslinux/${arch}/pxe-plymouth/archiso_pxe-${kernel}.cfg" > "${work_dir}/iso/${install_dir}/boot/syslinux/archiso_pxe.cfg"
1035
1036         sed "s|%ARCHISO_LABEL%|${iso_label}|g;
1037              s|%OS_NAME%|${os_name}|g;
1038              s|%INSTALL_DIR%|${install_dir}|g" \
1039              "${script_path}/syslinux/${arch}/sys-plymouth/archiso_sys-${kernel}.cfg" > "${work_dir}/iso/${install_dir}/boot/syslinux/archiso_sys.cfg"
1040     else
1041         sed "s|%ARCHISO_LABEL%|${iso_label}|g;
1042              s|%OS_NAME%|${os_name}|g;
1043              s|%INSTALL_DIR%|${install_dir}|g" \
1044              "${script_path}/syslinux/${arch}/pxe/archiso_pxe-${kernel}.cfg" > "${work_dir}/iso/${install_dir}/boot/syslinux/archiso_pxe.cfg"
1045
1046         sed "s|%ARCHISO_LABEL%|${iso_label}|g;
1047              s|%OS_NAME%|${os_name}|g;
1048              s|%INSTALL_DIR%|${install_dir}|g" \
1049              "${script_path}/syslinux/${arch}/sys/archiso_sys-${kernel}.cfg" > "${work_dir}/iso/${install_dir}/boot/syslinux/archiso_sys.cfg"
1050     fi
1051
1052     if [[ -f "${script_path}/channels/${channel_name}/splash.png" ]]; then
1053         cp "${script_path}/channels/${channel_name}/splash.png" "${work_dir}/iso/${install_dir}/boot/syslinux"
1054     else
1055         cp "${script_path}/syslinux/${arch}/splash.png" "${work_dir}/iso/${install_dir}/boot/syslinux"
1056     fi
1057     cp "${work_dir}"/${arch}/airootfs/usr/lib/syslinux/bios/*.c32 "${work_dir}/iso/${install_dir}/boot/syslinux"
1058     cp "${work_dir}/${arch}/airootfs/usr/lib/syslinux/bios/lpxelinux.0" "${work_dir}/iso/${install_dir}/boot/syslinux"
1059     cp "${work_dir}/${arch}/airootfs/usr/lib/syslinux/bios/memdisk" "${work_dir}/iso/${install_dir}/boot/syslinux"
1060     mkdir -p "${work_dir}/iso/${install_dir}/boot/syslinux/hdt"
1061     gzip -c -9 "${work_dir}/${arch}/airootfs/usr/share/hwdata/pci.ids" > "${work_dir}/iso/${install_dir}/boot/syslinux/hdt/pciids.gz"
1062     gzip -c -9 "${work_dir}/${arch}/airootfs/usr/lib/modules/${_uname_r}/modules.alias" > "${work_dir}/iso/${install_dir}/boot/syslinux/hdt/modalias.gz"
1063 }
1064
1065 # Prepare /isolinux
1066 make_isolinux() {
1067     mkdir -p "${work_dir}/iso/isolinux"
1068
1069     sed "s|%INSTALL_DIR%|${install_dir}|g" \
1070         "${script_path}/system/isolinux.cfg" > "${work_dir}/iso/isolinux/isolinux.cfg"
1071     cp "${work_dir}/${arch}/airootfs/usr/lib/syslinux/bios/isolinux.bin" "${work_dir}/iso/isolinux/"
1072     cp "${work_dir}/${arch}/airootfs/usr/lib/syslinux/bios/isohdpfx.bin" "${work_dir}/iso/isolinux/"
1073     cp "${work_dir}/${arch}/airootfs/usr/lib/syslinux/bios/ldlinux.c32" "${work_dir}/iso/isolinux/"
1074 }
1075
1076 # Prepare /EFI
1077 make_efi() {
1078     mkdir -p "${work_dir}/iso/EFI/boot"
1079     cp "${work_dir}/${arch}/airootfs/usr/share/efitools/efi/HashTool.efi" "${work_dir}/iso/EFI/boot/"
1080     if [[ "${arch}" = "x86_64" ]]; then
1081         cp "${work_dir}/${arch}/airootfs/usr/share/efitools/efi/PreLoader.efi" "${work_dir}/iso/EFI/boot/bootx64.efi"
1082         cp "${work_dir}/${arch}/airootfs/usr/lib/systemd/boot/efi/systemd-bootx64.efi" "${work_dir}/iso/EFI/boot/loader.efi"
1083     fi
1084
1085     mkdir -p "${work_dir}/iso/loader/entries"
1086     cp "${script_path}/efiboot/loader/loader.conf" "${work_dir}/iso/loader/"
1087     cp "${script_path}/efiboot/loader/entries/uefi-shell-x86_64.conf" "${work_dir}/iso/loader/entries/"
1088     cp "${script_path}/efiboot/loader/entries/uefi-shell-full-x86_64.conf" "${work_dir}/iso/loader/entries/"
1089
1090     sed "s|%ARCHISO_LABEL%|${iso_label}|g;
1091          s|%OS_NAME%|${os_name}|g;
1092          s|%INSTALL_DIR%|${install_dir}|g" \
1093         "${script_path}/efiboot/loader/entries/usb/archiso-x86_64-usb-${kernel}.conf" > "${work_dir}/iso/loader/entries/archiso-x86_64.conf"
1094
1095     # edk2-shell based UEFI shell
1096     cp /usr/share/edk2-shell/x64/Shell.efi ${work_dir}/iso/EFI/Shell_x64.efi
1097     cp /usr/share/edk2-shell/x64/Shell_Full.efi ${work_dir}/iso/EFI/Shell_Full_x64.efi
1098 }
1099
1100 # Prepare efiboot.img::/EFI for "El Torito" EFI boot mode
1101 make_efiboot() {
1102     mkdir -p "${work_dir}/iso/EFI/archiso"
1103     truncate -s 64M "${work_dir}/iso/EFI/archiso/efiboot.img"
1104     mkfs.fat -n ARCHISO_EFI "${work_dir}/iso/EFI/archiso/efiboot.img"
1105
1106     mkdir -p "${work_dir}/efiboot"
1107     mount "${work_dir}/iso/EFI/archiso/efiboot.img" "${work_dir}/efiboot"
1108
1109     mkdir -p "${work_dir}/efiboot/EFI/archiso"
1110
1111     if [[ ! ${kernel} = "core" ]]; then
1112         cp "${work_dir}/iso/${install_dir}/boot/${arch}/vmlinuz-linux-${kernel}" "${work_dir}/efiboot/EFI/archiso/vmlinuz-linux-${kernel}.efi"
1113     else
1114         cp "${work_dir}/iso/${install_dir}/boot/${arch}/vmlinuz" "${work_dir}/efiboot/EFI/archiso/vmlinuz.efi"
1115     fi
1116
1117     cp "${work_dir}/iso/${install_dir}/boot/${arch}/archiso.img" "${work_dir}/efiboot/EFI/archiso/archiso.img"
1118
1119     cp "${work_dir}/iso/${install_dir}/boot/intel_ucode.img" "${work_dir}/efiboot/EFI/archiso/intel_ucode.img"
1120     cp "${work_dir}/iso/${install_dir}/boot/amd_ucode.img" "${work_dir}/efiboot/EFI/archiso/amd_ucode.img"
1121
1122     mkdir -p "${work_dir}/efiboot/EFI/boot"
1123     cp "${work_dir}/${arch}/airootfs/usr/share/efitools/efi/HashTool.efi" "${work_dir}/efiboot/EFI/boot/"
1124
1125     if [[ "${arch}" = "x86_64" ]]; then
1126         cp "${work_dir}/${arch}/airootfs/usr/share/efitools/efi/PreLoader.efi" "${work_dir}/efiboot/EFI/boot/bootx64.efi"
1127         cp "${work_dir}/${arch}/airootfs/usr/lib/systemd/boot/efi/systemd-bootx64.efi" "${work_dir}/efiboot/EFI/boot/loader.efi"
1128     fi
1129
1130     mkdir -p "${work_dir}/efiboot/loader/entries"
1131     cp "${script_path}/efiboot/loader/loader.conf" "${work_dir}/efiboot/loader/"
1132     cp "${script_path}/efiboot/loader/entries/uefi-shell-x86_64.conf" "${work_dir}/efiboot/loader/entries/"
1133     cp "${script_path}/efiboot/loader/entries/uefi-shell-full-x86_64.conf" "${work_dir}/efiboot/loader/entries/"
1134
1135
1136     sed "s|%ARCHISO_LABEL%|${iso_label}|g;
1137          s|%OS_NAME%|${os_name}|g;
1138          s|%INSTALL_DIR%|${install_dir}|g" \
1139         "${script_path}/efiboot/loader/entries/cd/archiso-x86_64-cd-${kernel}.conf" > "${work_dir}/efiboot/loader/entries/archiso-x86_64.conf"
1140
1141     cp "${work_dir}/iso/EFI/Shell_x64.efi" "${work_dir}/efiboot/EFI/"
1142     cp "${work_dir}/iso/EFI/Shell_Full_x64.efi" "${work_dir}/efiboot/EFI/"
1143
1144     umount -d "${work_dir}/efiboot"
1145 }
1146
1147 # Build airootfs filesystem image
1148 make_prepare() {
1149     cp -a -l -f "${work_dir}/${arch}/airootfs" "${work_dir}"
1150     ${mkalteriso} ${mkalteriso_option} -w "${work_dir}" -D "${install_dir}" pkglist
1151     pacman -Q --sysroot "${work_dir}/airootfs" > "${work_dir}/packages-full.list"
1152     ${mkalteriso} ${mkalteriso_option} -w "${work_dir}" -D "${install_dir}" ${gpg_key:+-g ${gpg_key}} -c "${sfs_comp}" -t "${sfs_comp_opt}" prepare
1153     remove "${work_dir}/airootfs"
1154
1155     if [[ "${cleaning}" = true ]]; then
1156         remove "${work_dir}/${arch}/airootfs"
1157     fi
1158 }
1159
1160 # Build ISO
1161 make_iso() {
1162     ${mkalteriso} ${mkalteriso_option} -w "${work_dir}" -D "${install_dir}" -L "${iso_label}" -P "${iso_publisher}" -A "${iso_application}" -o "${out_dir}" iso "${iso_filename}"
1163     _msg_info "The password for the live user and root is ${password}."
1164 }
1165
1166
1167 # Parse options
1168 options="${@}"
1169 _opt_short="a:bc:dg:hjk:lo:p:t:u:w:x"
1170 _opt_long="arch:,boot-splash,comp-type:,debug,gpgkey:,help,japanese,kernel:,cleaning,out:,password:,comp-opts:,user:,work:,bash-debug,nocolor,noconfirm,nodepend,gitversion,shmkalteriso,msgdebug,noloopmod,channellist"
1171 OPT=$(getopt -o ${_opt_short} -l ${_opt_long} -- "${@}")
1172 if [[ ${?} != 0 ]]; then
1173     exit 1
1174 fi
1175
1176 eval set -- "${OPT}"
1177 unset OPT _opt_short _opt_long
1178
1179 while :; do
1180     case ${1} in
1181         -a | --arch)
1182             arch="${2}"
1183             shift 2
1184             ;;
1185         -b | --boot-splash)
1186             boot_splash=true
1187             shift 1
1188             ;;
1189         -c | --comp-type)
1190             case "${2}" in
1191                 "gzip" | "lzma" | "lzo" | "lz4" | "xz" | "zstd") sfs_comp="${2}" ;;
1192                 *) _msg_error "Invaild compressors '${2}'" '1' ;;
1193             esac
1194             shift 2
1195             ;;
1196         -d | --debug) 
1197             debug=true
1198             shift 1
1199             ;;
1200         -g | --gpgkey)
1201             gpg_key="$2"
1202             shift 2
1203             ;;
1204         -h | --help)
1205             _usage
1206             exit 0
1207             ;;
1208         -j | --japanese)
1209             japanese=true
1210             shift 1
1211             ;;
1212         -k | --kernel)
1213             if [[ -n $(cat ${script_path}/system/kernel_list-${arch} | grep -h -v ^'#' | grep -x "${2}") ]]; then
1214                 kernel="${2}"
1215             else
1216                 _msg_error "Invalid kernel ${2}" "1"
1217             fi
1218             shift 2
1219             ;;
1220         -l | --cleaning)
1221             cleaning=true
1222             shift 1
1223             ;;
1224         -o | --out)
1225             out_dir="${2}"
1226             shift 2
1227             ;;
1228         -p | --password)
1229             password="${2}"
1230             shift 2
1231             ;;
1232         -t | --comp-opts)
1233             sfs_comp_opt="${2}"
1234             shift 2
1235             ;;
1236         -u | --user)
1237             customized_username=true
1238             username="$(echo -n "${2}" | sed 's/ //g' |tr '[A-Z]' '[a-z]')"
1239             shift 2
1240             ;;
1241         -w | --work)
1242             work_dir="${2}"
1243             shift 2
1244             ;;
1245         -x | --bash-debug)
1246             debug=true
1247             bash_debug=true
1248             shift 1
1249             ;;
1250         --noconfirm)
1251             noconfirm=true
1252             shift 1
1253             ;;
1254         --nodepend)
1255             nodepend=true
1256             shift 1
1257             ;;
1258         --nocolor)
1259             nocolor=true
1260             shift 1
1261             ;;
1262         --gitversion)
1263             if [[ -d "${script_path}/.git" ]]; then
1264                 gitversion=true
1265             else
1266                 _msg_error "There is no git directory. You need to use git clone to use this feature." "1"
1267             fi
1268             shift 1
1269             ;;
1270         --shmkalteriso)
1271             shmkalteriso=true
1272             shift 1
1273             ;;
1274         --msgdebug)
1275             msgdebug=true;
1276             shift 1
1277             ;;
1278         --noloopmod)
1279             noloopmod=true
1280             shift 1
1281             ;;
1282         --channellist)
1283             show_channel_list
1284             shift 1
1285             ;;
1286         --)
1287             shift
1288             break
1289             ;;
1290         *)
1291             _msg_error "Invalid argument '${1}'"
1292             _usage 1
1293             ;;
1294     esac
1295 done
1296
1297
1298 # Check root.
1299 if [[ ${EUID} -ne 0 ]]; then
1300     _msg_warn "This script must be run as root." >&2
1301     # echo "Use -h to display script details." >&2
1302     # _usage 1
1303     _msg_warn "Re-run 'sudo ${0} ${options}'"
1304     sudo ${0} ${options}
1305     exit 1
1306 fi
1307
1308 # Show alteriso version
1309 if [[ -d "${script_path}/.git" ]]; then
1310     cd  "${script_path}"
1311     _msg_debug "The version of alteriso is $(git describe --long --tags | sed 's/\([^-]*-g\)/r\1/;s/-/./g')."
1312     cd - > /dev/null 2>&1
1313 fi
1314
1315 # Show config message
1316 [[ -f "${defaultconfig}" ]] && _msg_debug "The settings have been overwritten by the ${defaultconfig}"
1317
1318 # Debug mode
1319 mkalteriso_option="-a ${arch} -v"
1320 if [[ "${bash_debug}" = true ]]; then
1321     set -x -v
1322     mkalteriso_option="${mkalteriso_option} -x"
1323 fi
1324
1325 # Pacman configuration file used only when building
1326 build_pacman_conf=${script_path}/system/pacman-${arch}.conf
1327
1328 # Set rebuild config file
1329 rebuildfile="${work_dir}/build_options"
1330
1331
1332 # Parse channels
1333 set +eu
1334 if [[ -n "${1}" ]]; then
1335     channel_name="${1}"
1336
1337     # Channel list
1338     # check_channel <channel name>
1339     check_channel() {
1340         local channel_list
1341         local i
1342         channel_list=()
1343         for i in $(ls -l "${script_path}"/channels/ | awk '$1 ~ /d/ {print $9 }'); do
1344             if [[ -n $(ls "${script_path}"/channels/${i}) ]] && [[ ! ${i} = "share" ]]; then
1345                 if [[ ! $(echo "${i}" | sed 's/^.*\.\([^\.]*\)$/\1/') = "add" ]]; then
1346                     if [[ ! -d "${script_path}/channels/${i}.add" ]]; then
1347                         channel_list="${channel_list[@]} ${i}"
1348                     fi
1349                 else
1350                     channel_list="${channel_list[@]} ${i}"
1351                 fi
1352             fi
1353         done
1354         for i in ${channel_list[@]}; do
1355             if [[ $(echo "${i}" | sed 's/^.*\.\([^\.]*\)$/\1/') = "add" ]]; then
1356                 if [[ $(echo ${i} | sed 's/\.[^\.]*$//') = ${1} ]]; then
1357                     echo -n "true"
1358                     return 0
1359                 fi
1360             else
1361                 if [[ ${i} = ${1} ]]; then
1362                     echo -n "true"
1363                     return 0
1364                 fi
1365             fi
1366         done
1367         if [[ "${channel_name}" = "rebuild" ]] || [[ "${channel_name}" = "clean" ]]; then
1368             echo -n "true"
1369             return 0
1370         else
1371             echo -n "false"
1372             return 1
1373         fi
1374     }
1375
1376     if [[ $(check_channel "${channel_name}") = false ]]; then
1377         _msg_error "Invalid channel ${channel_name}" "1"
1378     fi
1379
1380     if [[ -d "${script_path}"/channels/${channel_name}.add ]]; then
1381         channel_name="${channel_name}.add"
1382     elif [[ "${channel_name}" = "rebuild" ]]; then
1383         if [[ -f "${rebuildfile}" ]]; then
1384                 rebuild=true
1385         else
1386             _msg_error "The previous build information is not in the working directory." "1"
1387         fi
1388     fi
1389
1390     if [[ ! "${channel_name}" == "rebuild" ]]; then
1391         _msg_debug "channel path is ${script_path}/channels/${channel_name}"
1392     fi
1393 fi
1394
1395 # Check architecture and kernel for each channel
1396 if [[ ! "${channel_name}" = "rebuild" ]] && [[ ! "${channel_name}" = "clean" ]]; then
1397     # architecture
1398     if [[ -z $(cat "${script_path}/channels/${channel_name}/architecture" | grep -h -v ^'#' | grep -x "${arch}") ]]; then
1399         _msg_error "${channel_name} channel does not support current architecture (${arch})." "1"
1400     fi
1401
1402     # kernel
1403     if [[ -f "${script_path}/channels/${channel_name}/kernel_list-${arch}" ]]; then
1404         if [[ -z $(cat "${script_path}/channels/${channel_name}/kernel_list-${arch}" | grep -h -v ^'#' | grep -x "${kernel}") ]]; then
1405             _msg_error "This kernel is currently not supported on this channel." "1"
1406         fi
1407     fi
1408 fi
1409
1410 # Run clean
1411 if [[ "${channel_name}" = "clean" ]]; then
1412     umount_chroot
1413     remove "${script_path}/menuconfig/build"
1414         remove "${script_path}/system/cpp-src/mkalteriso/build"
1415         remove "${script_path}/menuconfig-script/kernel_choice"
1416     remove_work
1417     remove "${rebuildfile}"
1418     remove "${script_path}/temp"
1419     exit 0
1420 fi
1421
1422 # Check the value of a variable that can only be set to true or false.
1423 check_bool() {
1424     local _value="$(eval echo '$'${1})"
1425     _msg_debug -n "Checking ${1}..."
1426     if [[ "${debug}" = true ]]; then
1427         echo -e " ${_value}"
1428     fi
1429     if [[ ! -v "${1}" ]]; then
1430         echo; _msg_error "The variable name ${1} is empty." "1"
1431     elif [[ ! "${_value}" = "true" ]] && [[ ! "${_value}" = "false" ]]; then
1432         echo; _msg_error "The variable name ${1} is not of bool type." "1"
1433     fi
1434 }
1435
1436 if [[ "${debug}" =  true ]]; then
1437     echo
1438 fi
1439 check_bool boot_splash
1440 check_bool debug
1441 check_bool bash_debug
1442 check_bool rebuild
1443 check_bool japanese
1444 check_bool cleaning
1445 check_bool noconfirm
1446 check_bool nodepend
1447 check_bool nocolor
1448 check_bool shmkalteriso
1449 check_bool msgdebug
1450 check_bool customized_username
1451 check_bool noloopmod
1452 check_bool nochname
1453
1454 if [[ "${debug}" =  true ]]; then
1455     echo
1456 fi
1457
1458 set -eu
1459
1460 prepare_build
1461 show_settings
1462 run_once make_pacman_conf
1463 run_once make_basefs
1464 run_once make_packages
1465 run_once make_customize_airootfs
1466 run_once make_setup_mkinitcpio
1467 run_once make_boot
1468 run_once make_boot_extra
1469 run_once make_syslinux
1470 run_once make_isolinux
1471 run_once make_efi
1472 run_once make_efiboot
1473 run_once make_prepare
1474 run_once make_iso
1475
1476 if [[ "${cleaning}" = true ]]; then
1477     remove_work
1478 fi