OSDN Git Service

[FIX] : remove trailing whitespace, require final newline
[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="$( cd -P "$( dirname "$(readlink -f "$0")" )" && pwd )"
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} | sed "/^$/d"); 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 (airootfs)
642 make_basefs() {
643     ${mkalteriso} ${mkalteriso_option} -w "${work_dir}/${arch}" -C "${work_dir}/pacman-${arch}.conf" -D "${install_dir}" init
644
645     # Install plymouth.
646     if [[ "${boot_splash}" = true ]]; then
647         if [[ -n "${theme_pkg}" ]]; then
648             ${mkalteriso} ${mkalteriso_option} -w "${work_dir}/${arch}" -C "${work_dir}/pacman-${arch}.conf" -D "${install_dir}" -p "plymouth ${theme_pkg}" install
649         else
650             ${mkalteriso} ${mkalteriso_option} -w "${work_dir}/${arch}" -C "${work_dir}/pacman-${arch}.conf" -D "${install_dir}" -p "plymouth" install
651         fi
652     fi
653
654     # Install kernel.
655     if [[ ! "${kernel}" = "core" ]]; then
656         ${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
657     else
658         ${mkalteriso} ${mkalteriso_option} -w "${work_dir}/${arch}" -C "${work_dir}/pacman-${arch}.conf" -D "${install_dir}" -p "linux linux-headers broadcom-wl" install
659     fi
660 }
661
662 # Additional packages (airootfs)
663 make_packages() {
664     # インストールするパッケージのリストを読み込み、配列pkglistに代入します。
665     installpkglist() {
666         set +e
667         local _loadfilelist _pkg _file jplist excludefile excludelist _pkglist
668
669         #-- Detect package list to load --#
670         # Append the file in the share directory to the file to be read.
671
672         # Package list for Japanese
673         jplist="${script_path}/channels/share/packages.${arch}/jp.${arch}"
674
675         # Package list for non-Japanese
676         nojplist="${script_path}/channels/share/packages.${arch}/non-jp.${arch}"
677
678         if [[ "${japanese}" = true ]]; then
679             _loadfilelist=($(ls "${script_path}"/channels/share/packages.${arch}/*.${arch} | grep -xv "${nojplist}"))
680         else
681             _loadfilelist=($(ls "${script_path}"/channels/share/packages.${arch}/*.${arch} | grep -xv "${jplist}"))
682         fi
683
684
685         # Add the files for each channel to the list of files to read.
686
687         # Package list for Japanese
688         jplist="${script_path}/channels/${channel_name}/packages.${arch}/jp.${arch}"
689
690         # Package list for non-Japanese
691         nojplist="${script_path}/channels/${channel_name}/packages.${arch}/non-jp.${arch}"
692
693         if [[ "${japanese}" = true ]]; then
694             # If Japanese is enabled, add it to the list of files to read other than non-jp.
695             _loadfilelist=(${_loadfilelist[@]} $(ls "${script_path}"/channels/${channel_name}/packages.${arch}/*.${arch} | grep -xv "${nojplist}"))
696         else
697             # If Japanese is disabled, add it to the list of files to read other than jp.
698             _loadfilelist=(${_loadfilelist[@]} $(ls "${script_path}"/channels/${channel_name}/packages.${arch}/*.${arch} | grep -xv ${jplist}))
699         fi
700
701
702         #-- Read package list --#
703         # Read the file and remove comments starting with # and add it to the list of packages to install.
704         for _file in ${_loadfilelist[@]}; do
705             _msg_debug "Loaded package file ${_file}"
706             pkglist=( ${pkglist[@]} "$(grep -h -v ^'#' ${_file} | sed ':a;N;$!ba;s/\n/ /g')" )
707         done
708         if [[ ${debug} = true ]]; then
709             sleep 3
710         fi
711
712         # Exclude packages from the share exclusion list
713         excludefile="${script_path}/channels/share/packages.${arch}/exclude"
714         if [[ -f "${excludefile}" ]]; then
715             excludelist=( $(grep -h -v ^'#' "${excludefile}" | sed ':a;N;$!ba;s/\n/ /g') )
716
717             # 現在のpkglistをコピーする
718             _pkglist=(${pkglist[@]})
719             unset pkglist
720             for _pkg in ${_pkglist[@]}; do
721                 # もし変数_pkgの値が配列excludelistに含まれていなかったらpkglistに追加する
722                 if [[ ! $(printf '%s\n' "${excludelist[@]}" | grep -qx "${_pkg}"; echo -n ${?} ) = 0 ]]; then
723                     pkglist=(${pkglist[@]} "${_pkg}")
724                 fi
725             done
726         fi
727
728         if [[ -n "${excludelist}" ]]; then
729             _msg_debug "The following packages have been removed from the installation list."
730             _msg_debug "Excluded packages:" "${excludelist[@]}"
731         fi
732
733         # Exclude packages from the exclusion list for each channel
734         excludefile="${script_path}/channels/${channel_name}/packages.${arch}/exclude"
735         if [[ -f "${excludefile}" ]]; then
736             excludelist=( $(grep -h -v ^'#' "${excludefile}" | sed ':a;N;$!ba;s/\n/ /g') )
737
738             # 現在のpkglistをコピーする
739             _pkglist=(${pkglist[@]})
740             unset pkglist
741             for _pkg in ${_pkglist[@]}; do
742                 # もし変数_pkgの値が配列excludelistに含まれていなかったらpkglistに追加する
743                 if [[ ! $(printf '%s\n' "${excludelist[@]}" | grep -qx "${_pkg}"; echo -n ${?} ) = 0 ]]; then
744                     pkglist=(${pkglist[@]} "${_pkg}")
745                 fi
746             done
747         fi
748
749         # Sort the list of packages in abc order.
750         pkglist=(
751             "$(
752                 for _pkg in ${pkglist[@]}; do
753                     echo "${_pkg}"
754                 done \
755                 | sort
756             )"
757         )
758
759         set -e
760     }
761
762     installpkglist
763
764     # _msg_debug "${pkglist[@]}"
765
766     # Create a list of packages to be finally installed as packages.list directly under the working directory.
767     echo "# The list of packages that is installed in live cd." > ${work_dir}/packages.list
768     echo "#" >> ${work_dir}/packages.list
769     echo >> ${work_dir}/packages.list
770     for _pkg in ${pkglist[@]}; do
771         echo ${_pkg} >> ${work_dir}/packages.list
772     done
773
774     # Install packages on airootfs
775     ${mkalteriso} ${mkalteriso_option} -w "${work_dir}/${arch}" -C "${work_dir}/pacman-${arch}.conf" -D "${install_dir}" -p "${pkglist[*]}" install
776 }
777
778 # Customize installation (airootfs)
779 make_customize_airootfs() {
780     # Overwrite airootfs with customize_airootfs.
781     local copy_airootfs
782
783     copy_airootfs() {
784         local i
785         for i in "${@}"; do
786             local _dir="${i%/}"
787             if [[ -d "${_dir}" ]]; then
788                 cp -af --no-preserve=ownership "${_dir}"/* "${work_dir}/${arch}/airootfs"
789             fi
790         done
791     }
792
793     copy_airootfs "${script_path}/channels/share/airootfs.any"
794     copy_airootfs "${script_path}/channels/share/airootfs.${arch}"
795     copy_airootfs "${script_path}/channels/${channel_name}/airootfs.any"
796     copy_airootfs "${script_path}/channels/${channel_name}/airootfs.${arch}"
797
798     # Replace /etc/mkinitcpio.conf if Plymouth is enabled.
799     if [[ "${boot_splash}" = true ]]; then
800         cp "${script_path}/mkinitcpio/mkinitcpio-plymouth.conf" "${work_dir}/${arch}/airootfs/etc/mkinitcpio.conf"
801     fi
802
803
804     # customize_airootfs.sh options
805     # -b            : Enable boot splash.
806     # -d            : Enable debug mode.
807     # -i <inst_dir> : Set install dir
808     # -j            : Enable Japanese.
809     # -k <kernel>   : Set kernel name.
810     # -o <os name>  : Set os name.
811     # -p <password> : Set password.
812     # -s <shell>    : Set user shell.
813     # -t            : Set plymouth theme.
814     # -u <username> : Set live user name.
815     # -x            : Enable bash debug mode.
816     # -r            : Enable rebuild.
817
818
819     # Generate options of customize_airootfs.sh.
820     local addition_options
821     local share_options
822     addition_options=
823     if [[ ${boot_splash} = true ]]; then
824         if [[ -z ${theme_name} ]]; then
825             addition_options="${addition_options} -b"
826         else
827             addition_options="${addition_options} -b -t ${theme_name}"
828         fi
829     fi
830     if [[ ${debug} = true ]]; then
831         addition_options="${addition_options} -d"
832     fi
833     if [[ ${bash_debug} = true ]]; then
834         addition_options="${addition_options} -x"
835     fi
836     if [[ ${japanese} = true ]]; then
837         addition_options="${addition_options} -j"
838     fi
839     if [[ ${rebuild} = true ]]; then
840         addition_options="${addition_options} -r"
841     fi
842
843     share_options="-p '${password}' -k '${kernel}' -u '${username}' -o '${os_name}' -i '${install_dir}' -s '${usershell}' -a '${arch}'"
844
845
846     # X permission
847     if [[ -f ${work_dir}/${arch}/airootfs/root/customize_airootfs.sh ]]; then
848         chmod 755 "${work_dir}/${arch}/airootfs/root/customize_airootfs.sh"
849     fi
850     if [[ -f "${work_dir}/${arch}/airootfs/root/customize_airootfs.sh" ]]; then
851         chmod 755 "${work_dir}/${arch}/airootfs/root/customize_airootfs.sh"
852     fi
853     if [[ -f "${work_dir}/${arch}/airootfs/root/customize_airootfs_${channel_name}.sh" ]]; then
854         chmod 755 "${work_dir}/${arch}/airootfs/root/customize_airootfs_${channel_name}.sh"
855     elif [[ -f "${work_dir}/${arch}/airootfs/root/customize_airootfs_$(echo ${channel_name} | sed 's/\.[^\.]*$//').sh" ]]; then
856         chmod 755 "${work_dir}/${arch}/airootfs/root/customize_airootfs_$(echo ${channel_name} | sed 's/\.[^\.]*$//').sh"
857     fi
858
859     # Execute customize_airootfs.sh.
860     if [[ -z ${addition_options} ]]; then
861         ${mkalteriso} ${mkalteriso_option} \
862             -w "${work_dir}/${arch}" \
863             -C "${work_dir}/pacman-${arch}.conf" \
864             -D "${install_dir}" \
865             -r "/root/customize_airootfs.sh ${share_options}" \
866             run
867         if [[ -f "${work_dir}/${arch}/airootfs/root/customize_airootfs_${channel_name}.sh" ]]; then
868             ${mkalteriso} ${mkalteriso_option} \
869                 -w "${work_dir}/${arch}" \
870                 -C "${work_dir}/pacman-${arch}.conf" \
871                 -D "${install_dir}" \
872                 -r "/root/customize_airootfs_${channel_name}.sh ${share_options}" \
873                 run
874         elif [[ -f "${work_dir}/${arch}/airootfs/root/customize_airootfs_$(echo ${channel_name} | sed 's/\.[^\.]*$//').sh" ]]; then
875             ${mkalteriso} ${mkalteriso_option} \
876                 -w "${work_dir}/${arch}" \
877                 -C "${work_dir}/pacman-${arch}.conf" \
878                 -D "${install_dir}" \
879                 -r "/root/customize_airootfs_$(echo ${channel_name} | sed 's/\.[^\.]*$//').sh ${share_options}" \
880                 run
881         fi
882     else
883         ${mkalteriso} ${mkalteriso_option} \
884             -w "${work_dir}/${arch}" \
885             -C "${work_dir}/pacman-${arch}.conf" \
886             -D "${install_dir}" \
887             -r "/root/customize_airootfs.sh ${share_options} ${addition_options}" \
888             run
889
890         if [[ -f "${work_dir}/${arch}/airootfs/root/customize_airootfs_${channel_name}.sh" ]]; 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_${channel_name}.sh ${share_options} ${addition_options}" \
896                 run
897         elif [[ -f "${work_dir}/${arch}/airootfs/root/customize_airootfs_$(echo ${channel_name} | sed 's/\.[^\.]*$//').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_$(echo ${channel_name} | sed 's/\.[^\.]*$//').sh ${share_options} ${addition_options}" \
903                 run
904         fi
905     fi
906
907
908     # Delete customize_airootfs.sh.
909     remove "${work_dir}/${arch}/airootfs/root/customize_airootfs.sh"
910     remove "${work_dir}/${arch}/airootfs/root/customize_airootfs_${channel_name}.sh"
911
912     # /root permission
913     # https://github.com/archlinux/archiso/commit/d39e2ba41bf556674501062742190c29ee11cd59
914     chmod -f 750 "${work_dir}/x86_64/airootfs/root"
915 }
916
917 # Copy mkinitcpio archiso hooks and build initramfs (airootfs)
918 make_setup_mkinitcpio() {
919     local _hook
920     mkdir -p "${work_dir}/${arch}/airootfs/etc/initcpio/hooks"
921     mkdir -p "${work_dir}/${arch}/airootfs/etc/initcpio/install"
922     for _hook in "archiso" "archiso_shutdown" "archiso_pxe_common" "archiso_pxe_nbd" "archiso_pxe_http" "archiso_pxe_nfs" "archiso_loop_mnt"; do
923         cp "${script_path}/system/initcpio/hooks/${_hook}" "${work_dir}/${arch}/airootfs/etc/initcpio/hooks"
924         cp "${script_path}/system/initcpio/install/${_hook}" "${work_dir}/${arch}/airootfs/etc/initcpio/install"
925     done
926     sed -i "s|/usr/lib/initcpio/|/etc/initcpio/|g" "${work_dir}/${arch}/airootfs/etc/initcpio/install/archiso_shutdown"
927     cp "${script_path}/system/initcpio/install/archiso_kms" "${work_dir}/${arch}/airootfs/etc/initcpio/install"
928     cp "${script_path}/system/initcpio/archiso_shutdown" "${work_dir}/${arch}/airootfs/etc/initcpio"
929     if [[ "${boot_splash}" = true ]]; then
930         cp "${script_path}/mkinitcpio/mkinitcpio-archiso-plymouth.conf" "${work_dir}/${arch}/airootfs/etc/mkinitcpio-archiso.conf"
931     else
932         cp "${script_path}/mkinitcpio/mkinitcpio-archiso.conf" "${work_dir}/${arch}/airootfs/etc/mkinitcpio-archiso.conf"
933     fi
934     gnupg_fd=
935     if [[ "${gpg_key}" ]]; then
936       gpg --export "${gpg_key}" >"${work_dir}/gpgkey"
937       exec 17<>"${work_dir}/gpgkey"
938     fi
939
940     if [[ ! ${kernel} = "core" ]]; then
941         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
942     else
943         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
944     fi
945
946     if [[ "${gpg_key}" ]]; then
947       exec 17<&-
948     fi
949 }
950
951 # Prepare kernel/initramfs ${install_dir}/boot/
952 make_boot() {
953     mkdir -p "${work_dir}/iso/${install_dir}/boot/${arch}"
954     cp "${work_dir}/${arch}/airootfs/boot/archiso.img" "${work_dir}/iso/${install_dir}/boot/${arch}/archiso.img"
955
956     if [[ ! "${kernel}" = "core" ]]; then
957         cp "${work_dir}/${arch}/airootfs/boot/vmlinuz-linux-${kernel}" "${work_dir}/iso/${install_dir}/boot/${arch}/vmlinuz-linux-${kernel}"
958     else
959         cp "${work_dir}/${arch}/airootfs/boot/vmlinuz-linux" "${work_dir}/iso/${install_dir}/boot/${arch}/vmlinuz-linux"
960     fi
961 }
962
963 # Add other aditional/extra files to ${install_dir}/boot/
964 make_boot_extra() {
965     if [[ -e "${work_dir}/${arch}/airootfs/boot/memtest86+/memtest.bin" ]]; then
966         cp "${work_dir}/${arch}/airootfs/boot/memtest86+/memtest.bin" "${work_dir}/iso/${install_dir}/boot/memtest"
967         cp "${work_dir}/${arch}/airootfs/usr/share/licenses/common/GPL2/license.txt" "${work_dir}/iso/${install_dir}/boot/memtest.COPYING"
968     fi
969     if [[ -e "${work_dir}/${arch}/airootfs/boot/intel-ucode.img" ]]; then
970         cp "${work_dir}/${arch}/airootfs/boot/intel-ucode.img" "${work_dir}/iso/${install_dir}/boot/intel_ucode.img"
971         cp "${work_dir}/${arch}/airootfs/usr/share/licenses/intel-ucode/LICENSE" "${work_dir}/iso/${install_dir}/boot/intel_ucode.LICENSE"
972     fi
973     if [[ -e "${work_dir}/${arch}/airootfs/boot/amd-ucode.img" ]]; then
974         cp "${work_dir}/${arch}/airootfs/boot/amd-ucode.img" "${work_dir}/iso/${install_dir}/boot/amd_ucode.img"
975         cp "${work_dir}/${arch}/airootfs/usr/share/licenses/amd-ucode/LICENSE.amd-ucode" "${work_dir}/iso/${install_dir}/boot/amd_ucode.LICENSE"
976     fi
977 }
978
979 # Prepare /${install_dir}/boot/syslinux
980 make_syslinux() {
981     if [[ ! ${kernel} = "core" ]]; then
982         _uname_r="$(file -b ${work_dir}/${arch}/airootfs/boot/vmlinuz-linux-${kernel} | awk 'f{print;f=0} /version/{f=1}' RS=' ')"
983     else
984         _uname_r="$(file -b ${work_dir}/${arch}/airootfs/boot/vmlinuz-linux | awk 'f{print;f=0} /version/{f=1}' RS=' ')"
985     fi
986     mkdir -p "${work_dir}/iso/${install_dir}/boot/syslinux"
987
988     for _cfg in ${script_path}/syslinux/${arch}/*.cfg; do
989         sed "s|%ARCHISO_LABEL%|${iso_label}|g;
990              s|%OS_NAME%|${os_name}|g;
991              s|%INSTALL_DIR%|${install_dir}|g" "${_cfg}" > "${work_dir}/iso/${install_dir}/boot/syslinux/${_cfg##*/}"
992     done
993
994     if [[ ${boot_splash} = true ]]; then
995         sed "s|%ARCHISO_LABEL%|${iso_label}|g;
996              s|%OS_NAME%|${os_name}|g;
997              s|%INSTALL_DIR%|${install_dir}|g" \
998              "${script_path}/syslinux/${arch}/pxe-plymouth/archiso_pxe-${kernel}.cfg" > "${work_dir}/iso/${install_dir}/boot/syslinux/archiso_pxe.cfg"
999
1000         sed "s|%ARCHISO_LABEL%|${iso_label}|g;
1001              s|%OS_NAME%|${os_name}|g;
1002              s|%INSTALL_DIR%|${install_dir}|g" \
1003              "${script_path}/syslinux/${arch}/sys-plymouth/archiso_sys-${kernel}.cfg" > "${work_dir}/iso/${install_dir}/boot/syslinux/archiso_sys.cfg"
1004     else
1005         sed "s|%ARCHISO_LABEL%|${iso_label}|g;
1006              s|%OS_NAME%|${os_name}|g;
1007              s|%INSTALL_DIR%|${install_dir}|g" \
1008              "${script_path}/syslinux/${arch}/pxe/archiso_pxe-${kernel}.cfg" > "${work_dir}/iso/${install_dir}/boot/syslinux/archiso_pxe.cfg"
1009
1010         sed "s|%ARCHISO_LABEL%|${iso_label}|g;
1011              s|%OS_NAME%|${os_name}|g;
1012              s|%INSTALL_DIR%|${install_dir}|g" \
1013              "${script_path}/syslinux/${arch}/sys/archiso_sys-${kernel}.cfg" > "${work_dir}/iso/${install_dir}/boot/syslinux/archiso_sys.cfg"
1014     fi
1015
1016     if [[ -f "${script_path}/channels/${channel_name}/splash.png" ]]; then
1017         cp "${script_path}/channels/${channel_name}/splash.png" "${work_dir}/iso/${install_dir}/boot/syslinux"
1018     else
1019         cp "${script_path}/syslinux/${arch}/splash.png" "${work_dir}/iso/${install_dir}/boot/syslinux"
1020     fi
1021     cp "${work_dir}"/${arch}/airootfs/usr/lib/syslinux/bios/*.c32 "${work_dir}/iso/${install_dir}/boot/syslinux"
1022     cp "${work_dir}/${arch}/airootfs/usr/lib/syslinux/bios/lpxelinux.0" "${work_dir}/iso/${install_dir}/boot/syslinux"
1023     cp "${work_dir}/${arch}/airootfs/usr/lib/syslinux/bios/memdisk" "${work_dir}/iso/${install_dir}/boot/syslinux"
1024     mkdir -p "${work_dir}/iso/${install_dir}/boot/syslinux/hdt"
1025     gzip -c -9 "${work_dir}/${arch}/airootfs/usr/share/hwdata/pci.ids" > "${work_dir}/iso/${install_dir}/boot/syslinux/hdt/pciids.gz"
1026     gzip -c -9 "${work_dir}/${arch}/airootfs/usr/lib/modules/${_uname_r}/modules.alias" > "${work_dir}/iso/${install_dir}/boot/syslinux/hdt/modalias.gz"
1027 }
1028
1029 # Prepare /isolinux
1030 make_isolinux() {
1031     mkdir -p "${work_dir}/iso/isolinux"
1032
1033     sed "s|%INSTALL_DIR%|${install_dir}|g" \
1034         "${script_path}/system/isolinux.cfg" > "${work_dir}/iso/isolinux/isolinux.cfg"
1035     cp "${work_dir}/${arch}/airootfs/usr/lib/syslinux/bios/isolinux.bin" "${work_dir}/iso/isolinux/"
1036     cp "${work_dir}/${arch}/airootfs/usr/lib/syslinux/bios/isohdpfx.bin" "${work_dir}/iso/isolinux/"
1037     cp "${work_dir}/${arch}/airootfs/usr/lib/syslinux/bios/ldlinux.c32" "${work_dir}/iso/isolinux/"
1038 }
1039
1040 # Prepare /EFI
1041 make_efi() {
1042     mkdir -p "${work_dir}/iso/EFI/boot"
1043     cp "${work_dir}/${arch}/airootfs/usr/lib/systemd/boot/efi/systemd-bootx64.efi" "${work_dir}/iso/EFI/boot/bootx64.efi"
1044
1045     mkdir -p "${work_dir}/iso/loader/entries"
1046     cp "${script_path}/efiboot/loader/loader.conf" "${work_dir}/iso/loader/"
1047
1048     sed "s|%ARCHISO_LABEL%|${iso_label}|g;
1049          s|%OS_NAME%|${os_name}|g;
1050          s|%INSTALL_DIR%|${install_dir}|g" \
1051         "${script_path}/efiboot/loader/entries/usb/archiso-x86_64-usb-${kernel}.conf" > "${work_dir}/iso/loader/entries/archiso-x86_64.conf"
1052
1053     # edk2-shell based UEFI shell
1054     # shellx64.efi is picked up automatically when on /
1055     cp "${work_dir}/x86_64/airootfs/usr/share/edk2-shell/x64/Shell_Full.efi" "${work_dir}/iso/shellx64.efi"
1056 }
1057
1058 # Prepare efiboot.img::/EFI for "El Torito" EFI boot mode
1059 make_efiboot() {
1060     mkdir -p "${work_dir}/iso/EFI/archiso"
1061     truncate -s 64M "${work_dir}/iso/EFI/archiso/efiboot.img"
1062     mkfs.fat -n ARCHISO_EFI "${work_dir}/iso/EFI/archiso/efiboot.img"
1063
1064     mkdir -p "${work_dir}/efiboot"
1065     mount "${work_dir}/iso/EFI/archiso/efiboot.img" "${work_dir}/efiboot"
1066
1067     mkdir -p "${work_dir}/efiboot/EFI/archiso"
1068
1069     if [[ ! ${kernel} = "core" ]]; then
1070         cp "${work_dir}/iso/${install_dir}/boot/${arch}/vmlinuz-linux-${kernel}" "${work_dir}/efiboot/EFI/archiso/vmlinuz-linux-${kernel}.efi"
1071     else
1072         cp "${work_dir}/iso/${install_dir}/boot/${arch}/vmlinuz" "${work_dir}/efiboot/EFI/archiso/vmlinuz.efi"
1073     fi
1074
1075     cp "${work_dir}/iso/${install_dir}/boot/${arch}/archiso.img" "${work_dir}/efiboot/EFI/archiso/archiso.img"
1076
1077     cp "${work_dir}/iso/${install_dir}/boot/intel_ucode.img" "${work_dir}/efiboot/EFI/archiso/intel_ucode.img"
1078     cp "${work_dir}/iso/${install_dir}/boot/amd_ucode.img" "${work_dir}/efiboot/EFI/archiso/amd_ucode.img"
1079
1080     mkdir -p "${work_dir}/efiboot/EFI/boot"
1081     cp "${work_dir}/${arch}/airootfs/usr/lib/systemd/boot/efi/systemd-bootx64.efi" "${work_dir}/efiboot/EFI/boot/bootx64.efi"
1082
1083     mkdir -p "${work_dir}/efiboot/loader/entries"
1084     cp "${script_path}/efiboot/loader/loader.conf" "${work_dir}/efiboot/loader/"
1085
1086
1087     sed "s|%ARCHISO_LABEL%|${iso_label}|g;
1088          s|%OS_NAME%|${os_name}|g;
1089          s|%INSTALL_DIR%|${install_dir}|g" \
1090         "${script_path}/efiboot/loader/entries/cd/archiso-x86_64-cd-${kernel}.conf" > "${work_dir}/efiboot/loader/entries/archiso-x86_64.conf"
1091
1092     # shellx64.efi is picked up automatically when on /
1093     cp "${work_dir}/iso/shellx64.efi" "${work_dir}/efiboot/"
1094
1095     umount -d "${work_dir}/efiboot"
1096 }
1097
1098 # Build airootfs filesystem image
1099 make_prepare() {
1100     cp -a -l -f "${work_dir}/${arch}/airootfs" "${work_dir}"
1101     ${mkalteriso} ${mkalteriso_option} -w "${work_dir}" -D "${install_dir}" pkglist
1102     pacman -Q --sysroot "${work_dir}/airootfs" > "${work_dir}/packages-full.list"
1103     ${mkalteriso} ${mkalteriso_option} -w "${work_dir}" -D "${install_dir}" ${gpg_key:+-g ${gpg_key}} -c "${sfs_comp}" -t "${sfs_comp_opt}" prepare
1104     remove "${work_dir}/airootfs"
1105
1106     if [[ "${cleaning}" = true ]]; then
1107         remove "${work_dir}/${arch}/airootfs"
1108     fi
1109 }
1110
1111 # Build ISO
1112 make_iso() {
1113     ${mkalteriso} ${mkalteriso_option} -w "${work_dir}" -D "${install_dir}" -L "${iso_label}" -P "${iso_publisher}" -A "${iso_application}" -o "${out_dir}" iso "${iso_filename}"
1114     _msg_info "The password for the live user and root is ${password}."
1115 }
1116
1117
1118 # Parse options
1119 options="${@}"
1120 _opt_short="a:bc:dg:hjk:lo:p:t:u:w:x"
1121 _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"
1122 OPT=$(getopt -o ${_opt_short} -l ${_opt_long} -- "${@}")
1123 if [[ ${?} != 0 ]]; then
1124     exit 1
1125 fi
1126
1127 eval set -- "${OPT}"
1128 unset OPT _opt_short _opt_long
1129
1130 while :; do
1131     case ${1} in
1132         -a | --arch)
1133             arch="${2}"
1134             shift 2
1135             ;;
1136         -b | --boot-splash)
1137             boot_splash=true
1138             shift 1
1139             ;;
1140         -c | --comp-type)
1141             case "${2}" in
1142                 "gzip" | "lzma" | "lzo" | "lz4" | "xz" | "zstd") sfs_comp="${2}" ;;
1143                 *) _msg_error "Invaild compressors '${2}'" '1' ;;
1144             esac
1145             shift 2
1146             ;;
1147         -d | --debug)
1148             debug=true
1149             shift 1
1150             ;;
1151         -g | --gpgkey)
1152             gpg_key="$2"
1153             shift 2
1154             ;;
1155         -h | --help)
1156             _usage
1157             exit 0
1158             ;;
1159         -j | --japanese)
1160             japanese=true
1161             shift 1
1162             ;;
1163         -k | --kernel)
1164             if [[ -n $(cat ${script_path}/system/kernel_list-${arch} | grep -h -v ^'#' | sed "/^$/d" | grep -x "${2}") ]]; then
1165                 kernel="${2}"
1166             else
1167                 _msg_error "Invalid kernel ${2}" "1"
1168             fi
1169             shift 2
1170             ;;
1171         -l | --cleaning)
1172             cleaning=true
1173             shift 1
1174             ;;
1175         -o | --out)
1176             out_dir="${2}"
1177             shift 2
1178             ;;
1179         -p | --password)
1180             password="${2}"
1181             shift 2
1182             ;;
1183         -t | --comp-opts)
1184             sfs_comp_opt="${2}"
1185             shift 2
1186             ;;
1187         -u | --user)
1188             customized_username=true
1189             username="$(echo -n "${2}" | sed 's/ //g' |tr '[A-Z]' '[a-z]')"
1190             shift 2
1191             ;;
1192         -w | --work)
1193             work_dir="${2}"
1194             shift 2
1195             ;;
1196         -x | --bash-debug)
1197             debug=true
1198             bash_debug=true
1199             shift 1
1200             ;;
1201         --noconfirm)
1202             noconfirm=true
1203             shift 1
1204             ;;
1205         --nodepend)
1206             nodepend=true
1207             shift 1
1208             ;;
1209         --nocolor)
1210             nocolor=true
1211             shift 1
1212             ;;
1213         --gitversion)
1214             if [[ -d "${script_path}/.git" ]]; then
1215                 gitversion=true
1216             else
1217                 _msg_error "There is no git directory. You need to use git clone to use this feature." "1"
1218             fi
1219             shift 1
1220             ;;
1221         --shmkalteriso)
1222             shmkalteriso=true
1223             shift 1
1224             ;;
1225         --msgdebug)
1226             msgdebug=true;
1227             shift 1
1228             ;;
1229         --noloopmod)
1230             noloopmod=true
1231             shift 1
1232             ;;
1233         --channellist)
1234             show_channel_list
1235             shift 1
1236             ;;
1237         --)
1238             shift
1239             break
1240             ;;
1241         *)
1242             _msg_error "Invalid argument '${1}'"
1243             _usage 1
1244             ;;
1245     esac
1246 done
1247
1248
1249 # Check root.
1250 if [[ ${EUID} -ne 0 ]]; then
1251     _msg_warn "This script must be run as root." >&2
1252     # echo "Use -h to display script details." >&2
1253     # _usage 1
1254     _msg_warn "Re-run 'sudo ${0} ${options}'"
1255     sudo ${0} ${options}
1256     exit 1
1257 fi
1258
1259 # Show alteriso version
1260 if [[ -d "${script_path}/.git" ]]; then
1261     cd  "${script_path}"
1262     _msg_debug "The version of alteriso is $(git describe --long --tags | sed 's/\([^-]*-g\)/r\1/;s/-/./g')."
1263     cd - > /dev/null 2>&1
1264 fi
1265
1266 # Show config message
1267 [[ -f "${defaultconfig}" ]] && _msg_debug "Use the default configuration file (${defaultconfig})."
1268
1269 # Debug mode
1270 mkalteriso_option="-a ${arch} -v"
1271 if [[ "${bash_debug}" = true ]]; then
1272     set -x -v
1273     mkalteriso_option="${mkalteriso_option} -x"
1274 fi
1275
1276 # Pacman configuration file used only when building
1277 build_pacman_conf="${script_path}/system/pacman-${arch}.conf"
1278
1279 # Set rebuild config file
1280 rebuildfile="${work_dir}/build_options"
1281
1282
1283 # Parse channels
1284 set +eu
1285 if [[ -n "${1}" ]]; then
1286     channel_name="${1}"
1287
1288     # Channel list
1289     # check_channel <channel name>
1290     check_channel() {
1291         local channel_list
1292         local i
1293         channel_list=()
1294         for i in $(ls -l "${script_path}"/channels/ | awk '$1 ~ /d/ {print $9 }'); do
1295             if [[ -n $(ls "${script_path}"/channels/${i}) ]] && [[ ! ${i} = "share" ]]; then
1296                 if [[ ! $(echo "${i}" | sed 's/^.*\.\([^\.]*\)$/\1/') = "add" ]]; then
1297                     if [[ ! -d "${script_path}/channels/${i}.add" ]]; then
1298                         channel_list="${channel_list[@]} ${i}"
1299                     fi
1300                 else
1301                     channel_list="${channel_list[@]} ${i}"
1302                 fi
1303             fi
1304         done
1305         for i in ${channel_list[@]}; do
1306             if [[ $(echo "${i}" | sed 's/^.*\.\([^\.]*\)$/\1/') = "add" ]]; then
1307                 if [[ $(echo ${i} | sed 's/\.[^\.]*$//') = ${1} ]]; then
1308                     echo -n "true"
1309                     return 0
1310                 fi
1311             else
1312                 if [[ ${i} = ${1} ]]; then
1313                     echo -n "true"
1314                     return 0
1315                 fi
1316             fi
1317         done
1318         if [[ "${channel_name}" = "rebuild" ]] || [[ "${channel_name}" = "clean" ]]; then
1319             echo -n "true"
1320             return 0
1321         else
1322             echo -n "false"
1323             return 1
1324         fi
1325     }
1326
1327     if [[ $(check_channel "${channel_name}") = false ]]; then
1328         _msg_error "Invalid channel ${channel_name}" "1"
1329     fi
1330
1331     if [[ -d "${script_path}"/channels/${channel_name}.add ]]; then
1332         channel_name="${channel_name}.add"
1333     elif [[ "${channel_name}" = "rebuild" ]]; then
1334         if [[ -f "${rebuildfile}" ]]; then
1335                 rebuild=true
1336         else
1337             _msg_error "The previous build information is not in the working directory." "1"
1338         fi
1339     fi
1340
1341     if [[ ! "${channel_name}" == "rebuild" ]] && [[ ! "${channel_name}" == "clean" ]]; then
1342         _msg_debug "channel path is ${script_path}/channels/${channel_name}"
1343     fi
1344 fi
1345
1346 # Check architecture and kernel for each channel
1347 if [[ ! "${channel_name}" = "rebuild" ]] && [[ ! "${channel_name}" = "clean" ]]; then
1348     # architecture
1349     if [[ -z $(cat "${script_path}/channels/${channel_name}/architecture" | grep -h -v ^'#' | sed "/^$/d" | grep -x "${arch}") ]]; then
1350         _msg_error "${channel_name} channel does not support current architecture (${arch})." "1"
1351     fi
1352
1353     # kernel
1354     if [[ -f "${script_path}/channels/${channel_name}/kernel_list-${arch}" ]]; then
1355         if [[ -z $(cat "${script_path}/channels/${channel_name}/kernel_list-${arch}" | grep -h -v ^'#' | sed "/^$/d" | grep -x "${kernel}") ]]; then
1356             _msg_error "This kernel is currently not supported on this channel." "1"
1357         fi
1358     fi
1359 fi
1360
1361 # Run clean
1362 if [[ "${channel_name}" = "clean" ]]; then
1363     umount_chroot
1364     remove "${script_path}/menuconfig/build"
1365         remove "${script_path}/system/cpp-src/mkalteriso/build"
1366         remove "${script_path}/menuconfig-script/kernel_choice"
1367     remove "${work_dir%/}"/*
1368     remove "${work_dir}"
1369     remove "${rebuildfile}"
1370     remove "${script_path}/temp"
1371     exit 0
1372 fi
1373
1374 # Check the value of a variable that can only be set to true or false.
1375 check_bool() {
1376     local _value="$(eval echo '$'${1})"
1377     _msg_debug -n "Checking ${1}..."
1378     if [[ "${debug}" = true ]]; then
1379         echo -e " ${_value}"
1380     fi
1381     if [[ ! -v "${1}" ]]; then
1382         echo; _msg_error "The variable name ${1} is empty." "1"
1383     elif [[ ! "${_value}" = "true" ]] && [[ ! "${_value}" = "false" ]]; then
1384         echo; _msg_error "The variable name ${1} is not of bool type." "1"
1385     fi
1386 }
1387
1388 if [[ "${debug}" =  true ]]; then
1389     echo
1390 fi
1391 check_bool boot_splash
1392 check_bool debug
1393 check_bool bash_debug
1394 check_bool rebuild
1395 check_bool japanese
1396 check_bool cleaning
1397 check_bool noconfirm
1398 check_bool nodepend
1399 check_bool nocolor
1400 check_bool shmkalteriso
1401 check_bool msgdebug
1402 check_bool customized_username
1403 check_bool noloopmod
1404 check_bool nochname
1405
1406 if [[ "${debug}" =  true ]]; then
1407     echo
1408 fi
1409
1410 set -eu
1411
1412 prepare_build
1413 show_settings
1414 run_once make_pacman_conf
1415 run_once make_basefs
1416 run_once make_packages
1417 run_once make_customize_airootfs
1418 run_once make_setup_mkinitcpio
1419 run_once make_boot
1420 run_once make_boot_extra
1421 run_once make_syslinux
1422 run_once make_isolinux
1423 run_once make_efi
1424 run_once make_efiboot
1425 run_once make_prepare
1426 run_once make_iso
1427
1428 if [[ "${cleaning}" = true ]]; then
1429     remove "${work_dir}"
1430 fi