OSDN Git Service

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