OSDN Git Service

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