OSDN Git Service

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