OSDN Git Service

Merge branch 'dev' into dev-stable
[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-2021 Fascode Network.
8 #
9 # build.sh
10 #
11 # The main script that runs the build
12 #
13
14 set -Eeu
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 tools_dir="${script_path}/tools" module_dir="${script_path}/modules"
21 customized_username=false customized_password=false customized_kernel=false customized_logpath=false
22 pkglist_args=() makepkg_script_args=() modules=() norepopkg=()
23 legacy_mode=false rerun=false
24 DEFAULT_ARGUMENT="" ARGUMENT=("${@}")
25 alteriso_version="3.1"
26
27 # Load config file
28 [[ ! -f "${defaultconfig}" ]] && "${tools_dir}/msg.sh" -a 'build.sh' error "${defaultconfig} was not found." && exit 1
29 for config in "${defaultconfig}" "${script_path}/custom.conf"; do
30     [[ -f "${config}" ]] && source "${config}" && loaded_files+=("${config}")
31 done
32
33 umask 0022
34
35 # Message common function
36 # msg_common [type] [-n] [string]
37 msg_common(){
38     local _msg_opts=("-a" "build.sh") _type="${1}" && shift 1
39     [[ "${1}" = "-n" ]] && _msg_opts+=("-o" "-n") && shift 1
40     [[ "${msgdebug}" = true ]] && _msg_opts+=("-x")
41     [[ "${nocolor}"  = true ]] && _msg_opts+=("-n")
42     _msg_opts+=("${_type}" "${@}")
43     "${tools_dir}/msg.sh" "${_msg_opts[@]}"
44 }
45
46 # Show an INFO message
47 # ${1}: message string
48 msg_info() { msg_common info "${@}"; }
49
50 # Show an Warning message
51 # ${1}: message string
52 msg_warn() { msg_common warn "${@}"; }
53
54 # Show an debug message
55 # ${1}: message string
56 msg_debug() { 
57     [[ "${debug}" = true ]] && msg_common debug "${@}" || return 0
58 }
59
60 # Show an ERROR message then exit with status
61 # ${1}: message string
62 # ${2}: exit code number (with 0 does not exit)
63 msg_error() {
64     msg_common error "${1}"
65     [[ -n "${2:-""}" ]] && exit "${2}" || return 0
66 }
67
68
69 # Usage: getclm <number>
70 # 標準入力から値を受けとり、引数で指定された列を抽出します。
71 getclm() { cut -d " " -f "${1}"; }
72
73 # Usage: echo_blank <number>
74 # 指定されたぶんの半角空白文字を出力します
75 echo_blank(){ yes " " 2> /dev/null  | head -n "${1}" | tr -d "\n"; }
76
77 # cpコマンドのラッパー
78 _cp(){ cp -af --no-preserve=ownership,mode -- "${@}"; }
79
80 _usage () {
81     cat "${script_path}/docs/build.sh/help.1"
82     local blank="29" _arch _dirname _type _output _first
83     for _type in "locale" "kernel"; do
84         echo " ${_type} for each architecture:"
85         for _arch in $(find "${script_path}/system/" -maxdepth 1 -mindepth 1 -name "${_type}-*" -print0 | xargs -I{} -0 basename {} | sed "s|${_type}-||g"); do
86             echo "    ${_arch}$(echo_blank "$(( "${blank}" - "${#_arch}" ))")$("${tools_dir}/${_type}.sh" -a "${_arch}" show)"
87         done
88         echo
89     done
90
91     echo " Channel:"
92     for _dirname in $(bash "${tools_dir}/channel.sh" --version "${alteriso_version}" -d -b -n --line show | sed "s|.add$||g"); do
93         readarray -t _output < <("${tools_dir}/channel.sh" --version "${alteriso_version}" --nocheck desc "${_dirname}")
94         _first=true
95         echo -n "    ${_dirname}"
96         for _out in "${_output[@]}"; do
97             "${_first}" && echo -e "    $(echo_blank "$(( "${blank}" - 4 - "${#_dirname}" ))")${_out}" || echo -e "    $(echo_blank "$(( "${blank}" + 5 - "${#_dirname}" ))")${_out}"
98             _first=false
99         done
100     done
101     cat "${script_path}/docs/build.sh/help.2"
102     [[ -n "${1:-}" ]] && exit "${1}"
103 }
104
105 # Unmount helper Usage: _umount <target>
106 _umount() { mountpoint -q "${1}" && umount -lf "${1}"; return 0; }
107
108 # Mount helper Usage: _mount <source> <target>
109 _mount() { ! mountpoint -q "${2}" && [[ -f "${1}" ]] && [[ -d "${2}" ]] && mount "${1}" "${2}"; return 0; }
110
111 # Unmount work dir
112 umount_work () {
113     local _args=("${build_dir}")
114     [[ "${debug}" = true ]] && _args=("-d" "${_args[@]}")
115     [[ "${nocolor}" = true ]] && _args+=("--nocolor")
116     "${tools_dir}/umount.sh" "${_args[@]}"
117 }
118
119 # Mount airootfs on "${airootfs_dir}"
120 mount_airootfs () {
121     mkdir -p "${airootfs_dir}"
122     _mount "${airootfs_dir}.img" "${airootfs_dir}"
123 }
124
125
126 # Helper function to run make_*() only one time.
127 run_once() {
128     if [[ ! -e "${lockfile_dir}/build.${1}" ]]; then
129         umount_work
130         msg_debug "Running ${1} ..."
131         mount_airootfs
132         eval "${@}"
133         mkdir -p "${lockfile_dir}"; touch "${lockfile_dir}/build.${1}"
134         
135     else
136         msg_debug "Skipped because ${1} has already been executed."
137     fi
138 }
139
140 # Show message when file is removed
141 # remove <file> <file> ...
142 remove() {
143     local _file
144     for _file in "${@}"; do msg_debug "Removing ${_file}"; rm -rf "${_file}"; done
145 }
146
147 # 強制終了時にアンマウント
148 umount_trap() {
149     local _status="${?}"
150     umount_work
151     msg_error "It was killed by the user.\nThe process may not have completed successfully."
152     exit "${_status}"
153 }
154
155 # 設定ファイルを読み込む
156 # load_config [file1] [file2] ...
157 load_config() {
158     local _file
159     for _file in "${@}"; do [[ -f "${_file}" ]] && source "${_file}" && msg_debug "The settings have been overwritten by the ${_file}"; done
160     return 0
161 }
162
163 # Display channel list
164 show_channel_list() {
165     local _args=("-v" "${alteriso_version}" show)
166     [[ "${nochkver}" = true ]] && _args+=("-n")
167     bash "${tools_dir}/channel.sh" "${_args[@]}"
168 }
169
170 # Execute command for each module. It will be executed with {} replaced with the module name.
171 # for_module <command>
172 for_module(){ local module && for module in "${modules[@]}"; do eval "${@//"{}"/${module}}"; done; }
173
174 # pacstrapを実行
175 _pacstrap(){
176     msg_info "Installing packages to ${airootfs_dir}/'..."
177     local _args=("-c" "-G" "-M" "--" "${airootfs_dir}" "${@}")
178     [[ "${pacman_debug}" = true ]] && _args+=(--debug)
179     pacstrap -C "${build_dir}/pacman.conf" "${_args[@]}"
180     msg_info "Packages installed successfully!"
181 }
182
183 # chroot環境でpacmanコマンドを実行
184 # /etc/alteriso-pacman.confを準備してコマンドを実行します
185 _run_with_pacmanconf(){
186     sed "s|^CacheDir     =|#CacheDir    =|g" "${build_dir}/pacman.conf" > "${airootfs_dir}/etc/alteriso-pacman.conf"
187     eval -- "${@}"
188     remove "${airootfs_dir}/etc/alteriso-pacman.conf"
189 }
190
191 # コマンドをchrootで実行する
192 _chroot_run() {
193     msg_debug "Run command in chroot\nCommand: ${*}"
194     arch-chroot "${airootfs_dir}" "${@}" || return "${?}"
195 }
196
197 _cleanup_common () {
198     msg_info "Cleaning up what we can on airootfs..."
199
200     # Delete pacman database sync cache files (*.tar.gz)
201     [[ -d "${airootfs_dir}/var/lib/pacman" ]] && find "${airootfs_dir}/var/lib/pacman" -maxdepth 1 -type f -delete
202
203     # Delete pacman database sync cache
204     [[ -d "${airootfs_dir}/var/lib/pacman/sync" ]] && find "${airootfs_dir}/var/lib/pacman/sync" -delete
205
206     # Delete pacman package cache
207     [[ -d "${airootfs_dir}/var/cache/pacman/pkg" ]] && find "${airootfs_dir}/var/cache/pacman/pkg" -type f -delete
208
209     # Delete all log files, keeps empty dirs.
210     [[ -d "${airootfs_dir}/var/log" ]] && find "${airootfs_dir}/var/log" -type f -delete
211
212     # Delete all temporary files and dirs
213     [[ -d "${airootfs_dir}/var/tmp" ]] && find "${airootfs_dir}/var/tmp" -mindepth 1 -delete
214
215     # Delete package pacman related files.
216     find "${build_dir}" \( -name '*.pacnew' -o -name '*.pacsave' -o -name '*.pacorig' \) -delete
217
218     # Delete all cache file
219     [[ -d "${airootfs_dir}/var/cache" ]] && find "${airootfs_dir}/var/cache" -mindepth 1 -delete
220
221     # Create an empty /etc/machine-id
222     printf '' > "${airootfs_dir}/etc/machine-id"
223
224     msg_info "Done!"
225 }
226
227 _cleanup_airootfs(){
228     _cleanup_common
229     # Delete all files in /boot
230     [[ -d "${airootfs_dir}/boot" ]] && find "${airootfs_dir}/boot" -mindepth 1 -delete
231 }
232
233 _mkchecksum() {
234     msg_info "Creating md5 checksum ..."
235     echo "$(md5sum "${1}" | getclm 1) $(basename "${1}")" > "${1}.md5"
236     msg_info "Creating sha256 checksum ..."
237     echo "$(sha256sum "${1}" | getclm 1) $(basename "${1}")" > "${1}.sha256"
238 }
239
240 # Check the value of a variable that can only be set to true or false.
241 check_bool() {
242     local _value _variable
243     for _variable in "${@}"; do
244         msg_debug -n "Checking ${_variable}..."
245         eval ": \${${_variable}:=''}"
246         _value="$(eval echo "\${${_variable},,}")"
247         eval "${_variable}=${_value}"
248         if [[ ! -v "${1}" ]] || [[ "${_value}"  = "" ]]; then
249             [[ "${debug}" = true ]] && echo ; msg_error "The variable name ${_variable} is empty." "1"
250         elif [[ ! "${_value}" = "true" ]] && [[ ! "${_value}" = "false" ]]; then
251             [[ "${debug}" = true ]] && echo ; msg_error "The variable name ${_variable} is not of bool type (${_variable} = ${_value})" "1"
252         elif [[ "${debug}" = true ]]; then
253             echo -e " ${_value}"
254         fi
255     done
256 }
257
258 _run_cleansh(){
259     bash "$([[ "${bash_debug}" = true ]] && echo -n "-x" || echo -n "+x")" "${tools_dir}/clean.sh" -o -w "$(realpath "${build_dir}")" "$([[ "${debug}" = true ]] && printf "%s" "-d")" "$([[ "${noconfirm}" = true ]] && printf "%s" "-n")" "$([[ "${nocolor}" = true ]] && printf "%s" "--nocolor")"
260 }
261
262
263 # Check the build environment and create a directory.
264 prepare_env() {
265     # Check packages
266     if [[ "${nodepend}" = false ]]; then
267         local _check_failed=false _pkg _result=0
268         msg_info "Checking dependencies ..."
269         ! pacman -Qq pyalpm > /dev/null 2>&1 && msg_error "pyalpm is not installed." 1
270         for _pkg in "${dependence[@]}"; do
271             eval "${tools_dir}/package.py" "${_pkg}" "$( [[ "${debug}" = false ]] && echo "> /dev/null")" || _result="${?}"
272             if (( _result == 3 )) || (( _result == 4 )); then
273                 _check_failed=true
274             fi
275             _result=0
276         done
277         [[ "${_check_failed}" = true ]] && exit 1
278     fi
279
280     # Load loop kernel module
281     if [[ "${noloopmod}" = false ]]; then
282         [[ ! -d "/usr/lib/modules/$(uname -r)" ]] && msg_error "The currently running kernel module could not be found.\nProbably the system kernel has been updated.\nReboot your system to run the latest kernel." "1"
283         lsmod | getclm 1 | grep -qx "loop" || modprobe loop
284     fi
285
286     # Check work dir
287     if [[ "${normwork}" = false ]]; then
288         msg_info "Deleting the contents of ${build_dir}..."
289         _run_cleansh
290     fi
291
292     # Set gpg key
293     if [[ -n "${gpg_key}" ]]; then
294         gpg --batch --output "${work_dir}/pubkey.gpg" --export "${gpg_key}"
295         exec {ARCHISO_GNUPG_FD}<>"${build_dir}/pubkey.gpg"
296         export ARCHISO_GNUPG_FD
297     fi
298
299     # 強制終了時に作業ディレクトリを削除する
300     local _trap_remove_work
301     _trap_remove_work() {
302         local status="${?}"
303         [[ "${normwork}" = false ]] && echo && _run_cleansh
304         exit "${status}"
305     }
306     trap '_trap_remove_work' HUP INT QUIT TERM
307
308     return 0
309 }
310
311 # Error message
312 error_exit_trap(){
313     local _exit="${?}" _line="${1}" && shift 1
314     msg_error "An exception error occurred in the function"
315     msg_error "Exit Code: ${_exit}\nLine: ${_line}\nArgument: ${ARGUMENT[*]}"
316     exit "${_exit}"
317 }
318
319 # Show settings.
320 show_settings() {
321     if [[ "${boot_splash}" = true ]]; then
322         msg_info "Boot splash is enabled."
323         msg_info "Theme is used ${theme_name}."
324     fi
325     msg_info "Language is ${locale_fullname}."
326     msg_info "Use the ${kernel} kernel."
327     msg_info "Live username is ${username}."
328     msg_info "Live user password is ${password}."
329     msg_info "The compression method of squashfs is ${sfs_comp}."
330     msg_info "Use the ${channel_name%.add} channel."
331     msg_info "Build with architecture ${arch}."
332     (( "${#additional_exclude_pkg[@]}" != 0 )) && msg_info "Excluded packages: ${additional_exclude_pkg[*]}"
333     if [[ "${noconfirm}" = false ]]; then
334         echo -e "\nPress Enter to continue or Ctrl + C to cancel."
335         read -r
336     fi
337     trap HUP INT QUIT TERM
338     trap 'umount_trap' HUP INT QUIT TERM
339     trap 'error_exit_trap $LINENO' ERR
340
341     return 0
342 }
343
344
345 # Preparation for build
346 prepare_build() {
347     # Debug mode
348     [[ "${bash_debug}" = true ]] && set -x -v
349
350     # Show alteriso version
351     [[ -n "${gitrev-""}" ]] && msg_debug "The version of alteriso is ${gitrev}"
352
353     # Load configs
354     load_config "${channel_dir}/config.any" "${channel_dir}/config.${arch}"
355
356     # Additional modules
357     modules+=("${additional_modules[@]}")
358
359     # Legacy mode
360     if [[ "$(bash "${tools_dir}/channel.sh" --version "${alteriso_version}" ver "${channel_name}")" = "3.0" ]]; then
361         msg_warn "The module cannot be used because it works with Alter ISO3.0 compatibility."
362         modules=("legacy")
363         legacy_mode=true
364         [[ "${include_extra-"unset"}" = true ]] && modules=("legacy-extra")
365     fi
366
367     # Load presets
368     local _modules=() module_check
369     for_module '[[ -f "${preset_dir}/{}" ]] && readarray -t -O "${#_modules[@]}" _modules < <(grep -h -v ^'#' "${preset_dir}/{}") || _modules+=("{}")'
370     modules=("${_modules[@]}")
371     unset _modules
372
373     # Check modules
374     module_check(){
375         msg_debug -n "Checking ${1} module ... "
376         bash "${tools_dir}/module.sh" check "${1}" || msg_error "Module ${1} is not available." "1" && echo "${module_dir}/${1}"
377     }
378     readarray -t modules < <(printf "%s\n" "${modules[@]}" | awk '!a[$0]++')
379     for_module "module_check {}"
380
381     # Load modules
382     for_module load_config "${module_dir}/{}/config.any" "${module_dir}/{}/config.${arch}"
383     msg_debug "Loaded modules: ${modules[*]}"
384     ! printf "%s\n" "${modules[@]}" | grep -x "share" >/dev/null 2>&1 && msg_warn "The share module is not loaded."
385     ! printf "%s\n" "${modules[@]}" | grep -x "base" >/dev/null 2>&1 && msg_error "The base module is not loaded." 1
386
387     # Set kernel
388     [[ "${customized_kernel}" = false ]] && kernel="${defaultkernel}"
389
390     # Parse files
391     eval "$(bash "${tools_dir}/locale.sh" -s -a "${arch}" get "${locale_name}")"
392     eval "$(bash "${tools_dir}/kernel.sh" -s -c "${channel_name}" -a "${arch}" get "${kernel}")"
393
394     # Set username and password
395     [[ "${customized_username}" = false ]] && username="${defaultusername}"
396     [[ "${customized_password}" = false ]] && password="${defaultpassword}"
397
398     # gitversion
399     [[ ! -d "${script_path}/.git" ]] && [[ "${gitversion}" = true ]] && msg_error "There is no git directory. You need to use git clone to use this feature." "1"
400     [[ "${gitversion}" = true ]] && iso_version="${iso_version}-${gitrev}"
401
402     # Generate tar file name
403     tar_ext=""
404     case "${tar_comp}" in
405         "gzip" ) tar_ext="gz"                        ;;
406         "zstd" ) tar_ext="zst"                       ;;
407         "xz" | "lzo" | "lzma") tar_ext="${tar_comp}" ;;
408     esac
409
410     # Generate iso file name
411     local _channel_name="${channel_name%.add}-${locale_version}" 
412     iso_filename="${iso_name}-${_channel_name}-${iso_version}-${arch}.iso"
413     tar_filename="${iso_filename%.iso}.tar.${tar_ext}"
414     [[ "${nochname}" = true ]] && iso_filename="${iso_name}-${iso_version}-${arch}.iso"
415     msg_debug "Iso filename is ${iso_filename}"
416
417     # check bool
418     check_bool boot_splash cleaning noconfirm nodepend customized_username customized_password noloopmod nochname tarball noiso noaur customized_syslinux norescue_entry debug bash_debug nocolor msgdebug noefi nosigcheck gitversion
419
420     # Check architecture for each channel
421     local _exit=0
422     bash "${tools_dir}/channel.sh" --version "${alteriso_version}" -a "${arch}" -n -b check "${channel_name}" || _exit="${?}"
423     ( (( "${_exit}" != 0 )) && (( "${_exit}" != 1 )) ) && msg_error "${channel_name} channel does not support current architecture (${arch})." "1"
424
425     # Run with tee
426     if [[ ! "${logging}" = false ]]; then
427         [[ "${customized_logpath}" = false ]] && logging="${out_dir}/${iso_filename%.iso}.log"
428         mkdir -p "$(dirname "${logging}")" && touch "${logging}"
429         msg_warn "Re-run sudo ${0} ${ARGUMENT[*]} --nodepend --nolog --nocolor --rerun 2>&1 | tee ${logging}"
430         sudo "${0}" "${ARGUMENT[@]}" --nolog --nocolor --nodepend --rerun 2>&1 | tee "${logging}"
431         exit "${PIPESTATUS[0]}"
432     fi
433
434     # Set argument of pkglist.sh
435     pkglist_args=("-a" "${arch}" "-k" "${kernel}" "-c" "${channel_dir}" "-l" "${locale_name}" --line)
436     [[ "${boot_splash}"              = true ]] && pkglist_args+=("-b")
437     [[ "${debug}"                    = true ]] && pkglist_args+=("-d")
438     [[ "${memtest86}"                = true ]] && pkglist_args+=("-m")
439     [[ "${nocolor}"                  = true ]] && pkglist_args+=("--nocolor")
440     (( "${#additional_exclude_pkg[@]}" >= 1 )) && pkglist_args+=("-e" "${additional_exclude_pkg[*]}")
441     pkglist_args+=("${modules[@]}")
442
443     # Set argument of aur.sh and pkgbuild.sh
444     [[ "${bash_debug}"   = true ]] && makepkg_script_args+=("-x")
445     [[ "${pacman_debug}" = true ]] && makepkg_script_args+=("-c")
446
447     return 0
448 }
449
450
451 # Setup custom pacman.conf with current cache directories.
452 make_pacman_conf() {
453     # Pacman configuration file used only when building
454     # If there is pacman.conf for each channel, use that for building
455     local _pacman_conf _pacman_conf_list=("${script_path}/pacman-${arch}.conf" "${channel_dir}/pacman-${arch}.conf" "${script_path}/system/pacman-${arch}.conf")
456     for _pacman_conf in "${_pacman_conf_list[@]}"; do
457         if [[ -f "${_pacman_conf}" ]]; then
458             build_pacman_conf="${_pacman_conf}"
459             break
460         fi
461     done
462
463     msg_debug "Use ${build_pacman_conf}"
464     sed -r "s|^#?\\s*CacheDir.+|CacheDir     = ${cache_dir}|g" "${build_pacman_conf}" > "${build_dir}/pacman.conf"
465
466     [[ "${nosigcheck}" = true ]] && sed -ir "s|^s*SigLevel.+|SigLevel = Never|g" "${build_pacman_conf}"
467
468     [[ -n "$(find "${cache_dir}" -maxdepth 1 -name '*.pkg.tar.*' 2> /dev/null)" ]] && msg_info "Use cached package files in ${cache_dir}"
469
470     # Share any architecture packages
471     #while read -r _pkg; do
472     #    if [[ ! -f "${cache_dir}/$(basename "${_pkg}")" ]]; then
473     #        ln -s "${_pkg}" "${cache_dir}"
474     #    fi
475     #done < <(find "${cache_dir}/../" -type d -name "$(basename "${cache_dir}")" -prune -o -type f -name "*-any.pkg.tar.*" -printf "%p\n")
476
477     return 0
478 }
479
480 # Base installation (airootfs)
481 make_basefs() {
482     msg_info "Creating ext4 image of 32GiB..."
483     truncate -s 32G -- "${airootfs_dir}.img"
484     mkfs.ext4 -O '^has_journal,^resize_inode' -E 'lazy_itable_init=0' -m 0 -F -- "${airootfs_dir}.img" 32G
485     tune2fs -c "0" -i "0" "${airootfs_dir}.img"
486     msg_info "Done!"
487
488     msg_info "Mounting ${airootfs_dir}.img on ${airootfs_dir}"
489     mount_airootfs
490     msg_info "Done!"
491     return 0
492 }
493
494 # Additional packages (airootfs)
495 make_packages_repo() {
496     msg_debug "pkglist.sh ${pkglist_args[*]}"
497     readarray -t _pkglist_install < <("${tools_dir}/pkglist.sh" "${pkglist_args[@]}")
498
499     # Package check
500     if [[ "${legacy_mode}" = true ]]; then
501         readarray -t _pkglist < <("${tools_dir}/pkglist.sh" "${pkglist_args[@]}")
502         readarray -t repopkgs < <(pacman-conf -c "${build_pacman_conf}" -l | xargs -I{} pacman -Sql --config "${build_pacman_conf}" --color=never {} && pacman -Sg)
503         local _pkg
504         for _pkg in "${_pkglist[@]}"; do
505             msg_info "Checking ${_pkg}..."
506             if printf "%s\n" "${repopkgs[@]}" | grep -qx "${_pkg}"; then
507                 _pkglist_install+=("${_pkg}")
508             else
509                 msg_info "${_pkg} was not found. Install it from AUR"
510                 norepopkg+=("${_pkg}")
511             fi
512         done
513     fi
514
515     # Create a list of packages to be finally installed as packages.list directly under the working directory.
516     echo -e "# The list of packages that is installed in live cd.\n#\n" > "${build_dir}/packages.list"
517     printf "%s\n" "${_pkglist_install[@]}" >> "${build_dir}/packages.list"
518
519     # Install packages on airootfs
520     _pacstrap "${_pkglist_install[@]}"
521
522     return 0
523 }
524
525 make_packages_aur() {
526     readarray -t _pkglist_aur < <("${tools_dir}/pkglist.sh" --aur "${pkglist_args[@]}")
527     _pkglist_aur=("${_pkglist_aur[@]}" "${norepopkg[@]}")
528     _aursh_args=(
529         "-a" "${aur_helper_command}" -e "${aur_helper_package}"
530         "-d" "$(printf "%s\n" "${aur_helper_depends[@]}" | tr "\n" ",")"
531         "-p" "$(printf "%s\n" "${_pkglist_aur[@]}" | tr "\n" ",")"
532         "${makepkg_script_args[@]}" -- "${aur_helper_args[@]}"
533     )
534
535     # Create a list of packages to be finally installed as packages.list directly under the working directory.
536     echo -e "\n# AUR packages.\n#\n" >> "${build_dir}/packages.list"
537     printf "%s\n" "${_pkglist_aur[@]}" >> "${build_dir}/packages.list"
538
539     # prepare for aur helper
540     _cp "${script_path}/system/aur.sh" "${airootfs_dir}/root/aur.sh"
541     _pacstrap --asdeps --needed "${aur_helper_depend[@]}"
542
543     # Run aur script
544     _run_with_pacmanconf _chroot_run "bash" "/root/aur.sh" "${_aursh_args[@]}"
545
546     # Remove script
547     remove "${airootfs_dir}/root/aur.sh"
548
549     return 0
550 }
551
552 make_pkgbuild() {
553     # Get PKGBUILD List
554     local _pkgbuild_dirs=("${channel_dir}/pkgbuild.any" "${channel_dir}/pkgbuild.${arch}")
555     for_module '_pkgbuild_dirs+=("${module_dir}/{}/pkgbuild.any" "${module_dir}/{}/pkgbuild.${arch}")'
556
557     # Copy PKGBUILD to work
558     mkdir -p "${airootfs_dir}/pkgbuilds/"
559     for _dir in $(find "${_pkgbuild_dirs[@]}" -type f -name "PKGBUILD" -print0 2>/dev/null | xargs -0 -I{} realpath {} | xargs -I{} dirname {}); do
560         msg_info "Find $(basename "${_dir}")"
561         _cp "${_dir}" "${airootfs_dir}/pkgbuilds/"
562     done
563     
564     # copy buold script
565     _cp "${script_path}/system/pkgbuild.sh" "${airootfs_dir}/root/pkgbuild.sh"
566
567     # Run build script
568     _run_with_pacmanconf _chroot_run "bash" "/root/pkgbuild.sh" "${makepkg_script_args[@]}" "/pkgbuilds"
569
570     # Remove script
571     remove "${airootfs_dir}/root/pkgbuild.sh"
572
573     return 0
574 }
575
576 # Customize installation (airootfs)
577 make_customize_airootfs() {
578     # Overwrite airootfs with customize_airootfs.
579     local _airootfs _airootfs_script_options _script _script_list _airootfs_list=() _main_script
580
581     for_module '_airootfs_list+=("${module_dir}/{}/airootfs.any" "${module_dir}/{}/airootfs.${arch}")'
582     _airootfs_list+=("${channel_dir}/airootfs.any" "${channel_dir}/airootfs.${arch}")
583
584     for _airootfs in "${_airootfs_list[@]}";do
585         if [[ -d "${_airootfs}" ]]; then
586             msg_debug "Copying airootfs ${_airootfs} ..."
587             _cp "${_airootfs}"/* "${airootfs_dir}"
588         fi
589     done
590
591     # Replace /etc/mkinitcpio.conf if Plymouth is enabled.
592     if [[ "${boot_splash}" = true ]]; then
593         install -m 0644 -- "${script_path}/mkinitcpio/mkinitcpio-plymouth.conf" "${airootfs_dir}/etc/mkinitcpio.conf"
594     else
595         install -m 0644 -- "${script_path}/mkinitcpio/mkinitcpio.conf" "${airootfs_dir}/etc/mkinitcpio.conf"
596     fi
597     
598     # customize_airootfs options
599     # -b                        : Enable boot splash.
600     # -d                        : Enable debug mode.
601     # -g <locale_gen_name>      : Set locale-gen.
602     # -i <inst_dir>             : Set install dir
603     # -k <kernel config line>   : Set kernel name.
604     # -o <os name>              : Set os name.
605     # -p <password>             : Set password.
606     # -s <shell>                : Set user shell.
607     # -t                        : Set plymouth theme.
608     # -u <username>             : Set live user name.
609     # -x                        : Enable bash debug mode.
610     # -z <locale_time>          : Set the time zone.
611     # -l <locale_name>          : Set language.
612     #
613     # -j is obsolete in AlterISO3 and cannot be used.
614     # -r is obsolete due to the removal of rebuild.
615     # -k changed in AlterISO3 from passing kernel name to passing kernel configuration.
616
617     # Generate options of customize_airootfs.sh.
618     _airootfs_script_options=(-p "${password}" -k "${kernel} ${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}")
619     [[ "${boot_splash}" = true ]] && _airootfs_script_options+=("-b")
620     [[ "${debug}" = true       ]] && _airootfs_script_options+=("-d")
621     [[ "${bash_debug}" = true  ]] && _airootfs_script_options+=("-x")
622
623     _main_script="root/customize_airootfs.sh"
624
625     _script_list=(
626         "${airootfs_dir}/root/customize_airootfs_${channel_name}.sh"
627         "${airootfs_dir}/root/customize_airootfs_${channel_name%.add}.sh"
628     )
629
630     for_module '_script_list+=("${airootfs_dir}/root/customize_airootfs_{}.sh")'
631
632     # Create script
633     for _script in "${_script_list[@]}"; do
634         if [[ -f "${_script}" ]]; then
635             (echo -e "\n#--$(basename "${_script}")--#\n" && cat "${_script}")  >> "${airootfs_dir}/${_main_script}"
636             remove "${_script}"
637         else
638             msg_debug "${_script} was not found."
639         fi
640     done
641
642     chmod 755 "${airootfs_dir}/${_main_script}"
643     cp "${airootfs_dir}/${_main_script}" "${build_dir}/$(basename "${_main_script}")"
644     _chroot_run "${_main_script}" "${_airootfs_script_options[@]}"
645     remove "${airootfs_dir}/${_main_script}"
646
647     # /root permission https://github.com/archlinux/archiso/commit/d39e2ba41bf556674501062742190c29ee11cd59
648     chmod -f 750 "${airootfs_dir}/root"
649
650     return 0
651 }
652
653 # Copy mkinitcpio archiso hooks and build initramfs (airootfs)
654 make_setup_mkinitcpio() {
655     local _hook
656     mkdir -p "${airootfs_dir}/etc/initcpio/hooks" "${airootfs_dir}/etc/initcpio/install"
657
658     for _hook in "archiso" "archiso_shutdown" "archiso_pxe_common" "archiso_pxe_nbd" "archiso_pxe_http" "archiso_pxe_nfs" "archiso_loop_mnt"; do
659         install -m 0644 -- "${script_path}/system/initcpio/hooks/${_hook}" "${airootfs_dir}/etc/initcpio/hooks"
660         install -m 0644 -- "${script_path}/system/initcpio/install/${_hook}" "${airootfs_dir}/etc/initcpio/install"
661     done
662
663     sed -i "s|%COWSPACE%|${cowspace}|g" "${airootfs_dir}/etc/initcpio/hooks/archiso"
664     sed -i "s|/usr/lib/initcpio/|/etc/initcpio/|g" "${airootfs_dir}/etc/initcpio/install/archiso_shutdown"
665     install -m 0644 -- "${script_path}/system/initcpio/install/archiso_kms" "${airootfs_dir}/etc/initcpio/install"
666     install -m 0755 -- "${script_path}/system/initcpio/script/archiso_shutdown" "${airootfs_dir}/etc/initcpio"
667     install -m 0644 -- "${script_path}/mkinitcpio/mkinitcpio-archiso.conf" "${airootfs_dir}/etc/mkinitcpio-archiso.conf"
668     [[ "${boot_splash}" = true ]] && cp "${script_path}/mkinitcpio/mkinitcpio-archiso-plymouth.conf" "${airootfs_dir}/etc/mkinitcpio-archiso.conf"
669
670     if [[ "${gpg_key}" ]]; then
671       gpg --export "${gpg_key}" >"${build_dir}/gpgkey"
672       exec 17<>"${build_dir}/gpgkey"
673     fi
674
675     _chroot_run mkinitcpio -c "/etc/mkinitcpio-archiso.conf" -k "/boot/${kernel_filename}" -g "/boot/archiso.img"
676
677     [[ "${gpg_key}" ]] && exec 17<&-
678     
679     return 0
680 }
681
682 # Prepare kernel/initramfs ${install_dir}/boot/
683 make_boot() {
684     mkdir -p "${isofs_dir}/${install_dir}/boot/${arch}"
685     install -m 0644 --  "${airootfs_dir}/boot/archiso.img" "${isofs_dir}/${install_dir}/boot/${arch}/archiso.img"
686     install -m 0644 --  "${airootfs_dir}/boot/${kernel_filename}" "${isofs_dir}/${install_dir}/boot/${arch}/${kernel_filename}"
687
688     return 0
689 }
690
691 # Add other aditional/extra files to ${install_dir}/boot/
692 make_boot_extra() {
693     if [[ -e "${airootfs_dir}/boot/memtest86+/memtest.bin" ]]; then
694         install -m 0644 -- "${airootfs_dir}/boot/memtest86+/memtest.bin" "${isofs_dir}/${install_dir}/boot/memtest"
695         install -d -m 0755 -- "${isofs_dir}/${install_dir}/boot/licenses/memtest86+/"
696         install -m 0644 -- "${airootfs_dir}/usr/share/licenses/common/GPL2/license.txt" "${isofs_dir}/${install_dir}/boot/licenses/memtest86+/"
697     fi
698
699     local _ucode_image
700     msg_info "Preparing microcode for the ISO 9660 file system..."
701
702     for _ucode_image in {intel-uc.img,intel-ucode.img,amd-uc.img,amd-ucode.img,early_ucode.cpio,microcode.cpio}; do
703         if [[ -e "${airootfs_dir}/boot/${_ucode_image}" ]]; then
704             msg_info "Installimg ${_ucode_image} ..."
705             install -m 0644 -- "${airootfs_dir}/boot/${_ucode_image}" "${isofs_dir}/${install_dir}/boot/"
706             if [[ -e "${airootfs_dir}/usr/share/licenses/${_ucode_image%.*}/" ]]; then
707                 install -d -m 0755 -- "${isofs_dir}/${install_dir}/boot/licenses/${_ucode_image%.*}/"
708                 install -m 0644 -- "${airootfs_dir}/usr/share/licenses/${_ucode_image%.*}/"* "${isofs_dir}/${install_dir}/boot/licenses/${_ucode_image%.*}/"
709             fi
710         fi
711     done
712     msg_info "Done!"
713
714     return 0
715 }
716
717 # Prepare /${install_dir}/boot/syslinux
718 make_syslinux() {
719     mkdir -p "${isofs_dir}/syslinux"
720
721     # 一時ディレクトリに設定ファイルをコピー
722     mkdir -p "${build_dir}/syslinux/"
723     _cp "${script_path}/syslinux/"* "${build_dir}/syslinux/"
724     [[ -d "${channel_dir}/syslinux" ]] && [[ "${customized_syslinux}" = true ]] && cp -af "${channel_dir}/syslinux"* "${build_dir}/syslinux/"
725
726     # copy all syslinux config to work dir
727     for _cfg in "${build_dir}/syslinux/"*.cfg; do
728         sed "s|%ARCHISO_LABEL%|${iso_label}|g;
729              s|%OS_NAME%|${os_name}|g;
730              s|%KERNEL_FILENAME%|${kernel_filename}|g;
731              s|%ARCH%|${arch}|g;
732              s|%INSTALL_DIR%|${install_dir}|g" "${_cfg}" > "${isofs_dir}/syslinux/${_cfg##*/}"
733     done
734
735     # Replace the SYSLINUX configuration file with or without boot splash.
736     local _use_config_name="nosplash" _no_use_config_name="splash" _pxe_or_sys
737     if [[ "${boot_splash}" = true ]]; then
738         _use_config_name=splash
739         _no_use_config_name=nosplash
740     fi
741     for _pxe_or_sys in "sys" "pxe"; do
742         remove "${isofs_dir}/syslinux/archiso_${_pxe_or_sys}_${_no_use_config_name}.cfg"
743         mv "${isofs_dir}/syslinux/archiso_${_pxe_or_sys}_${_use_config_name}.cfg" "${isofs_dir}/syslinux/archiso_${_pxe_or_sys}.cfg"
744     done
745
746     # Set syslinux wallpaper
747     install -m 0644 -- "${script_path}/syslinux/splash.png" "${isofs_dir}/syslinux/"
748     [[ -f "${channel_dir}/splash.png" ]] && install -m 0644 -- "${channel_dir}/splash.png" "${isofs_dir}/syslinux"
749
750     # remove config
751     local _remove_config
752     function _remove_config() {
753         remove "${isofs_dir}/syslinux/${1}"
754         sed -i "s|$(grep "${1}" "${isofs_dir}/syslinux/archiso_sys_load.cfg")||g" "${isofs_dir}/syslinux/archiso_sys_load.cfg" 
755     }
756
757     [[ "${norescue_entry}" = true  ]] && _remove_config archiso_sys_rescue.cfg
758     [[ "${memtest86}"      = false ]] && _remove_config memtest86.cfg
759
760     # copy files
761     install -m 0644 -- "${airootfs_dir}/usr/lib/syslinux/bios/"*.c32 "${isofs_dir}/syslinux/"
762     install -m 0644 -- "${airootfs_dir}/usr/lib/syslinux/bios/lpxelinux.0" "${isofs_dir}/syslinux/"
763     install -m 0644 -- "${airootfs_dir}/usr/lib/syslinux/bios/memdisk" "${isofs_dir}/syslinux/"
764
765
766     if [[ -e "${isofs_dir}/syslinux/hdt.c32" ]]; then
767         install -d -m 0755 -- "${isofs_dir}/syslinux/hdt"
768         if [[ -e "${airootfs_dir}/usr/share/hwdata/pci.ids" ]]; then
769             gzip -c -9 "${airootfs_dir}/usr/share/hwdata/pci.ids" > "${isofs_dir}/syslinux/hdt/pciids.gz"
770         fi
771         find "${airootfs_dir}/usr/lib/modules" -name 'modules.alias' -print -exec gzip -c -9 '{}' ';' -quit > "${isofs_dir}/syslinux/hdt/modalias.gz"
772     fi
773
774     return 0
775 }
776
777 # Prepare /isolinux
778 make_isolinux() {
779     install -d -m 0755 -- "${isofs_dir}/syslinux"
780     sed "s|%INSTALL_DIR%|${install_dir}|g" "${script_path}/system/isolinux.cfg" > "${isofs_dir}/syslinux/isolinux.cfg"
781     install -m 0644 -- "${airootfs_dir}/usr/lib/syslinux/bios/isolinux.bin" "${isofs_dir}/syslinux/"
782     install -m 0644 -- "${airootfs_dir}/usr/lib/syslinux/bios/isohdpfx.bin" "${isofs_dir}/syslinux/"
783
784     return 0
785 }
786
787 # Prepare /EFI
788 make_efi() {
789     local _bootfile _use_config_name="nosplash" _efi_config_list=() _efi_config
790     [[ "${boot_splash}" = true ]] && _use_config_name="splash"
791     _bootfile="$(basename "$(ls "${airootfs_dir}/usr/lib/systemd/boot/efi/systemd-boot"*".efi" )")"
792
793     install -d -m 0755 -- "${isofs_dir}/EFI/boot"
794     install -m 0644 -- "${airootfs_dir}/usr/lib/systemd/boot/efi/${_bootfile}" "${isofs_dir}/EFI/boot/${_bootfile#systemd-}"
795
796     install -d -m 0755 -- "${isofs_dir}/loader/entries"
797     sed "s|%ARCH%|${arch}|g;" "${script_path}/efiboot/${_use_config_name}/loader.conf" > "${isofs_dir}/loader/loader.conf"
798
799     readarray -t _efi_config_list < <(find "${script_path}/efiboot/${_use_config_name}/" -mindepth 1 -maxdepth 1 -type f -name "*-archiso-usb*.conf" -printf "%f\n" | grep -v "rescue")
800     [[ "${norescue_entry}" = false ]] && readarray -t _efi_config_list < <(find "${script_path}/efiboot/${_use_config_name}/" -mindepth 1 -maxdepth 1 -type f  -name "*-archiso-usb*.conf" -printf "%f\n")
801
802     for _efi_config in "${_efi_config_list[@]}"; do
803         sed "s|%ARCHISO_LABEL%|${iso_label}|g;
804             s|%OS_NAME%|${os_name}|g;
805             s|%KERNEL_FILENAME%|${kernel_filename}|g;
806             s|%ARCH%|${arch}|g;
807             s|%INSTALL_DIR%|${install_dir}|g" \
808         "${script_path}/efiboot/${_use_config_name}/${_efi_config}" > "${isofs_dir}/loader/entries/$(basename "${_efi_config}" | sed "s|usb|${arch}|g")"
809     done
810
811     # edk2-shell based UEFI shell
812     local _efi_shell_arch
813     if [[ -d "${airootfs_dir}/usr/share/edk2-shell" ]]; then
814         for _efi_shell_arch in $(find "${airootfs_dir}/usr/share/edk2-shell" -mindepth 1 -maxdepth 1 -type d -print0 | xargs -0 -I{} basename {}); do
815             if [[ -f "${airootfs_dir}/usr/share/edk2-shell/${_efi_shell_arch}/Shell_Full.efi" ]]; then
816                 cp "${airootfs_dir}/usr/share/edk2-shell/${_efi_shell_arch}/Shell_Full.efi" "${isofs_dir}/EFI/shell_${_efi_shell_arch}.efi"
817             elif [[ -f "${airootfs_dir}/usr/share/edk2-shell/${_efi_shell_arch}/Shell.efi" ]]; then
818                 cp "${airootfs_dir}/usr/share/edk2-shell/${_efi_shell_arch}/Shell.efi" "${isofs_dir}/EFI/shell_${_efi_shell_arch}.efi"
819             else
820                 continue
821             fi
822             echo -e "title  UEFI Shell ${_efi_shell_arch}\nefi    /EFI/shell_${_efi_shell_arch}.efi" > "${isofs_dir}/loader/entries/uefi-shell-${_efi_shell_arch}.conf"
823         done
824     fi
825
826     return 0
827 }
828
829 # Prepare efiboot.img::/EFI for "El Torito" EFI boot mode
830 make_efiboot() {
831     truncate -s 128M "${build_dir}/efiboot.img"
832     mkfs.fat -n ARCHISO_EFI "${build_dir}/efiboot.img"
833
834     mkdir -p "${build_dir}/efiboot"
835     mount "${build_dir}/efiboot.img" "${build_dir}/efiboot"
836
837     mkdir -p "${build_dir}/efiboot/EFI/alteriso/${arch}" "${build_dir}/efiboot/EFI/boot" "${build_dir}/efiboot/loader/entries"
838     _cp "${isofs_dir}/${install_dir}/boot/${arch}/${kernel_filename}" "${build_dir}/efiboot/EFI/alteriso/${arch}/${kernel_filename}.efi"
839     _cp "${isofs_dir}/${install_dir}/boot/${arch}/archiso.img" "${build_dir}/efiboot/EFI/alteriso/${arch}/archiso.img"
840
841     local _ucode_image _efi_config _use_config_name="nosplash" _bootfile
842     for _ucode_image in "${airootfs_dir}/boot/"{intel-uc.img,intel-ucode.img,amd-uc.img,amd-ucode.img,early_ucode.cpio,microcode.cpio}; do
843         [[ -e "${_ucode_image}" ]] && _cp "${_ucode_image}" "${build_dir}/efiboot/EFI/alteriso/"
844     done
845
846     _cp "${airootfs_dir}/usr/share/efitools/efi/HashTool.efi" "${build_dir}/efiboot/EFI/boot/"
847
848     _bootfile="$(basename "$(ls "${airootfs_dir}/usr/lib/systemd/boot/efi/systemd-boot"*".efi" )")"
849     _cp "${airootfs_dir}/usr/lib/systemd/boot/efi/${_bootfile}" "${build_dir}/efiboot/EFI/boot/${_bootfile#systemd-}"
850
851     [[ "${boot_splash}" = true ]] && _use_config_name="splash"
852     sed "s|%ARCH%|${arch}|g;" "${script_path}/efiboot/${_use_config_name}/loader.conf" > "${build_dir}/efiboot/loader/loader.conf"
853
854     find "${isofs_dir}/loader/entries/" -maxdepth 1 -mindepth 1 -name "uefi-shell*" -type f -printf "%p\0" | xargs -0 -I{} cp {} "${build_dir}/efiboot/loader/entries/"
855
856     readarray -t _efi_config_list < <(find "${script_path}/efiboot/${_use_config_name}/" -mindepth 1 -maxdepth 1 -type f -name "*-archiso-cd*.conf" -printf "%f\n" | grep -v "rescue")
857     [[ "${norescue_entry}" = false ]] && readarray -t _efi_config_list < <(find "${script_path}/efiboot/${_use_config_name}/" -mindepth 1 -maxdepth 1 -type f  -name "*-archiso-cd*.conf" -printf "%f\n")
858
859     for _efi_config in "${_efi_config_list[@]}"; do
860         sed "s|%ARCHISO_LABEL%|${iso_label}|g;
861             s|%OS_NAME%|${os_name}|g;
862             s|%KERNEL_FILENAME%|${kernel_filename}|g;
863             s|%ARCH%|${arch}|g;
864             s|%INSTALL_DIR%|${install_dir}|g" \
865         "${script_path}/efiboot/${_use_config_name}/${_efi_config}" > "${build_dir}/efiboot/loader/entries/$(basename "${_efi_config}" | sed "s|cd|${arch}|g")"
866     done
867
868     find "${isofs_dir}/EFI" -maxdepth 1 -mindepth 1 -name "shell*.efi" -printf "%p\0" | xargs -0 -I{} cp {} "${build_dir}/efiboot/EFI/"
869     umount -d "${build_dir}/efiboot"
870
871     return 0
872 }
873
874 # Compress tarball
875 make_tarball() {
876     # backup airootfs.img for tarball
877     msg_debug "Tarball filename is ${tar_filename}"
878     msg_info "Copying airootfs.img ..."
879     cp "${airootfs_dir}.img" "${airootfs_dir}.img.org"
880
881     # Run script
882     mount_airootfs
883     [[ -f "${airootfs_dir}/root/optimize_for_tarball.sh" ]] && _chroot_run "bash /root/optimize_for_tarball.sh -u ${username}"
884     _cleanup_common
885     _chroot_run "mkinitcpio -P"
886     remove "${airootfs_dir}/root/optimize_for_tarball.sh"
887
888     # make
889     tar_comp_opt+=("--${tar_comp}")
890     mkdir -p "${out_dir}"
891     msg_info "Creating tarball..."
892     cd -- "${airootfs_dir}"
893     msg_debug "Run tar -c -v -p -f \"${out_dir}/${tar_filename}\" ${tar_comp_opt[*]} ./*"
894     tar -c -v -p -f "${out_dir}/${tar_filename}" "${tar_comp_opt[@]}" ./*
895     cd -- "${OLDPWD}"
896
897     # checksum
898     _mkchecksum "${out_dir}/${tar_filename}"
899     msg_info "Done! | $(ls -sh "${out_dir}/${tar_filename}")"
900
901     remove "${airootfs_dir}.img"
902     mv "${airootfs_dir}.img.org" "${airootfs_dir}.img"
903
904     [[ "${noiso}" = true ]] && msg_info "The password for the live user and root is ${password}."
905     
906     return 0
907 }
908
909
910 # Build airootfs filesystem image
911 make_prepare() {
912     mount_airootfs
913
914     # Create packages list
915     msg_info "Creating a list of installed packages on live-enviroment..."
916     pacman-key --init
917     pacman -Q --sysroot "${airootfs_dir}" | tee "${isofs_dir}/${install_dir}/pkglist.${arch}.txt" "${build_dir}/packages-full.list" > /dev/null
918
919     # Cleanup
920     remove "${airootfs_dir}/root/optimize_for_tarball.sh"
921     _cleanup_airootfs
922
923     # Create squashfs
924     mkdir -p -- "${isofs_dir}/${install_dir}/${arch}"
925     msg_info "Creating SquashFS image, this may take some time..."
926     mksquashfs "${airootfs_dir}" "${build_dir}/iso/${install_dir}/${arch}/airootfs.sfs" -noappend -comp "${sfs_comp}" "${sfs_comp_opt[@]}"
927
928     # Create checksum
929     msg_info "Creating checksum file for self-test..."
930     echo "$(sha512sum "${isofs_dir}/${install_dir}/${arch}/airootfs.sfs" | getclm 1) airootfs.sfs" > "${isofs_dir}/${install_dir}/${arch}/airootfs.sha512"
931     msg_info "Done!"
932
933     # Sign with gpg
934     if [[ -v gpg_key ]] && (( "${#gpg_key}" != 0 )); then
935         msg_info "Creating signature file ($gpg_key) ..."
936         cd -- "${isofs_dir}/${install_dir}/${arch}"
937         gpg --detach-sign --default-key "${gpg_key}" "airootfs.sfs"
938         cd -- "${OLDPWD}"
939         msg_info "Done!"
940     fi
941
942     umount_work
943
944     [[ "${cleaning}" = true ]] && remove "${airootfs_dir}" "${airootfs_dir}.img"
945
946     return 0
947 }
948
949 make_alteriso_info(){
950     # iso version info
951     if [[ "${include_info}" = true ]]; then
952         local _info_file="${isofs_dir}/alteriso-info" _version="${iso_version}"
953         remove "${_info_file}"; touch "${_info_file}"
954         [[ -d "${script_path}/.git" ]] && [[ "${gitversion}" = false ]] && _version="${iso_version}-${gitrev}"
955         "${tools_dir}/alteriso-info.sh" -a "${arch}" -b "${boot_splash}" -c "${channel_name%.add}" -d "${iso_publisher}" -k "${kernel}" -o "${os_name}" -p "${password}" -u "${username}" -v "${_version}" -m "$(printf "%s," "${modules[@]}")" > "${_info_file}"
956     fi
957
958     return 0
959 }
960
961 # Add files to the root of isofs
962 make_overisofs() {
963     local _over_isofs_list _isofs
964     _over_isofs_list=("${channel_dir}/over_isofs.any""${channel_dir}/over_isofs.${arch}")
965     for_module '_over_isofs_list+=("${module_dir}/{}/over_isofs.any" "${module_dir}/{}/over_isofs.${arch}")'
966     for _isofs in "${_over_isofs_list[@]}"; do
967         [[ -d "${_isofs}" ]] && [[ -n "$(find "${_isofs}" -mindepth 1 -maxdepth 2)" ]] &&  cp -af "${_isofs}"/* "${isofs_dir}"
968     done
969
970     return 0
971 }
972
973 # Build ISO
974 make_iso() {
975     local _iso_efi_boot_args=()
976     # If exists, add an EFI "El Torito" boot image (FAT filesystem) to ISO-9660 image.
977     [[ -f "${build_dir}/efiboot.img" ]] && _iso_efi_boot_args=(-append_partition 2 C12A7328-F81F-11D2-BA4B-00A0C93EC93B "${build_dir}/efiboot.img" -appended_part_as_gpt -eltorito-alt-boot -e --interval:appended_partition_2:all:: -no-emul-boot -isohybrid-gpt-basdat)
978
979     mkdir -p -- "${out_dir}"
980     msg_info "Creating ISO image..."
981     xorriso -as mkisofs \
982         -iso-level 3 \
983         -full-iso9660-filenames \
984         -joliet \
985         -joliet-long \
986         -rational-rock \
987         -volid "${iso_label}" \
988         -appid "${iso_application}" \
989         -publisher "${iso_publisher}" \
990         -preparer "prepared by AlterISO" \
991         -eltorito-boot syslinux/isolinux.bin \
992         -eltorito-catalog syslinux/boot.cat \
993         -no-emul-boot -boot-load-size 4 -boot-info-table \
994         -isohybrid-mbr "${build_dir}/iso/syslinux/isohdpfx.bin" \
995         "${_iso_efi_boot_args[@]}" \
996         -output "${out_dir}/${iso_filename}" \
997         "${build_dir}/iso/"
998     _mkchecksum "${out_dir}/${iso_filename}"
999     msg_info "Done! | $(ls -sh -- "${out_dir}/${iso_filename}")"
1000
1001     msg_info "The password for the live user and root is ${password}."
1002
1003     return 0
1004 }
1005
1006
1007 # Parse options
1008 ARGUMENT=("${DEFAULT_ARGUMENT[@]}" "${@}") OPTS=("a:" "b" "c:" "d" "e" "g:" "h" "j" "k:" "l:" "o:" "p:" "r" "t:" "u:" "w:" "x") OPTL=("arch:" "boot-splash" "comp-type:" "debug" "cleaning" "cleanup" "gpgkey:" "help" "lang:" "japanese" "kernel:" "out:" "password:" "comp-opts:" "user:" "work:" "bash-debug" "nocolor" "noconfirm" "nodepend" "gitversion" "msgdebug" "noloopmod" "tarball" "noiso" "noaur" "nochkver" "channellist" "config:" "noefi" "nodebug" "nosigcheck" "normwork" "log" "logpath:" "nolog" "nopkgbuild" "pacman-debug" "confirm" "tar-type:" "tar-opts:" "add-module:" "nogitversion" "cowspace:" "rerun" "depend" "loopmod")
1009 GETOPT=(-o "$(printf "%s," "${OPTS[@]}")" -l "$(printf "%s," "${OPTL[@]}")" -- "${ARGUMENT[@]}")
1010 getopt -Q "${GETOPT[@]}" || exit 1 # 引数エラー判定
1011 readarray -t OPT < <(getopt "${GETOPT[@]}") # 配列に代入
1012
1013 eval set -- "${OPT[@]}"
1014 msg_debug "Argument: ${OPT[*]}"
1015 unset OPT OPTS OPTL DEFAULT_ARGUMENT GETOPT
1016
1017 while true; do
1018     case "${1}" in
1019         -c | --comp-type)
1020             case "${2}" in
1021                 "gzip" | "lzma" | "lzo" | "lz4" | "xz" | "zstd") sfs_comp="${2}" ;;
1022                 *) msg_error "Invaild compressors '${2}'" '1' ;;
1023             esac
1024             shift 2
1025             ;;
1026         -j | --japanese)
1027             msg_error "This option is obsolete in AlterISO 3. To use Japanese, use \"-l ja\"." "1"
1028             ;;
1029         -k | --kernel)
1030             customized_kernel=true kernel="${2}"
1031             shift 2
1032             ;;
1033         -p | --password)
1034             customized_password=true password="${2}"
1035             shift 2
1036             ;;
1037         -t | --comp-opts)
1038             if [[ "${2}" = "reset" ]]; then
1039                 sfs_comp_opt=()
1040             else
1041                 IFS=" " read -r -a sfs_comp_opt <<< "${2}"
1042             fi
1043             shift 2
1044             ;;
1045         -u | --user)
1046             customized_username=true
1047             username="$(echo -n "${2}" | sed 's/ //g' | tr '[:upper:]' '[:lower:]')"
1048             shift 2
1049             ;;
1050         --nodebug)
1051             debug=false msgdebug=false bash_debug=false
1052             shift 1
1053             ;;
1054         --logpath)
1055             logging="${2}" customized_logpath=true
1056             shift 2
1057             ;;
1058         --tar-type)
1059             case "${2}" in
1060                 "gzip" | "lzma" | "lzo" | "lz4" | "xz" | "zstd") tar_comp="${2}" ;;
1061                 *) msg_error "Invaild compressors '${2}'" '1' ;;
1062             esac
1063             shift 2
1064             ;;
1065         --tar-opts)
1066             IFS=" " read -r -a tar_comp_opt <<< "${2}"
1067             shift 2
1068             ;;
1069         --add-module)
1070             readarray -t -O "${#additional_modules[@]}" additional_modules < <(echo "${2}" | tr "," "\n")
1071             msg_debug "Added modules: ${additional_modules[*]}"
1072             shift 2
1073             ;;
1074         -g | --gpgkey               ) gpg_key="${2}"     && shift 2 ;;
1075         -h | --help                 ) _usage 0                      ;;
1076         -a | --arch                 ) arch="${2}"        && shift 2 ;;
1077         -d | --debug                ) debug=true         && shift 1 ;;
1078         -e | --cleaning | --cleanup ) cleaning=true      && shift 1 ;;
1079         -b | --boot-splash          ) boot_splash=true   && shift 1 ;;
1080         -l | --lang                 ) locale_name="${2}" && shift 2 ;;
1081         -o | --out                  ) out_dir="${2}"     && shift 2 ;;
1082         -r | --tarball              ) tarball=true       && shift 1 ;;
1083         -w | --work                 ) work_dir="${2}"    && shift 2 ;;
1084         -x | --bash-debug           ) bash_debug=true    && shift 1 ;;
1085         --gitversion                ) gitversion=true    && shift 1 ;;
1086         --noconfirm                 ) noconfirm=true     && shift 1 ;;
1087         --confirm                   ) noconfirm=false    && shift 1 ;;
1088         --nodepend                  ) nodepend=true      && shift 1 ;;
1089         --nocolor                   ) nocolor=true       && shift 1 ;;
1090         --msgdebug                  ) msgdebug=true      && shift 1 ;;
1091         --noloopmod                 ) noloopmod=true     && shift 1 ;;
1092         --noiso                     ) noiso=true         && shift 1 ;;
1093         --noaur                     ) noaur=true         && shift 1 ;;
1094         --nochkver                  ) nochkver=true      && shift 1 ;;
1095         --noefi                     ) noefi=true         && shift 1 ;;
1096         --channellist               ) show_channel_list  && exit  0 ;;
1097         --config                    ) source "${2}"      ;  shift 2 ;;
1098         --pacman-debug              ) pacman_debug=true  && shift 1 ;;
1099         --nosigcheck                ) nosigcheck=true    && shift 1 ;;
1100         --normwork                  ) normwork=true      && shift 1 ;;
1101         --log                       ) logging=true       && shift 1 ;;
1102         --nolog                     ) logging=false      && shift 1 ;;
1103         --nopkgbuild                ) nopkgbuild=true    && shift 1 ;;
1104         --nogitversion              ) gitversion=false   && shift 1 ;;
1105         --cowspace                  ) cowspace="${2}"    && shift 2 ;;
1106         --rerun                     ) rerun=true         && shift 1 ;;
1107         --depend                    ) nodepend=false     && shift 1 ;;
1108         --loopmod                   ) noloopmod=false    && shift 1 ;;
1109         --                          ) shift 1            && break   ;;
1110         *)
1111             msg_error "Argument exception error '${1}'"
1112             msg_error "Please report this error to the developer." 1
1113             ;;
1114     esac
1115 done
1116
1117 # Check root.
1118 if (( ! "${EUID}" == 0 )); then
1119     msg_warn "This script must be run as root." >&2
1120     msg_warn "Re-run 'sudo ${0} ${ARGUMENT[*]}'"
1121     sudo "${0}" "${ARGUMENT[@]}" --rerun
1122     exit "${?}"
1123 fi
1124
1125 # Show config message
1126 msg_debug "Use the default configuration file (${defaultconfig})."
1127 [[ -f "${script_path}/custom.conf" ]] && msg_debug "The default settings have been overridden by custom.conf"
1128
1129 # Debug mode
1130 [[ "${bash_debug}" = true ]] && set -x -v
1131
1132 # Check for a valid channel name
1133 if [[ -n "${1+SET}" ]]; then
1134     case "$(bash "${tools_dir}/channel.sh" --version "${alteriso_version}" -n check "${1}"; printf "%d" "${?}")" in
1135         "2")
1136             msg_error "Invalid channel ${1}" "1"
1137             ;;
1138         "1")
1139             channel_dir="${1}"
1140             channel_name="$(basename "${1%/}")"
1141             ;;
1142         "0")
1143             channel_dir="${script_path}/channels/${1}"
1144             channel_name="${1}"
1145             ;;
1146     esac
1147 else
1148     channel_dir="${script_path}/channels/${channel_name}"
1149 fi
1150
1151 # Set vars
1152 build_dir="${work_dir}/build/${arch}" cache_dir="${work_dir}/cache/${arch}" airootfs_dir="${build_dir}/airootfs" isofs_dir="${build_dir}/iso" lockfile_dir="${build_dir}/lockfile" gitrev="$(cd "${script_path}"; git rev-parse --short HEAD)" preset_dir="${script_path}/presets"
1153
1154 # Create dir
1155 for _dir in build_dir cache_dir airootfs_dir isofs_dir lockfile_dir out_dir; do
1156     mkdir -p "$(eval "echo \$${_dir}")"
1157     msg_debug "${_dir} is $(realpath "$(eval "echo \$${_dir}")")"
1158     eval "${_dir}=\"$(realpath "$(eval "echo \$${_dir}")")\""
1159 done
1160
1161 # Set for special channels
1162 if [[ -d "${channel_dir}.add" ]]; then
1163     channel_name="${1}"
1164     channel_dir="${channel_dir}.add"
1165 elif [[ "${channel_name}" = "clean" ]]; then
1166    _run_cleansh
1167     exit 0
1168 fi
1169
1170 # Check channel version
1171 msg_debug "channel path is ${channel_dir}"
1172 if [[ ! "$(bash "${tools_dir}/channel.sh" --version "${alteriso_version}" ver "${channel_name}" | cut -d "." -f 1)" = "$(echo "${alteriso_version}" | cut -d "." -f 1)" ]] && [[ "${nochkver}" = false ]]; then
1173     msg_error "This channel does not support Alter ISO 3."
1174     if [[ -d "${script_path}/.git" ]]; then
1175         msg_error "Please run \"git checkout alteriso-2\"" "1"
1176     else
1177         msg_error "Please download old version here.\nhttps://github.com/FascodeNet/alterlinux/releases" "1"
1178     fi
1179 fi
1180
1181 prepare_env
1182 prepare_build
1183 show_settings
1184 run_once make_pacman_conf
1185 run_once make_basefs # Mount airootfs
1186 run_once make_packages_repo
1187 [[ "${noaur}" = false ]] && run_once make_packages_aur
1188 [[ "${nopkgbuild}" = false ]] && run_once make_pkgbuild
1189 run_once make_customize_airootfs
1190 run_once make_setup_mkinitcpio
1191 [[ "${tarball}" = true ]] && run_once make_tarball
1192 if [[ "${noiso}" = false ]]; then
1193     run_once make_syslinux
1194     run_once make_isolinux
1195     run_once make_boot
1196     run_once make_boot_extra
1197     if [[ "${noefi}" = false ]]; then
1198         run_once make_efi
1199         run_once make_efiboot
1200     fi
1201     run_once make_alteriso_info
1202     run_once make_prepare
1203     run_once make_overisofs
1204     run_once make_iso
1205 fi
1206
1207 [[ "${cleaning}" = true ]] && _run_cleansh
1208
1209 exit 0