OSDN Git Service

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