OSDN Git Service

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