OSDN Git Service

[update] : change open help file browser on customize_airootfs
[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 # Display channel list
359 show_channel_list() {
360     local i
361     for i in $(ls -l "${script_path}"/channels/ | awk '$1 ~ /d/ {print $9 }'); do
362         if [[ -n $(ls "${script_path}"/channels/${i}) ]] && [[ ! ${i} = "share" ]]; then
363             if [[ ! $(echo "${i}" | sed 's/^.*\.\([^\.]*\)$/\1/') = "add" ]]; then
364                 if [[ ! -d "${script_path}/channels/${i}.add" ]]; then
365                     echo -n "${i} "
366                 fi
367             else
368                 echo -n "${i} "
369             fi
370         fi
371     done
372     echo
373     exit 0
374 }
375
376
377 # Preparation for build
378 prepare_build() {
379     # Build mkalteriso
380     if [[ "${shmkalteriso}" = false ]]; then
381         mkalteriso="${script_path}/system/mkalteriso"
382         cd "${script_path}"
383         _msg_info "Building mkalteriso..."
384         if [[ "${debug}" = true ]]; then
385             make mkalteriso
386             echo
387         else
388             make mkalteriso > /dev/null 2>&1
389         fi
390         cd - > /dev/null 2>&1
391     else
392         mkalteriso="${script_path}/system/mkalteriso.sh"
393     fi
394
395     # Create a working directory.
396     [[ ! -d "${work_dir}" ]] && mkdir -p "${work_dir}"
397
398
399     # Check work dir
400     if [[ -n $(ls -a "${work_dir}" 2> /dev/null | grep -xv ".." | grep -xv ".") ]] && [[ ! "${rebuild}" = true ]]; then
401         umount_chroot
402         _msg_info "Deleting the contents of ${work_dir}..."
403         remove "${work_dir%/}"/*
404     fi
405
406
407     # 強制終了時に作業ディレクトリを削除する
408     local trap_remove_work
409     trap_remove_work() {
410         local status=${?}
411         echo
412         remove "${work_dir}"
413         exit ${status}
414     }
415     trap 'trap_remove_work' 1 2 3 15
416
417     # Save build options
418     local save_var
419     save_var() {
420         local out_file="${rebuildfile}"
421         local i
422         echo "#!/usr/bin/env bash" > "${out_file}"
423         echo "# Build options are stored here." >> "${out_file}"
424         for i in ${@}; do
425             echo -n "${i}=" >> "${out_file}"
426             echo -n '"' >> "${out_file}"
427             eval echo -n '$'{${i}} >> "${out_file}"
428             echo '"' >> "${out_file}"
429         done
430     }
431     if [[ ${rebuild} = false ]]; then
432         # If there is pacman.conf for each channel, use that for building
433         if [[ -f "${script_path}/channels/${channel_name}/pacman-${arch}.conf" ]]; then
434             build_pacman_conf="${script_path}/channels/${channel_name}/pacman-${arch}.conf"
435         fi
436
437         # If there is config for share channel. load that.
438         load_config "${script_path}/channels/share/config.any"
439         load_config ${script_path}/channels/share/config.${arch}
440
441         # If there is config for each channel. load that.
442         load_config "${script_path}/channels/${channel_name}/config.any"
443         load_config "${script_path}/channels/${channel_name}/config.${arch}"
444
445         # Set username
446         if [[ "${customized_username}" = false ]]; then
447             username="${defaultusername}"
448         fi
449
450         # gitversion
451         if [[ "${gitversion}" = true ]]; then
452             cd ${script_path}
453             iso_version=${iso_version}-$(git rev-parse --short HEAD)
454             cd - > /dev/null 2>&1
455         fi
456     
457         # Generate iso file name.
458         local _channel_name
459         if [[ $(echo "${channel_name}" | sed 's/^.*\.\([^\.]*\)$/\1/') = "add" ]]; then
460             _channel_name="$(echo ${channel_name} | sed 's/\.[^\.]*$//')"
461         else
462             _channel_name="${channel_name}"
463         fi
464         if [[ "${japanese}" = true ]]; then
465             _channel_name="${_channel_name}-jp"
466         fi
467         if [[ "${nochname}" = true ]]; then
468             iso_filename="${iso_name}-${iso_version}-${arch}.iso"
469         else
470             iso_filename="${iso_name}-${_channel_name}-${iso_version}-${arch}.iso"
471         fi
472         _msg_debug "Iso filename is ${iso_filename}"
473
474         # Save the value of the variable for use in rebuild.
475         save_var \
476             arch \
477             os_name \
478             iso_name \
479             iso_label \
480             iso_publisher \
481             iso_application \
482             iso_version \
483             iso_filename \
484             install_dir \
485             work_dir \
486             out_dir \
487             gpg_key \
488             mkalteriso_option \
489             password \
490             boot_splash \
491             kernel \
492             theme_name \
493             theme_pkg \
494             sfs_comp \
495             sfs_comp_opt \
496             debug \
497             japanese \
498             channel_name \
499             cleaning \
500             username \
501             mkalteriso \
502             usershell \
503             shmkalteriso \
504             nocolor \
505             build_pacman_conf \
506             defaultconfig \
507             msgdebug \
508             defaultusername \
509             customized_username \
510             gitversion \
511             noloopmod
512     else
513         # Load rebuild file
514         load_config "${rebuildfile}"
515         _msg_debug "Iso filename is ${iso_filename}"
516
517         # Delete the lock file.
518         # remove "$(ls ${work_dir}/* | grep "build.make")"
519     fi
520
521     # Unmount
522     local mount
523     for mount in $(mount | awk '{print $3}' | grep $(realpath ${work_dir})); do
524         _msg_info "Unmounting ${mount}"
525         umount "${mount}"
526     done
527
528      # Check packages
529     if [[ "${nodepend}" = false ]] && [[ "${arch}" = $(uname -m) ]] ; then
530         local installed_pkg
531         local installed_ver
532         local check_pkg
533         local check_failed=false
534         local pkg
535
536         installed_pkg=($(pacman -Q | awk '{print $1}'))
537         installed_ver=($(pacman -Q | awk '{print $2}'))
538
539         check_pkg() {
540             local i
541             local ver
542             for i in $(seq 0 $(( ${#installed_pkg[@]} - 1 ))); do
543                 if [[ "${installed_pkg[${i}]}" = ${1} ]]; then
544                     ver=$(pacman -Sp --print-format '%v' --config ${build_pacman_conf} ${1} 2> /dev/null)
545                     if [[ "${installed_ver[${i}]}" = "${ver}" ]]; then
546                         echo -n "installed"
547                         return 0
548                     elif [[ -z ${ver} ]]; then
549                         echo "norepo"
550                         return 0
551                     else
552                         echo -n "old"
553                         return 0
554                     fi
555                 fi
556             done
557             echo -n "not"
558             return 0
559         }
560         if [[ ${debug} = false ]]; then
561             _msg_info "Checking dependencies ..."
562         else
563             echo
564         fi
565         for pkg in ${dependence[@]}; do
566             _msg_debug -n "Checking ${pkg} ..."
567             case $(check_pkg ${pkg}) in
568                 "old") 
569                     [[ "${debug}" = true ]] && echo -ne " $(pacman -Q ${pkg} | awk '{print $2}')\n"
570                     _msg_warn "${pkg} is not the latest package."
571                     _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)"
572                     ;;
573                 "not")
574                     [[ "${debug}" = true ]] && echo
575                     _msg_error "${pkg} is not installed." ; check_failed=true
576                     ;;
577                 "norepo") 
578                     [[ "${debug}" = true ]] && echo
579                     _msg_warn "${pkg} is not a repository package."
580                     ;;
581                 "installed") [[ ${debug} = true ]] && echo -ne " $(pacman -Q ${pkg} | awk '{print $2}')\n" ;;
582             esac
583         done
584
585         if [[ "${check_failed}" = true ]]; then
586             exit 1
587         fi
588     fi
589
590     # Load loop kernel module
591     if [[ "${noloopmod}" = false ]]; then
592         if [[ ! -d "/usr/lib/modules/$(uname -r)" ]]; then
593             _msg_error "The currently running kernel module could not be found."
594             _msg_error "Probably the system kernel has been updated."
595             _msg_error "Reboot your system to run the latest kernel." "1"
596         fi
597         if [[ -z $(lsmod | awk '{print $1}' | grep -x "loop") ]]; then
598             sudo modprobe loop
599         fi
600     fi
601 }
602
603
604 # Show settings.
605 show_settings() {
606     _msg_info "mkalteriso path is ${mkalteriso}"
607     echo
608     if [[ "${boot_splash}" = true ]]; then
609         _msg_info "Boot splash is enabled."
610         _msg_info "Theme is used ${theme_name}."
611     fi
612     _msg_info "Use the ${kernel} kernel."
613     _msg_info "Live username is ${username}."
614     _msg_info "Live user password is ${password}."
615     _msg_info "The compression method of squashfs is ${sfs_comp}."
616     if [[ $(echo "${channel_name}" | sed 's/^.*\.\([^\.]*\)$/\1/') = "add" ]]; then
617         _msg_info "Use the $(echo ${channel_name} | sed 's/\.[^\.]*$//') channel."
618     else
619         _msg_info "Use the ${channel_name} channel."
620     fi
621     [[ "${japanese}" = true ]] && _msg_info "Japanese mode has been activated."
622     _msg_info "Build with architecture ${arch}."
623     echo
624     if [[ ${noconfirm} = false ]]; then
625         echo "Press Enter to continue or Ctrl + C to cancel."
626         read
627     fi
628     trap 1 2 3 15
629     trap 'umount_trap' 1 2 3 15
630 }
631
632
633 # Setup custom pacman.conf with current cache directories.
634 make_pacman_conf() {
635     _msg_debug "Use ${build_pacman_conf}"
636     local _cache_dirs
637     _cache_dirs=($(pacman -v 2>&1 | grep '^Cache Dirs:' | sed 's/Cache Dirs:\s*//g'))
638     sed -r "s|^#?\\s*CacheDir.+|CacheDir = $(echo -n ${_cache_dirs[@]})|g" ${build_pacman_conf} > "${work_dir}/pacman-${arch}.conf"
639 }
640
641 # Base installation, plus needed packages (airootfs)
642 make_basefs() {
643     ${mkalteriso} ${mkalteriso_option} -w "${work_dir}/${arch}" -C "${work_dir}/pacman-${arch}.conf" -D "${install_dir}" init
644     # ${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
645     ${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
646
647     # Install plymouth.
648     if [[ "${boot_splash}" = true ]]; then
649         if [[ -n "${theme_pkg}" ]]; then
650             ${mkalteriso} ${mkalteriso_option} -w "${work_dir}/${arch}" -C "${work_dir}/pacman-${arch}.conf" -D "${install_dir}" -p "plymouth ${theme_pkg}" install
651         else
652             ${mkalteriso} ${mkalteriso_option} -w "${work_dir}/${arch}" -C "${work_dir}/pacman-${arch}.conf" -D "${install_dir}" -p "plymouth" install
653         fi
654     fi
655
656     # Install kernel.
657     if [[ ! "${kernel}" = "core" ]]; then
658         ${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
659     else
660         ${mkalteriso} ${mkalteriso_option} -w "${work_dir}/${arch}" -C "${work_dir}/pacman-${arch}.conf" -D "${install_dir}" -p "linux linux-headers broadcom-wl" install
661     fi
662 }
663
664 # Additional packages (airootfs)
665 make_packages() {
666     # インストールするパッケージのリストを読み込み、配列pkglistに代入します。
667     installpkglist() {
668         set +e
669         local _loadfilelist _pkg _file jplist excludefile excludelist _pkglist
670
671         #-- Detect package list to load --#
672         # Append the file in the share directory to the file to be read.
673
674         # Package list for Japanese
675         jplist="${script_path}/channels/share/packages.${arch}/jp.${arch}"
676
677         # Package list for non-Japanese
678         nojplist="${script_path}/channels/share/packages.${arch}/non-jp.${arch}"
679
680         if [[ "${japanese}" = true ]]; then
681             _loadfilelist=($(ls "${script_path}"/channels/share/packages.${arch}/*.${arch} | grep -xv "${nojplist}"))
682         else
683             _loadfilelist=($(ls "${script_path}"/channels/share/packages.${arch}/*.${arch} | grep -xv "${jplist}"))
684         fi
685
686
687         # Add the files for each channel to the list of files to read.
688
689         # Package list for Japanese
690         jplist="${script_path}/channels/${channel_name}/packages.${arch}/jp.${arch}"
691
692         # Package list for non-Japanese
693         nojplist="${script_path}/channels/${channel_name}/packages.${arch}/non-jp.${arch}"
694
695         if [[ "${japanese}" = true ]]; then
696             # If Japanese is enabled, add it to the list of files to read other than non-jp.
697             _loadfilelist=(${_loadfilelist[@]} $(ls "${script_path}"/channels/${channel_name}/packages.${arch}/*.${arch} | grep -xv "${nojplist}"))
698         else
699             # If Japanese is disabled, add it to the list of files to read other than jp.
700             _loadfilelist=(${_loadfilelist[@]} $(ls "${script_path}"/channels/${channel_name}/packages.${arch}/*.${arch} | grep -xv ${jplist}))
701         fi
702
703
704         #-- Read package list --#
705         # Read the file and remove comments starting with # and add it to the list of packages to install.
706         for _file in ${_loadfilelist[@]}; do
707             _msg_debug "Loaded package file ${_file}"
708             pkglist=( ${pkglist[@]} "$(grep -h -v ^'#' ${_file})" )
709         done
710         if [[ ${debug} = true ]]; then
711             sleep 3
712         fi
713
714         # Exclude packages from the share exclusion list
715         excludefile="${script_path}/channels/share/packages.${arch}/exclude"
716         if [[ -f "${excludefile}" ]]; then
717             excludelist=( $(grep -h -v ^'#' "${excludefile}") )
718
719             # 現在のpkglistをコピーする
720             _pkglist=(${pkglist[@]})
721             unset pkglist
722             for _pkg in ${_pkglist[@]}; do
723                 # もし変数_pkgの値が配列excludelistに含まれていなかったらpkglistに追加する
724                 if [[ ! $(printf '%s\n' "${excludelist[@]}" | grep -qx "${_pkg}"; echo -n ${?} ) = 0 ]]; then
725                     pkglist=(${pkglist[@]} "${_pkg}")
726                 fi
727             done
728         fi
729
730         if [[ -n "${excludelist}" ]]; then
731             _msg_debug "The following packages have been removed from the installation list."
732             _msg_debug "Excluded packages:" "${excludelist[@]}"
733         fi
734
735         # Exclude packages from the exclusion list for each channel
736         excludefile="${script_path}/channels/${channel_name}/packages.${arch}/exclude"
737         if [[ -f "${excludefile}" ]]; then
738             excludelist=( $(grep -h -v ^'#' "${excludefile}") )
739         
740             # 現在のpkglistをコピーする
741             _pkglist=(${pkglist[@]})
742             unset pkglist
743             for _pkg in ${_pkglist[@]}; do
744                 # もし変数_pkgの値が配列excludelistに含まれていなかったらpkglistに追加する
745                 if [[ ! $(printf '%s\n' "${excludelist[@]}" | grep -qx "${_pkg}"; echo -n ${?} ) = 0 ]]; then
746                     pkglist=(${pkglist[@]} "${_pkg}")
747                 fi
748             done
749         fi
750         
751         # Sort the list of packages in abc order.
752         pkglist=(
753             "$(
754                 for _pkg in ${pkglist[@]}; do
755                     echo "${_pkg}"
756                 done \
757                 | sort
758             )"
759         )
760
761         set -e
762     }
763
764     installpkglist
765
766     # _msg_debug "${pkglist[@]}"
767
768     # Create a list of packages to be finally installed as packages.list directly under the working directory.
769     echo "# The list of packages that is installed in live cd." > ${work_dir}/packages.list
770     echo "#" >> ${work_dir}/packages.list
771     echo >> ${work_dir}/packages.list
772     for _pkg in ${pkglist[@]}; do
773         echo ${_pkg} >> ${work_dir}/packages.list
774     done
775
776     # Install packages on airootfs
777     ${mkalteriso} ${mkalteriso_option} -w "${work_dir}/${arch}" -C "${work_dir}/pacman-${arch}.conf" -D "${install_dir}" -p "${pkglist[@]}" install
778 }
779
780 # Customize installation (airootfs)
781 make_customize_airootfs() {
782     # Overwrite airootfs with customize_airootfs.
783     local copy_airootfs
784
785     copy_airootfs() {
786         local i 
787         for i in "${@}"; do
788             local _dir="${i%/}"
789             if [[ -d "${_dir}" ]]; then
790                 cp -af "${_dir}"/* "${work_dir}/${arch}/airootfs"
791             fi
792         done
793     }
794
795     copy_airootfs "${script_path}/channels/share/airootfs.any"
796     copy_airootfs "${script_path}/channels/share/airootfs.${arch}"
797     copy_airootfs "${script_path}/channels/${channel_name}/airootfs.any"
798     copy_airootfs "${script_path}/channels/${channel_name}/airootfs.${arch}"
799
800     # Replace /etc/mkinitcpio.conf if Plymouth is enabled.
801     if [[ "${boot_splash}" = true ]]; then
802         cp "${script_path}/mkinitcpio/mkinitcpio-plymouth.conf" "${work_dir}/${arch}/airootfs/etc/mkinitcpio.conf"
803     fi
804
805     # Code to use common pacman.conf in archiso.
806     # cp "${script_path}/pacman.conf" "${work_dir}/${arch}/airootfs/etc"
807     # cp "${build_pacman_conf}" "${work_dir}/${arch}/airootfs/etc"
808
809     # Get the optimal mirror list.
810     local mirrorlisturl mirrorlisturl_all  mirrorlisturl_jp
811
812     case "${arch}" in
813         "x86_64")
814             mirrorlisturl_jp='https://www.archlinux.org/mirrorlist/?country=JP'
815             mirrorlisturl_all='https://www.archlinux.org/mirrorlist/?country=all'
816             ;;
817         "i686")
818             mirrorlisturl_jp='https://archlinux32.org/mirrorlist/?country=jp'
819             mirrorlisturl_all='https://archlinux32.org/mirrorlist/?country=all'
820             ;;
821     esac
822
823     if [[ "${japanese}" = true ]]; then
824         mirrorlisturl="${mirrorlisturl_jp}"
825     else
826         mirrorlisturl="${mirrorlisturl_all}"
827     fi
828     curl -o "${work_dir}/${arch}/airootfs/etc/pacman.d/mirrorlist" "${mirrorlisturl}"
829
830     # Add install guide to /root (disabled)
831     # lynx -dump -nolist 'https://wiki.archlinux.org/index.php/Installation_Guide?action=render' >> ${work_dir}/${arch}/airootfs/root/install.txt
832
833
834     # customize_airootfs.sh options
835     # -b            : Enable boot splash.
836     # -d            : Enable debug mode.
837     # -i <inst_dir> : Set install dir
838     # -j            : Enable Japanese.
839     # -k <kernel>   : Set kernel name.
840     # -o <os name>  : Set os name.
841     # -p <password> : Set password.
842     # -s <shell>    : Set user shell.
843     # -t            : Set plymouth theme.
844     # -u <username> : Set live user name.
845     # -x            : Enable bash debug mode.
846     # -r            : Enable rebuild.
847
848
849     # Generate options of customize_airootfs.sh.
850     local addition_options
851     local share_options
852     addition_options=
853     if [[ ${boot_splash} = true ]]; then
854         if [[ -z ${theme_name} ]]; then
855             addition_options="${addition_options} -b"
856         else
857             addition_options="${addition_options} -b -t ${theme_name}"
858         fi
859     fi
860     if [[ ${debug} = true ]]; then
861         addition_options="${addition_options} -d"
862     fi
863     if [[ ${bash_debug} = true ]]; then
864         addition_options="${addition_options} -x"
865     fi
866     if [[ ${japanese} = true ]]; then
867         addition_options="${addition_options} -j"
868     fi
869     if [[ ${rebuild} = true ]]; then
870         addition_options="${addition_options} -r"
871     fi
872
873     share_options="-p '${password}' -k '${kernel}' -u '${username}' -o '${os_name}' -i '${install_dir}' -s '${usershell}' -a '${arch}'"
874
875
876     # X permission
877     if [[ -f ${work_dir}/${arch}/airootfs/root/customize_airootfs.sh ]]; then
878         chmod 755 "${work_dir}/${arch}/airootfs/root/customize_airootfs.sh"
879     fi
880     if [[ -f "${work_dir}/${arch}/airootfs/root/customize_airootfs.sh" ]]; then
881         chmod 755 "${work_dir}/${arch}/airootfs/root/customize_airootfs.sh"
882     fi
883     if [[ -f "${work_dir}/${arch}/airootfs/root/customize_airootfs_${channel_name}.sh" ]]; then
884         chmod 755 "${work_dir}/${arch}/airootfs/root/customize_airootfs_${channel_name}.sh"
885     elif [[ -f "${work_dir}/${arch}/airootfs/root/customize_airootfs_$(echo ${channel_name} | sed 's/\.[^\.]*$//').sh" ]]; then
886         chmod 755 "${work_dir}/${arch}/airootfs/root/customize_airootfs_$(echo ${channel_name} | sed 's/\.[^\.]*$//').sh"
887     fi
888
889     # Execute customize_airootfs.sh.
890     if [[ -z ${addition_options} ]]; then
891         ${mkalteriso} ${mkalteriso_option} \
892             -w "${work_dir}/${arch}" \
893             -C "${work_dir}/pacman-${arch}.conf" \
894             -D "${install_dir}" \
895             -r "/root/customize_airootfs.sh ${share_options}" \
896             run
897         if [[ -f "${work_dir}/${arch}/airootfs/root/customize_airootfs_${channel_name}.sh" ]]; then
898             ${mkalteriso} ${mkalteriso_option} \
899                 -w "${work_dir}/${arch}" \
900                 -C "${work_dir}/pacman-${arch}.conf" \
901                 -D "${install_dir}" \
902                 -r "/root/customize_airootfs_${channel_name}.sh ${share_options}" \
903                 run
904         elif [[ -f "${work_dir}/${arch}/airootfs/root/customize_airootfs_$(echo ${channel_name} | sed 's/\.[^\.]*$//').sh" ]]; then
905             ${mkalteriso} ${mkalteriso_option} \
906                 -w "${work_dir}/${arch}" \
907                 -C "${work_dir}/pacman-${arch}.conf" \
908                 -D "${install_dir}" \
909                 -r "/root/customize_airootfs_$(echo ${channel_name} | sed 's/\.[^\.]*$//').sh ${share_options}" \
910                 run
911         fi
912     else
913         ${mkalteriso} ${mkalteriso_option} \
914             -w "${work_dir}/${arch}" \
915             -C "${work_dir}/pacman-${arch}.conf" \
916             -D "${install_dir}" \
917             -r "/root/customize_airootfs.sh ${share_options} ${addition_options}" \
918             run
919
920         if [[ -f "${work_dir}/${arch}/airootfs/root/customize_airootfs_${channel_name}.sh" ]]; then
921             ${mkalteriso} ${mkalteriso_option} \
922                 -w "${work_dir}/${arch}" \
923                 -C "${work_dir}/pacman-${arch}.conf" \
924                 -D "${install_dir}" \
925                 -r "/root/customize_airootfs_${channel_name}.sh ${share_options} ${addition_options}" \
926                 run
927         elif [[ -f "${work_dir}/${arch}/airootfs/root/customize_airootfs_$(echo ${channel_name} | sed 's/\.[^\.]*$//').sh" ]]; then
928             ${mkalteriso} ${mkalteriso_option} \
929                 -w "${work_dir}/${arch}" \
930                 -C "${work_dir}/pacman-${arch}.conf" \
931                 -D "${install_dir}" \
932                 -r "/root/customize_airootfs_$(echo ${channel_name} | sed 's/\.[^\.]*$//').sh ${share_options} ${addition_options}" \
933                 run
934         fi
935     fi
936
937
938     # Delete customize_airootfs.sh.
939     remove "${work_dir}/${arch}/airootfs/root/customize_airootfs.sh"
940     remove "${work_dir}/${arch}/airootfs/root/customize_airootfs_${channel_name}.sh"
941 }
942
943 # Copy mkinitcpio archiso hooks and build initramfs (airootfs)
944 make_setup_mkinitcpio() {
945     local _hook
946     mkdir -p "${work_dir}/${arch}/airootfs/etc/initcpio/hooks"
947     mkdir -p "${work_dir}/${arch}/airootfs/etc/initcpio/install"
948     for _hook in "archiso" "archiso_shutdown" "archiso_pxe_common" "archiso_pxe_nbd" "archiso_pxe_http" "archiso_pxe_nfs" "archiso_loop_mnt"; do
949         cp "${script_path}/system/initcpio/hooks/${_hook}" "${work_dir}/${arch}/airootfs/etc/initcpio/hooks"
950         cp "${script_path}/system/initcpio/install/${_hook}" "${work_dir}/${arch}/airootfs/etc/initcpio/install"
951     done
952     sed -i "s|/usr/lib/initcpio/|/etc/initcpio/|g" "${work_dir}/${arch}/airootfs/etc/initcpio/install/archiso_shutdown"
953     cp "${script_path}/system/initcpio/install/archiso_kms" "${work_dir}/${arch}/airootfs/etc/initcpio/install"
954     cp "${script_path}/system/initcpio/archiso_shutdown" "${work_dir}/${arch}/airootfs/etc/initcpio"
955     if [[ "${boot_splash}" = true ]]; then
956         cp "${script_path}/mkinitcpio/mkinitcpio-archiso-plymouth.conf" "${work_dir}/${arch}/airootfs/etc/mkinitcpio-archiso.conf"
957     else
958         cp "${script_path}/mkinitcpio/mkinitcpio-archiso.conf" "${work_dir}/${arch}/airootfs/etc/mkinitcpio-archiso.conf"
959     fi
960     gnupg_fd=
961     if [[ "${gpg_key}" ]]; then
962       gpg --export "${gpg_key}" >"${work_dir}/gpgkey"
963       exec 17<>$"{work_dir}/gpgkey"
964     fi
965
966     if [[ ! ${kernel} = "core" ]]; then
967         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
968     else
969         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
970     fi
971
972     if [[ "${gpg_key}" ]]; then
973       exec 17<&-
974     fi
975 }
976
977 # Prepare kernel/initramfs ${install_dir}/boot/
978 make_boot() {
979     mkdir -p "${work_dir}/iso/${install_dir}/boot/${arch}"
980     cp "${work_dir}/${arch}/airootfs/boot/archiso.img" "${work_dir}/iso/${install_dir}/boot/${arch}/archiso.img"
981
982     if [[ ! "${kernel}" = "core" ]]; then
983         cp "${work_dir}/${arch}/airootfs/boot/vmlinuz-linux-${kernel}" "${work_dir}/iso/${install_dir}/boot/${arch}/vmlinuz-linux-${kernel}"
984     else
985         cp "${work_dir}/${arch}/airootfs/boot/vmlinuz-linux" "${work_dir}/iso/${install_dir}/boot/${arch}/vmlinuz-linux"
986     fi
987 }
988
989 # Add other aditional/extra files to ${install_dir}/boot/
990 make_boot_extra() {
991     cp "${work_dir}/${arch}/airootfs/boot/intel-ucode.img" "${work_dir}/iso/${install_dir}/boot/intel_ucode.img"
992     cp "${work_dir}/${arch}/airootfs/usr/share/licenses/intel-ucode/LICENSE" "${work_dir}/iso/${install_dir}/boot/intel_ucode.LICENSE"
993     cp "${work_dir}/${arch}/airootfs/boot/amd-ucode.img" "${work_dir}/iso/${install_dir}/boot/amd_ucode.img"
994     cp "${work_dir}/${arch}/airootfs/usr/share/licenses/amd-ucode/LICENSE.amd-ucode" "${work_dir}/iso/${install_dir}/boot/amd_ucode.LICENSE"
995 }
996
997 # Prepare /${install_dir}/boot/syslinux
998 make_syslinux() {
999     if [[ ! ${kernel} = "core" ]]; then
1000         _uname_r="$(file -b ${work_dir}/${arch}/airootfs/boot/vmlinuz-linux-${kernel} | awk 'f{print;f=0} /version/{f=1}' RS=' ')"
1001     else
1002         _uname_r="$(file -b ${work_dir}/${arch}/airootfs/boot/vmlinuz-linux | awk 'f{print;f=0} /version/{f=1}' RS=' ')"
1003     fi
1004     mkdir -p "${work_dir}/iso/${install_dir}/boot/syslinux"
1005
1006     for _cfg in ${script_path}/syslinux/${arch}/*.cfg; do
1007         sed "s|%ARCHISO_LABEL%|${iso_label}|g;
1008              s|%OS_NAME%|${os_name}|g;
1009              s|%INSTALL_DIR%|${install_dir}|g" "${_cfg}" > "${work_dir}/iso/${install_dir}/boot/syslinux/${_cfg##*/}"
1010     done
1011
1012     if [[ ${boot_splash} = true ]]; then
1013         sed "s|%ARCHISO_LABEL%|${iso_label}|g;
1014              s|%OS_NAME%|${os_name}|g;
1015              s|%INSTALL_DIR%|${install_dir}|g" \
1016              "${script_path}/syslinux/${arch}/pxe-plymouth/archiso_pxe-${kernel}.cfg" > "${work_dir}/iso/${install_dir}/boot/syslinux/archiso_pxe.cfg"
1017
1018         sed "s|%ARCHISO_LABEL%|${iso_label}|g;
1019              s|%OS_NAME%|${os_name}|g;
1020              s|%INSTALL_DIR%|${install_dir}|g" \
1021              "${script_path}/syslinux/${arch}/sys-plymouth/archiso_sys-${kernel}.cfg" > "${work_dir}/iso/${install_dir}/boot/syslinux/archiso_sys.cfg"
1022     else
1023         sed "s|%ARCHISO_LABEL%|${iso_label}|g;
1024              s|%OS_NAME%|${os_name}|g;
1025              s|%INSTALL_DIR%|${install_dir}|g" \
1026              "${script_path}/syslinux/${arch}/pxe/archiso_pxe-${kernel}.cfg" > "${work_dir}/iso/${install_dir}/boot/syslinux/archiso_pxe.cfg"
1027
1028         sed "s|%ARCHISO_LABEL%|${iso_label}|g;
1029              s|%OS_NAME%|${os_name}|g;
1030              s|%INSTALL_DIR%|${install_dir}|g" \
1031              "${script_path}/syslinux/${arch}/sys/archiso_sys-${kernel}.cfg" > "${work_dir}/iso/${install_dir}/boot/syslinux/archiso_sys.cfg"
1032     fi
1033
1034     if [[ -f "${script_path}/channels/${channel_name}/splash.png" ]]; then
1035         cp "${script_path}/channels/${channel_name}/splash.png" "${work_dir}/iso/${install_dir}/boot/syslinux"
1036     else
1037         cp "${script_path}/syslinux/${arch}/splash.png" "${work_dir}/iso/${install_dir}/boot/syslinux"
1038     fi
1039     cp "${work_dir}"/${arch}/airootfs/usr/lib/syslinux/bios/*.c32 "${work_dir}/iso/${install_dir}/boot/syslinux"
1040     cp "${work_dir}/${arch}/airootfs/usr/lib/syslinux/bios/lpxelinux.0" "${work_dir}/iso/${install_dir}/boot/syslinux"
1041     cp "${work_dir}/${arch}/airootfs/usr/lib/syslinux/bios/memdisk" "${work_dir}/iso/${install_dir}/boot/syslinux"
1042     mkdir -p "${work_dir}/iso/${install_dir}/boot/syslinux/hdt"
1043     gzip -c -9 "${work_dir}/${arch}/airootfs/usr/share/hwdata/pci.ids" > "${work_dir}/iso/${install_dir}/boot/syslinux/hdt/pciids.gz"
1044     gzip -c -9 "${work_dir}/${arch}/airootfs/usr/lib/modules/${_uname_r}/modules.alias" > "${work_dir}/iso/${install_dir}/boot/syslinux/hdt/modalias.gz"
1045 }
1046
1047 # Prepare /isolinux
1048 make_isolinux() {
1049     mkdir -p "${work_dir}/iso/isolinux"
1050
1051     sed "s|%INSTALL_DIR%|${install_dir}|g" \
1052         "${script_path}/system/isolinux.cfg" > "${work_dir}/iso/isolinux/isolinux.cfg"
1053     cp "${work_dir}/${arch}/airootfs/usr/lib/syslinux/bios/isolinux.bin" "${work_dir}/iso/isolinux/"
1054     cp "${work_dir}/${arch}/airootfs/usr/lib/syslinux/bios/isohdpfx.bin" "${work_dir}/iso/isolinux/"
1055     cp "${work_dir}/${arch}/airootfs/usr/lib/syslinux/bios/ldlinux.c32" "${work_dir}/iso/isolinux/"
1056 }
1057
1058 # Prepare /EFI
1059 make_efi() {
1060     mkdir -p "${work_dir}/iso/EFI/boot"
1061     cp "${work_dir}/${arch}/airootfs/usr/share/efitools/efi/HashTool.efi" "${work_dir}/iso/EFI/boot/"
1062     if [[ "${arch}" = "x86_64" ]]; then
1063         cp "${work_dir}/${arch}/airootfs/usr/share/efitools/efi/PreLoader.efi" "${work_dir}/iso/EFI/boot/bootx64.efi"
1064         cp "${work_dir}/${arch}/airootfs/usr/lib/systemd/boot/efi/systemd-bootx64.efi" "${work_dir}/iso/EFI/boot/loader.efi"
1065     fi
1066
1067     mkdir -p "${work_dir}/iso/loader/entries"
1068     cp "${script_path}/efiboot/loader/loader.conf" "${work_dir}/iso/loader/"
1069     cp "${script_path}/efiboot/loader/entries/uefi-shell-x86_64.conf" "${work_dir}/iso/loader/entries/"
1070     cp "${script_path}/efiboot/loader/entries/uefi-shell-full-x86_64.conf" "${work_dir}/iso/loader/entries/"
1071
1072     sed "s|%ARCHISO_LABEL%|${iso_label}|g;
1073          s|%OS_NAME%|${os_name}|g;
1074          s|%INSTALL_DIR%|${install_dir}|g" \
1075         "${script_path}/efiboot/loader/entries/usb/archiso-x86_64-usb-${kernel}.conf" > "${work_dir}/iso/loader/entries/archiso-x86_64.conf"
1076
1077     # edk2-shell based UEFI shell
1078     cp /usr/share/edk2-shell/x64/Shell.efi ${work_dir}/iso/EFI/Shell_x64.efi
1079     cp /usr/share/edk2-shell/x64/Shell_Full.efi ${work_dir}/iso/EFI/Shell_Full_x64.efi
1080 }
1081
1082 # Prepare efiboot.img::/EFI for "El Torito" EFI boot mode
1083 make_efiboot() {
1084     mkdir -p "${work_dir}/iso/EFI/archiso"
1085     truncate -s 64M "${work_dir}/iso/EFI/archiso/efiboot.img"
1086     mkfs.fat -n ARCHISO_EFI "${work_dir}/iso/EFI/archiso/efiboot.img"
1087
1088     mkdir -p "${work_dir}/efiboot"
1089     mount "${work_dir}/iso/EFI/archiso/efiboot.img" "${work_dir}/efiboot"
1090
1091     mkdir -p "${work_dir}/efiboot/EFI/archiso"
1092
1093     if [[ ! ${kernel} = "core" ]]; then
1094         cp "${work_dir}/iso/${install_dir}/boot/${arch}/vmlinuz-linux-${kernel}" "${work_dir}/efiboot/EFI/archiso/vmlinuz-linux-${kernel}.efi"
1095     else
1096         cp "${work_dir}/iso/${install_dir}/boot/${arch}/vmlinuz" "${work_dir}/efiboot/EFI/archiso/vmlinuz.efi"
1097     fi
1098
1099     cp "${work_dir}/iso/${install_dir}/boot/${arch}/archiso.img" "${work_dir}/efiboot/EFI/archiso/archiso.img"
1100
1101     cp "${work_dir}/iso/${install_dir}/boot/intel_ucode.img" "${work_dir}/efiboot/EFI/archiso/intel_ucode.img"
1102     cp "${work_dir}/iso/${install_dir}/boot/amd_ucode.img" "${work_dir}/efiboot/EFI/archiso/amd_ucode.img"
1103
1104     mkdir -p "${work_dir}/efiboot/EFI/boot"
1105     cp "${work_dir}/${arch}/airootfs/usr/share/efitools/efi/HashTool.efi" "${work_dir}/efiboot/EFI/boot/"
1106
1107     if [[ "${arch}" = "x86_64" ]]; then
1108         cp "${work_dir}/${arch}/airootfs/usr/share/efitools/efi/PreLoader.efi" "${work_dir}/efiboot/EFI/boot/bootx64.efi"
1109         cp "${work_dir}/${arch}/airootfs/usr/lib/systemd/boot/efi/systemd-bootx64.efi" "${work_dir}/efiboot/EFI/boot/loader.efi"
1110     fi
1111
1112     mkdir -p "${work_dir}/efiboot/loader/entries"
1113     cp "${script_path}/efiboot/loader/loader.conf" "${work_dir}/efiboot/loader/"
1114     cp "${script_path}/efiboot/loader/entries/uefi-shell-x86_64.conf" "${work_dir}/efiboot/loader/entries/"
1115     cp "${script_path}/efiboot/loader/entries/uefi-shell-full-x86_64.conf" "${work_dir}/efiboot/loader/entries/"
1116
1117
1118     sed "s|%ARCHISO_LABEL%|${iso_label}|g;
1119          s|%OS_NAME%|${os_name}|g;
1120          s|%INSTALL_DIR%|${install_dir}|g" \
1121         "${script_path}/efiboot/loader/entries/cd/archiso-x86_64-cd-${kernel}.conf" > "${work_dir}/efiboot/loader/entries/archiso-x86_64.conf"
1122
1123     cp "${work_dir}/iso/EFI/Shell_x64.efi" "${work_dir}/efiboot/EFI/"
1124     cp "${work_dir}/iso/EFI/Shell_Full_x64.efi" "${work_dir}/efiboot/EFI/"
1125
1126     umount -d "${work_dir}/efiboot"
1127 }
1128
1129 # Build airootfs filesystem image
1130 make_prepare() {
1131     cp -a -l -f "${work_dir}/${arch}/airootfs" "${work_dir}"
1132     ${mkalteriso} ${mkalteriso_option} -w "${work_dir}" -D "${install_dir}" pkglist
1133     pacman -Q --sysroot "${work_dir}/airootfs" > "${work_dir}/packages-full.list"
1134     ${mkalteriso} ${mkalteriso_option} -w "${work_dir}" -D "${install_dir}" ${gpg_key:+-g ${gpg_key}} -c "${sfs_comp}" -t "${sfs_comp_opt}" prepare
1135     remove "${work_dir}/airootfs"
1136
1137     if [[ "${cleaning}" = true ]]; then
1138         remove "${work_dir}/${arch}/airootfs"
1139     fi
1140 }
1141
1142 # Build ISO
1143 make_iso() {
1144     ${mkalteriso} ${mkalteriso_option} -w "${work_dir}" -D "${install_dir}" -L "${iso_label}" -P "${iso_publisher}" -A "${iso_application}" -o "${out_dir}" iso "${iso_filename}"
1145     _msg_info "The password for the live user and root is ${password}."
1146 }
1147
1148
1149 # Parse options
1150 options="${@}"
1151 _opt_short="a:bc:dg:hjk:lo:p:t:u:w:x"
1152 _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"
1153 OPT=$(getopt -o ${_opt_short} -l ${_opt_long} -- "${@}")
1154 if [[ ${?} != 0 ]]; then
1155     exit 1
1156 fi
1157
1158 eval set -- "${OPT}"
1159 unset OPT _opt_short _opt_long
1160
1161 while :; do
1162     case ${1} in
1163         -a | --arch)
1164             arch="${2}"
1165             shift 2
1166             ;;
1167         -b | --boot-splash)
1168             boot_splash=true
1169             shift 1
1170             ;;
1171         -c | --comp-type)
1172             case "${2}" in
1173                 "gzip" | "lzma" | "lzo" | "lz4" | "xz" | "zstd") sfs_comp="${2}" ;;
1174                 *) _msg_error "Invaild compressors '${2}'" '1' ;;
1175             esac
1176             shift 2
1177             ;;
1178         -d | --debug) 
1179             debug=true
1180             shift 1
1181             ;;
1182         -g | --gpgkey)
1183             gpg_key="$2"
1184             shift 2
1185             ;;
1186         -h | --help)
1187             _usage
1188             exit 0
1189             ;;
1190         -j | --japanese)
1191             japanese=true
1192             shift 1
1193             ;;
1194         -k | --kernel)
1195             if [[ -n $(cat ${script_path}/system/kernel_list-${arch} | grep -h -v ^'#' | grep -x "${2}") ]]; then
1196                 kernel="${2}"
1197             else
1198                 _msg_error "Invalid kernel ${2}" "1"
1199             fi
1200             shift 2
1201             ;;
1202         -l | --cleaning)
1203             cleaning=true
1204             shift 1
1205             ;;
1206         -o | --out)
1207             out_dir="${2}"
1208             shift 2
1209             ;;
1210         -p | --password)
1211             password="${2}"
1212             shift 2
1213             ;;
1214         -t | --comp-opts)
1215             sfs_comp_opt="${2}"
1216             shift 2
1217             ;;
1218         -u | --user)
1219             customized_username=true
1220             username="$(echo -n "${2}" | sed 's/ //g' |tr '[A-Z]' '[a-z]')"
1221             shift 2
1222             ;;
1223         -w | --work)
1224             work_dir="${2}"
1225             shift 2
1226             ;;
1227         -x | --bash-debug)
1228             debug=true
1229             bash_debug=true
1230             shift 1
1231             ;;
1232         --noconfirm)
1233             noconfirm=true
1234             shift 1
1235             ;;
1236         --nodepend)
1237             nodepend=true
1238             shift 1
1239             ;;
1240         --nocolor)
1241             nocolor=true
1242             shift 1
1243             ;;
1244         --gitversion)
1245             if [[ -d "${script_path}/.git" ]]; then
1246                 gitversion=true
1247             else
1248                 _msg_error "There is no git directory. You need to use git clone to use this feature." "1"
1249             fi
1250             shift 1
1251             ;;
1252         --shmkalteriso)
1253             shmkalteriso=true
1254             shift 1
1255             ;;
1256         --msgdebug)
1257             msgdebug=true;
1258             shift 1
1259             ;;
1260         --noloopmod)
1261             noloopmod=true
1262             shift 1
1263             ;;
1264         --channellist)
1265             show_channel_list
1266             shift 1
1267             ;;
1268         --)
1269             shift
1270             break
1271             ;;
1272         *)
1273             _msg_error "Invalid argument '${1}'"
1274             _usage 1
1275             ;;
1276     esac
1277 done
1278
1279
1280 # Check root.
1281 if [[ ${EUID} -ne 0 ]]; then
1282     _msg_warn "This script must be run as root." >&2
1283     # echo "Use -h to display script details." >&2
1284     # _usage 1
1285     _msg_warn "Re-run 'sudo ${0} ${options}'"
1286     sudo ${0} ${options}
1287     exit 1
1288 fi
1289
1290 # Show alteriso version
1291 if [[ -d "${script_path}/.git" ]]; then
1292     cd  "${script_path}"
1293     _msg_debug "The version of alteriso is $(git describe --long --tags | sed 's/\([^-]*-g\)/r\1/;s/-/./g')."
1294     cd - > /dev/null 2>&1
1295 fi
1296
1297 # Show config message
1298 [[ -f "${defaultconfig}" ]] && _msg_debug "The settings have been overwritten by the ${defaultconfig}"
1299
1300 # Debug mode
1301 mkalteriso_option="-a ${arch} -v"
1302 if [[ "${bash_debug}" = true ]]; then
1303     set -x -v
1304     mkalteriso_option="${mkalteriso_option} -x"
1305 fi
1306
1307 # Pacman configuration file used only when building
1308 build_pacman_conf=${script_path}/system/pacman-${arch}.conf
1309
1310 # Set rebuild config file
1311 rebuildfile="${work_dir}/build_options"
1312
1313
1314 # Parse channels
1315 set +eu
1316 if [[ -n "${1}" ]]; then
1317     channel_name="${1}"
1318
1319     # Channel list
1320     # check_channel <channel name>
1321     check_channel() {
1322         local channel_list
1323         local i
1324         channel_list=()
1325         for i in $(ls -l "${script_path}"/channels/ | awk '$1 ~ /d/ {print $9 }'); do
1326             if [[ -n $(ls "${script_path}"/channels/${i}) ]] && [[ ! ${i} = "share" ]]; then
1327                 if [[ ! $(echo "${i}" | sed 's/^.*\.\([^\.]*\)$/\1/') = "add" ]]; then
1328                     if [[ ! -d "${script_path}/channels/${i}.add" ]]; then
1329                         channel_list="${channel_list[@]} ${i}"
1330                     fi
1331                 else
1332                     channel_list="${channel_list[@]} ${i}"
1333                 fi
1334             fi
1335         done
1336         for i in ${channel_list[@]}; do
1337             if [[ $(echo "${i}" | sed 's/^.*\.\([^\.]*\)$/\1/') = "add" ]]; then
1338                 if [[ $(echo ${i} | sed 's/\.[^\.]*$//') = ${1} ]]; then
1339                     echo -n "true"
1340                     return 0
1341                 fi
1342             else
1343                 if [[ ${i} = ${1} ]]; then
1344                     echo -n "true"
1345                     return 0
1346                 fi
1347             fi
1348         done
1349         if [[ "${channel_name}" = "rebuild" ]] || [[ "${channel_name}" = "clean" ]]; then
1350             echo -n "true"
1351             return 0
1352         else
1353             echo -n "false"
1354             return 1
1355         fi
1356     }
1357
1358     if [[ $(check_channel "${channel_name}") = false ]]; then
1359         _msg_error "Invalid channel ${channel_name}" "1"
1360     fi
1361
1362     if [[ -d "${script_path}"/channels/${channel_name}.add ]]; then
1363         channel_name="${channel_name}.add"
1364     elif [[ "${channel_name}" = "rebuild" ]]; then
1365         if [[ -f "${rebuildfile}" ]]; then
1366                 rebuild=true
1367         else
1368             _msg_error "The previous build information is not in the working directory." "1"
1369         fi
1370     fi
1371
1372     if [[ ! "${channel_name}" == "rebuild" ]]; then
1373         _msg_debug "channel path is ${script_path}/channels/${channel_name}"
1374     fi
1375 fi
1376
1377 # Check architecture and kernel for each channel
1378 if [[ ! "${channel_name}" = "rebuild" ]] && [[ ! "${channel_name}" = "clean" ]]; then
1379     # architecture
1380     if [[ -z $(cat "${script_path}/channels/${channel_name}/architecture" | grep -h -v ^'#' | grep -x "${arch}") ]]; then
1381         _msg_error "${channel_name} channel does not support current architecture (${arch})." "1"
1382     fi
1383
1384     # kernel
1385     if [[ -f "${script_path}/channels/${channel_name}/kernel_list-${arch}" ]]; then
1386         if [[ -z $(cat "${script_path}/channels/${channel_name}/kernel_list-${arch}" | grep -h -v ^'#' | grep -x "${kernel}") ]]; then
1387             _msg_error "This kernel is currently not supported on this channel." "1"
1388         fi
1389     fi
1390 fi
1391
1392 # Run clean
1393 if [[ "${channel_name}" = "clean" ]]; then
1394     umount_chroot
1395     remove "${script_path}/menuconfig/build"
1396         remove "${script_path}/system/cpp-src/mkalteriso/build"
1397         remove "${script_path}/menuconfig-script/kernel_choice"
1398     remove "${work_dir}"
1399     remove "${rebuildfile}"
1400     remove "${script_path}/temp"
1401     exit 0
1402 fi
1403
1404 # Check the value of a variable that can only be set to true or false.
1405 check_bool() {
1406     local _value="$(eval echo '$'${1})"
1407     _msg_debug -n "Checking ${1}..."
1408     if [[ "${debug}" = true ]]; then
1409         echo -e " ${_value}"
1410     fi
1411     if [[ ! -v "${1}" ]]; then
1412         echo; _msg_error "The variable name ${1} is empty." "1"
1413     elif [[ ! "${_value}" = "true" ]] && [[ ! "${_value}" = "false" ]]; then
1414         echo; _msg_error "The variable name ${1} is not of bool type." "1"
1415     fi
1416 }
1417
1418 if [[ "${debug}" =  true ]]; then
1419     echo
1420 fi
1421 check_bool boot_splash
1422 check_bool debug
1423 check_bool bash_debug
1424 check_bool rebuild
1425 check_bool japanese
1426 check_bool cleaning
1427 check_bool noconfirm
1428 check_bool nodepend
1429 check_bool nocolor
1430 check_bool shmkalteriso
1431 check_bool msgdebug
1432 check_bool customized_username
1433 check_bool noloopmod
1434 check_bool nochname
1435
1436 if [[ "${debug}" =  true ]]; then
1437     echo
1438 fi
1439
1440 set -eu
1441
1442 prepare_build
1443 show_settings
1444 run_once make_pacman_conf
1445 run_once make_basefs
1446 run_once make_packages
1447 run_once make_customize_airootfs
1448 run_once make_setup_mkinitcpio
1449 run_once make_boot
1450 run_once make_boot_extra
1451 run_once make_syslinux
1452 run_once make_isolinux
1453 run_once make_efi
1454 run_once make_efiboot
1455 run_once make_prepare
1456 run_once make_iso
1457
1458 if [[ "${cleaning}" = true ]]; then
1459     remove "${work_dir}"
1460 fi