#!/bin/bash # Script for building bootable .iso images from downloaded macOS upgrade # Copyright (C) 2015-2017 Karlson2k (Evgeny Grin) # # You can run, copy, modify, publish and do whatever you want with this # script as long as this message and copyright string above are preserved. # You are also explicitly allowed to reuse this script under any LGPL or # GPL license or under any BSD-style license. # # # Latest version: # https://raw.githubusercontent.com/Karlson2k/k2k-OSX-Tools/master/Create_osx_install_iso/create_osx_install_iso.sh # # Version 1.0.6 readonly script_org_name='create_osx_install_iso.sh' || exit 127 unset work_dir script_name tmp_dir OSX_inst_name OSX_inst_inst_dmg_mnt \ OSX_inst_img_rw_mnt OSX_inst_img_rw_dev || exit 127 work_dir="$PWD" save_IFS="$IFS" || exit 127 export LANG='en_US.UTF-8' || exit 127 # prevent localization of output, not really required [[ `ps -o comm -p $$ | tail -n1 2>/dev/null` =~ bash$ ]] || { echo "Script is designed to be run only with bash" exit 127 } [[ "$(uname -s)" == Darwin ]] || { echo "Script can be run only on Mac OS X" exit 127 } cleanup() { trap - SIGHUP SIGTERM SIGQUIT SIGINT SIGSTOP SIGTSTP EXIT if [[ -n $tmp_dir ]] && [[ -e "$tmp_dir" ]]; then if [[ -e "$OSX_inst_img_rw_dev" ]]; then echo "Unmounting writable image..." hdiutil detach "$OSX_inst_img_rw_dev" -force fi if [[ -e "$OSX_inst_img_rw_mnt" ]]; then echo "Unmounting writable image..." hdiutil detach "$OSX_inst_img_rw_mnt" -force fi if [[ -e "$OSX_inst_inst_dmg_mnt" ]]; then echo "Unmounting temporary mounted source image..." hdiutil detach "$OSX_inst_inst_dmg_mnt" -force fi echo "Removing temporary files..." rm -fdR "$tmp_dir" fi } trap '{ exit_code="$?"; cleanup; exit $exit_code; }' EXIT echo_term_ansi_m() { local n_param='' if [[ "$1" == "-n" ]]; then n_param="$1" shift elif [[ -z "$1" ]]; then shift fi local m_code="$1" shift if [[ -t 1 ]]; then echo $n_param $'\e['"${m_code}m$@"$'\e[0m' else echo $n_param "$@" fi } echo_neutral() { echo "$@" } echo_enh() { echo_term_ansi_m '1;97' "$@" } echo_enh_n() { echo_term_ansi_m -n '1;97' "$@" } echo_positive() { echo_term_ansi_m '1;92' "$@" } echo_positive_n() { echo_term_ansi_m -n '1;92' "$@" } echo_warning() { echo_term_ansi_m '1;93' "$@" } echo_warning_n() { echo_term_ansi_m -n '1;93' "$@" } echo_error() { echo_term_ansi_m '1;91' "$@" 1>&2 } echo_error_n() { echo_term_ansi_m -n '1;91' "$@" 1>&2 } exit_with_error() { trap - SIGHUP SIGTERM SIGQUIT SIGINT SIGSTOP SIGTSTP EXIT if [[ -n $1 ]]; then echo_error "Error: $1" else echo_error "Error." fi cleanup [[ $2 > 0 ]] && exit $2 exit 1 } trap '{ exit_with_error "unexpected interrupt at line $LINENO"; exit 255; }' SIGHUP SIGTERM SIGQUIT SIGINT SIGSTOP SIGTSTP # trap 'echo "Line number: $LINENO"; read -p "\"Enter\" to continue" ' DEBUG stage_start() { echo_enh_n "$@... " } stage_start_nl() { stage_start "$@" echo '' } stage_end_ok() { if [[ -z "$@" ]]; then echo_positive "OK" else echo_positive "$@" fi } stage_end_warn() { if [[ -z "$@" ]]; then echo_warning "OK, but with warnings" else echo_warning "$@" fi } is_answer_valid() { local answ="$1" shift while [[ -n $1 ]]; do [[ "$answ" == "$1" ]] && return 0 shift done return 1 } script_name="$(basename "${BASH_SOURCE[0]}" 2>/dev/null)" [[ -n "$script_name" ]] || script_name="${0##*/}" # fallback [[ -n "$script_name" ]] || script_name="${script_org_name}" # second fallback script_version="$(sed -n -e '\|^# Version| {s|^# Version \(.*$\)|\1|p; q;}' "${BASH_SOURCE[0]}" 2>/dev/null)" || unset script_version [[ -n "$script_version" ]] || script_version="Unknown" print_help() { echo "\ Script for creating .iso images from downloaded macOS upgrade application. Usage:" echo_enh_n " $script_name"; echo " [options] Valid options are: -a, --app[lication] Path and name of macOS upgrade application. Path can be omitted if application is located at default path. -i, --iso Path with optional name for output .iso -m, --method Use method number D to create installation image: Method 1 create image that most close to Apple's image, but potentially less compatible with some BIOSes/EFI. Method 2 create more BIOS/EFI-friendly images, but require more disk space for conversion. Method 3 can produce bootable images without super user rights. -n, --nosudo Do not use sudo command -v, --verify Do not skip verifications (slow down image creation) -h, --help Print this message and exit -V, --version Print version information and exit" } print_version() { echo "${script_org_name} version $script_version" } exit_with_cmd_err() { echo_error "$@" print_help 1>&2 exit 32 } unset cmd_par_app cmd_par_iso test_name ver_opt cr_method || exit_with_error "Can't unset variable" allow_sudo='yes' && ver_opt='--noverify' || exit_with_error "Can't set variable" while [[ -n "$1" ]]; do case "$1" in -a | --app | --application ) cmd_par_app="$2" [[ -n "$cmd_par_app" ]] && [[ "$cmd_par_app" != "--iso" ]] || exit_with_cmd_err "No Application name given for $1" shift 2 ;; -i | --iso ) cmd_par_iso="$2" [[ -n "$cmd_par_iso" ]] && [[ "$cmd_par_iso" != "--app" ]] || exit_with_cmd_err "No .iso name given for $1" shift 2 ;; -m | --method ) [[ -z "$2" ]] && exit_with_cmd_err "Method not specified for $1" cr_method="method${2}" shift 2 ;; -m* ) cr_method="method${1#-m}"; shift ;; --method* ) cr_method="method${1#--method}"; shift ;; -n | --nosudo ) allow_sudo='no'; shift ;; -v | --verify ) unset ver_opt; shift ;; -h | --h | --help ) print_help; exit 0 ;; -V | --version ) print_version; exit 0 ;; *) exit_with_cmd_err "Unknown option \"$1\"" esac done [[ "${cr_method-notset}" == "notset" ]] || [[ "$cr_method" =~ ^"method"[1-3]$ ]] || exit_with_cmd_err "Unknown creation method specified: ${cr_method#method}" check_intall_app() { [[ -n "$1" ]] || return 3 [[ -d "$1" ]] || return 2 [[ -e "$1/Contents/SharedSupport/InstallESD.dmg" ]] || return 1 return 0 } if [[ -z "$cmd_par_app" ]]; then stage_start "Looking for downloaded OS upgrades" unset test_name || exit_with_error IFS=$'\n' dirlist=(`find /Applications -maxdepth 1 -mindepth 1 \( -name 'Install OS X *.app' -or -name 'Install macOS *.app' \)`) || exit_with_error "Can't find downloaded macOS upgrade" IFS="$save_IFS" [[ ${#dirlist[@]} -eq 0 ]] && exit_with_error "Can't find downloaded macOS upgrade" stage_end_ok "found" if [[ ${#dirlist[@]} -gt 1 ]]; then echo "Several OS upgrades were found." echo "Which one OS upgrade do you want to use?" valid_answers=() unset test_name || exit_with_error for ((i=0;i<${#dirlist[@]};i++)); do test_name="${dirlist[$i]#/Applications/Install }" echo "$((i+1))) ${test_name%.app}" valid_answers[$i]="$((i+1))" done read -n 1 -p "[1-$i, q for quit]: " answer echo '' until is_answer_valid $answer ${valid_answers[@]} 'q'; do echo "'$answer' is incorrect response" read -n 1 -p "Select ""$(seq -s ', ' -t '\b\b' 1 $i)"" or q for quit: " answer echo '' done [[ "$answer" == "q" ]] && { echo_warning "Aborted."; exit 2; } OSX_inst_app="${dirlist[$((answer-1))]}" else OSX_inst_app="${dirlist[0]}" fi echo_enh "Using \"$OSX_inst_app\"." else stage_start "Checking for specified OS upgrade" unset OSX_inst_app || exit_with_error if check_intall_app "${cmd_par_app%/}"; then # direct location with path if [[ "${cmd_par_app:0:1}" == "/" ]]; then OSX_inst_app="${cmd_par_app%/}" # absolute path else OSX_inst_app="$(pwd)/${cmd_par_app%/}" # relative path test_name="$(cd "$OSX_inst_app/" 2>/dev/null && pwd)" || unset test_name || exit_with_error [[ -n "$test_name" ]] && OSX_inst_app="$test_name" # use absolute path if possible fi elif [[ "${cmd_par_app%%/*}" == "${cmd_par_app%/}" ]]; then # check /Applications test_name="${cmd_par_app%/}" test_name="${test_name%.app}.app" if check_intall_app "/Applications/${test_name}"; then OSX_inst_app="/Applications/${test_name}" elif check_intall_app "/Applications/Install ${test_name}"; then OSX_inst_app="/Applications/Install ${test_name}" elif check_intall_app "/Applications/Install OS X ${test_name}"; then OSX_inst_app="/Applications/Install OS X ${test_name}" elif check_intall_app "/Applications/Install macOS ${test_name}"; then OSX_inst_app="/Applications/Install macOS ${test_name}" fi fi [[ -n "$OSX_inst_app" ]] || exit_with_error "\"$cmd_par_app\" is not valid macOS Install application" stage_end_ok "found" echo_enh "Using \"$OSX_inst_app\"." fi stage_start "Detecting macOS name for installation" unset test_name OSX_inst_prt_name || exit_with_error test_name=$(sed -n -e '\|CFBundleDisplayName| { N; s|^.*\(.\{1,\}\).*$|\1|p; q; }' \ "$OSX_inst_app/Contents/Info.plist" 2>/dev/null) || unset test_name if [[ -n "$test_name" ]]; then OSX_inst_name="${test_name#Install }" OSX_inst_prt_name="Install $OSX_inst_name" stage_end_ok "$OSX_inst_name" else OSX_inst_name=$(echo "$OSX_inst_app"|sed -n -e's|^.*Install \(\(macOS|OS X\) .\{1,\}\)\.app.*$|\1|p' 2>/dev/null) || unset OSX_inst_name || exit_with_error [[ -z "$OSX_inst_name" ]] && OSX_inst_name="macOS" OSX_inst_prt_name="Install $OSX_inst_name" stage_end_warn "guessed \"$OSX_inst_name\"" fi stage_start "Creating temporary directory" tmp_dir="$(mktemp -d -t osx_iso_tmpdir)" || exit_with_error "Can't create tmp directory" # mkdir "tmp-tmp" # tmp_dir=$(cd tmp-tmp && pwd) || exit_with_error "Can't create tmp directory" stage_end_ok "succeed" stage_start_nl "Mounting InstallESD.dmg" OSX_inst_inst_dmg="$OSX_inst_app"'/Contents/SharedSupport/InstallESD.dmg' OSX_inst_inst_dmg_mnt="$tmp_dir/InstallESD_dmg_mnt" hdiutil attach "$OSX_inst_inst_dmg" -kernel -readonly -nobrowse ${ver_opt+-noverify} -mountpoint "$OSX_inst_inst_dmg_mnt" || exit_with_error "Can't mount installation image. Reboot recommended before retry." OSX_inst_base_dmg="$OSX_inst_inst_dmg_mnt/BaseSystem.dmg" || exit_with_error stage_end_ok "Mounting succeed" stage_start "Calculating required image size" unset OSX_inst_inst_dmg_used_size OSX_inst_base_dmg_real_size OSX_inst_base_dmg_size || exit_with_error "Can't unset variables" OSX_inst_inst_dmg_used_size=$(hdiutil imageinfo "$OSX_inst_inst_dmg" -plist | \ sed -En -e '\|Total Non-Empty Bytes| { N; s|^.*(.+).*$|\1|p; q; }') || unset OSX_inst_inst_dmg_used_size OSX_inst_base_dmg_real_size=$(hdiutil imageinfo "$OSX_inst_base_dmg" -plist | \ sed -En -e '\|Total Bytes| { N; s|^.*(.+).*$|\1|p; q; }') || unset OSX_inst_base_dmg_real_size OSX_inst_base_dmg_size=$(stat -f %z "$OSX_inst_base_dmg") || unset OSX_inst_base_dmg_size ((OSX_inst_base_dmg_size=(OSX_inst_base_dmg_size/512)*512)) # round to sector bound if !((OSX_inst_inst_dmg_used_size)) || !((OSX_inst_base_dmg_real_size)) || !((OSX_inst_base_dmg_size)); then ((OSX_inst_img_rw_size=10*1024*1024*1024)) stage_end_warn "Can't calculate, will use $OSX_inst_img_rw_size ($((OSX_inst_img_rw_size/(1024*1024))) MiB)" else ((OSX_inst_img_rw_size=OSX_inst_base_dmg_real_size+(OSX_inst_inst_dmg_used_size-OSX_inst_base_dmg_size) )) ((OSX_inst_img_rw_size+=OSX_inst_img_rw_size/10)) # add 10% for overhead, no need to be precise ((OSX_inst_img_rw_size=(OSX_inst_img_rw_size/512 + 1)*512)) # round to sector bound stage_end_ok "$OSX_inst_img_rw_size ($((OSX_inst_img_rw_size/(1024*1024))) MiB)" fi stage_start "Checking for available disk space" unset tmp_dir_free_space || exit_with_error tmp_dir_free_space="$(df -bi "$tmp_dir" | \ sed -nE -e 's|^.+[[:space:]]+[0-9]+[[:space:]]+[0-9]+[[:space:]]+([0-9]+)[[:space:]]+[0-9]{1,3}%[[:space:]]+[0-9]+[[:space:]]+[0-9]+[[:space:]]+[0-9]{1,3}%[[:space:]]+/.*$|\1|p' )" || unset tmp_dir_free_space if [[ "${tmp_dir_free_space-notset}" == "notset" ]] || ( [[ -n "$tmp_dir_free_space" ]] && !((tmp_dir_free_space)) ); then tmp_dir_free_space='0' stage_end_warn "Can't determinate" else ((tmp_dir_free_space*=512)) if ((tmp_dir_free_space < OSX_inst_img_rw_size)); then stage_end_warn "$tmp_dir_free_space ($((tmp_dir_free_space/(1024*1024))) MiB), image creation may fail" else stage_end_ok "$tmp_dir_free_space ($((tmp_dir_free_space/(1024*1024))) MiB)" fi fi stage_start "Checking for super user rights" unset have_su_rights use_sudo sudo_prf || exit_with_error "Can't unset variables" if [[ `id -u` != '0' ]]; then have_su_rights='no' else have_su_rights='yes' fi if [[ "$have_su_rights" == "yes" ]] || [[ "$allow_sudo" != "yes" ]]; then use_sudo='no' sudo_prf='' else use_sudo='yes' sudo_prf='sudo' fi if [[ "$have_su_rights" == "yes" ]]; then stage_end_ok 'Owned' else stage_end_warn "Not owned" fi stage_start "Choosing creation method" if [[ -n "$cr_method" ]]; then stage_end_ok "Method ${cr_method#method}, specified on command line" if [[ "$cr_method" != "method3" ]] && [[ "$have_su_rights" != "yes" ]] && [[ "$allow_sudo" != "yes" ]]; then echo_warning "Resulting image probably will be unbootable as method ${cr_method#method} require super user rights and sudo was disabled by command line" fi elif [[ "$have_su_rights" != 'yes' ]]; then cr_method="method3" stage_end_ok "Method 3 as safest without super user right" elif ((tmp_dir_free_space < OSX_inst_img_rw_size*3)); then cr_method="method1" stage_end_ok "Method 1 due to limited disk space" else cr_method="method2" stage_end_ok "Method 2" fi unset img_bootable || exit_with_error if [[ "$cr_method" == "method1" ]] || [[ "$cr_method" == "method2" ]]; then if [[ "$cr_method" == "method1" ]]; then stage_start_nl "Converting BaseSystem.dmg to writable image" OSX_inst_img_rw="$tmp_dir/OS_X_Install.sparsebundle" hdiutil convert "$OSX_inst_base_dmg" -format UDSB -o "$OSX_inst_img_rw" -pmap || exit_with_error "Can't convert to writable image" stage_end_ok "Converting succeed" elif [[ "$cr_method" == "method2" ]]; then stage_start_nl "Creating installation image from BaseSystem.dmg" OSX_inst_img_dmg_tmp="$tmp_dir/OS_X_Install.dmg" || exit_with_error hdiutil create "${OSX_inst_img_dmg_tmp}" -srcdevice "$OSX_inst_base_dmg" -layout ISOCD || exit_with_error "Can't create writable image" stage_end_ok "Creating succeed" stage_start_nl "Converting installation image to writeable format" OSX_inst_img_rw="$tmp_dir/OS_X_Install.sparsebundle" hdiutil convert "$OSX_inst_img_dmg_tmp" -format UDSB -o "$OSX_inst_img_rw" -pmap || exit_with_error "Can't convert to writable image" rm -f "$OSX_inst_img_dmg_tmp" stage_end_ok "Converting succeed" fi stage_start "Resizing writable image" hdiutil resize -size "$OSX_inst_img_rw_size" "$OSX_inst_img_rw" -nofinalgap || exit_with_error "Can't resize writable image" stage_end_ok "Resizing succeed" stage_start_nl "Mounting writable image" OSX_inst_img_rw_mnt="$tmp_dir/OS_X_Install_img_rw_mnt" hdiutil attach "$OSX_inst_img_rw" -readwrite -nobrowse -mountpoint "$OSX_inst_img_rw_mnt" ${ver_opt+-noverify} || exit_with_error "Can't mount writable image" stage_end_ok "Mounting succeed" elif [[ "$cr_method" == "method3" ]]; then stage_start_nl "Creating blank writable image" OSX_inst_img_rw="$tmp_dir/OS_X_Install.sparsebundle" OSX_inst_img_rw_tmp_name="$OSX_inst_prt_name" || exit_with_error hdiutil create -size "$OSX_inst_img_rw_size" "$OSX_inst_img_rw" -type SPARSEBUNDLE -fs HFS+ -layout ISOCD -volname "$OSX_inst_img_rw_tmp_name" || exit_with_error "Can't create writable image" stage_end_ok "Creating succeed" stage_start_nl "Mounting writable image" OSX_inst_img_rw_mnt="$tmp_dir/OS_X_Install_img_rw_mnt" hdiutil attach "$OSX_inst_img_rw" -readwrite -nobrowse -mountpoint "$OSX_inst_img_rw_mnt" ${ver_opt+-noverify} || exit_with_error "Can't mount writable image" stage_end_ok "Mounting succeed" stage_start "Detecting mounted image device node" OSX_inst_img_rw_dev=`diskutil info -plist "$OSX_inst_img_rw_mnt" | sed -n -e '\|DeviceIdentifier| { N; s|^.*\(.\{1,\}\).*$|/dev/\1|p; q; }'` && \ [[ -n "$OSX_inst_img_rw_dev" ]] || exit_with_error "Can't find device node" stage_end_ok "$OSX_inst_img_rw_dev" stage_start_nl "Restoring BaseSystem.dmg to writable image" asr restore --source "$OSX_inst_base_dmg" --target "$OSX_inst_img_rw_dev" --erase --noprompt $ver_opt --buffers 1 --buffersize 64m || exit_with_error "Can't restore BaseSystem.dmg to writable image" unset OSX_inst_img_rw_mnt || exit_with_error # OSX_inst_img_rw_mnt is no valid anymore as image was remounted to different mountpoint img_bootable='yes' stage_end_ok "Restoring succeed" stage_start "Detecting re-mounted image volume name" unset OSX_inst_img_rw_volname || exit_with_error OSX_inst_img_rw_volname=`diskutil info -plist "$OSX_inst_img_rw_dev" | sed -n -e '\|VolumeName| { N; s|^.*\(.\{1,\}\).*$|\1|p; q; }'` || unset OSX_inst_img_rw_folname if [[ -z "$OSX_inst_img_rw_volname" ]]; then stage_end_warn "can't detect" else osascript -e "Tell application \"Finder\" to close the window \"$OSX_inst_img_rw_volname\"" &>/dev/null stage_end_ok "$OSX_inst_img_rw_volname" fi stage_start_nl "Remounting writable image to predefined mointpoint" hdiutil detach "$OSX_inst_img_rw_dev" -force || exit_with_error "Can't unmount image" unset OSX_inst_img_rw_dev OSX_inst_img_rw_mnt="$tmp_dir/OS_X_Install_img_rw_mnt" hdiutil attach "$OSX_inst_img_rw" -readwrite -nobrowse -mountpoint "$OSX_inst_img_rw_mnt" ${ver_opt+-noverify} || exit_with_error "Can't mount writable image" stage_end_ok "Remounting succeed" else exit_with_error "Unknown creation method" fi stage_start "Detecting macOS version on image" unset OSX_inst_ver || exit_with_error "Can't unset variable" OSX_inst_img_rw_ver_file="$OSX_inst_img_rw_mnt/System/Library/CoreServices/SystemVersion.plist" || exit_with_error "Can't set variable" OSX_inst_ver=`sed -n -e '\|ProductUserVisibleVersion| { N; s|^.*\(.\{1,\}\).*$|\1|p; q; }' "$OSX_inst_img_rw_ver_file"` || unset OSX_inst_ver if [[ -z "$OSX_inst_ver" ]]; then stage_end_warn "not detected" else stage_end_ok "$OSX_inst_ver" fi [[ "$OSX_inst_ver" =~ ^10.11($|.[1-4]$)|^10.12($|.[1-5]$) ]] || \ echo_warning "Warning! This script is tested only with images of macOS versions 10.11.0-10.11.4 and 10.12.0-10.12.5. Use with your own risk!" stage_start_nl "Renaming partition on writeable image" if ! diskutil rename "$OSX_inst_img_rw_mnt" "$OSX_inst_prt_name"; then stage_end_warn "Partition was not renamed" else unset OSX_inst_img_rw_volname stage_end_ok "Renamed to \"$OSX_inst_prt_name\"" fi stage_start "Copying BaseSystem.dmg to writeable image" #rsync -aIWEh --cache --progress "$OSX_inst_base_dmg" "$OSX_inst_img_rw_mnt/" || exit_with_error "Copying BaseSystem.dmg failed" cp -p "$OSX_inst_base_dmg" "$OSX_inst_img_rw_mnt/" || exit_with_error "Copying BaseSystem.dmg failed" cp -p "${OSX_inst_base_dmg%.dmg}.chunklist" "$OSX_inst_img_rw_mnt/" || exit_with_error "Copying BaseSystem.chunklist failed" stage_end_ok stage_start "Replacing Packages symlink with real files" rm -f "$OSX_inst_img_rw_mnt/System/Installation/Packages" || exit_with_error "Deleting Packages symlink failed" cp -pPR "$OSX_inst_inst_dmg_mnt/Packages" "$OSX_inst_img_rw_mnt/System/Installation/" || exit_with_error "Copying Packages failed" stage_end_ok stage_start "Configuring image as bootable" OSX_inst_img_rw_CoreSrv="$OSX_inst_img_rw_mnt/System/Library/CoreServices" || exit_with_error if bless --folder "$OSX_inst_img_rw_CoreSrv" \ --file "$OSX_inst_img_rw_CoreSrv/boot.efi" --openfolder "$OSX_inst_img_rw_mnt" --label "Install $OSX_inst_name"; then stage_end_ok else stage_end_warn "Failed, image may not be bootable" fi stage_start_nl "Unmounting InstallESD.dmg" hdiutil detach "$OSX_inst_inst_dmg_mnt" -force || exit_with_error "Can't unmount InstallESD.dmg" unset OSX_inst_img_rw_dev stage_end_ok "Unmointing succeed" stage_start_nl "Unmounting writable images" hdiutil detach "$OSX_inst_img_rw_mnt" -force || exit_with_error "Can't unmount writable image" unset OSX_inst_img_rw_dev stage_end_ok "Unmointing succeed" insert_version_into_name() { local name="$1" local version="$2" [[ -z "$name" ]] && return 1 [[ -z "$version" ]] && { echo "$name"; return 0; } local result local ins_aft if [[ "$name" =~ (^|[[:space:]])"OS X"($|[[:space:]]) ]]; then ins_aft="OS X" elif [[ "$name" =~ (^|[[:space:]])"MacOS X"($|[[:space:]]) ]]; then ins_aft="MacOS X" elif [[ "$name" =~ (^|[[:space:]])"macOS"($|[[:space:]]) ]]; then ins_aft="macOS" fi if [[ -n "$ins_aft" ]]; then result=$(echo -n "$name" | sed -n -e 's|^\(.*[[:<:]]'"$ins_aft"'[[:>:]]\).*$|\1|p') || return 2 [[ -z "$result" ]] && return 2 result+=" $version" # allow any regex/special symbols in $version result+=$(echo -n "$name" | sed -n -e 's|^.*[[:<:]]'"$ins_aft"'[[:>:]]\(.*\)$|\1|p') || return 2 else result="$name (macOS $version)" fi [[ -z "$result" ]] && return 1 echo "$result" return 0 } stage_start "Checking for output directory and image name" unset iso_name out_dir test_name || exit_with_error if [[ -z "$cmd_par_iso" ]]; then iso_name="$(insert_version_into_name "$OSX_inst_name" "$OSX_inst_ver")" || exit_with_error "Script internal error" iso_name="Install_${iso_name// /_}.iso" if [[ -z "$work_dir" ]] || [[ ! -w "$work_dir/" ]]; then [[ -n "$HOME" ]] && out_dir="$HOME/Desktop" # use Desktop as fallback if [[ -z "$out_dir" ]] || [[ ! -w "$out_dir/" ]]; then # use script location directory as fallback script_path="$(dirname "${BASH_SOURCE[0]}" 2>/dev/null)" [[ -n "$script_path" ]] || script_path="${0%/*}" [[ -n "$script_path" ]] && out_dir="$(cd "$script_path"2 2>/dev/null && pwd)" fi [[ -n "$out_dir" ]] && [[ -w "$out_dir/" ]] || out_dir="${0%/*}" [[ -n "$out_dir" ]] && [[ -w "$out_dir/" ]] || exit_with_error "Can't find writable output directory" stage_end_warn "Directory \"$work_dir\" seems to be unwritable, \"$out_dir/$iso_name\" will be used for output" else out_dir="$work_dir" stage_end_ok "$work_dir/$iso_name" fi else test_name="${cmd_par_iso}" [[ "${test_name:0:1}" == "/" ]] || test_name="$work_dir/$test_name" if [[ -d "$test_name" ]] || [[ "${test_name%/}" != "${test_name}" ]]; then # cmd_par_iso is output directory without filename out_dir="${cmd_par_iso%/}" else iso_name="${cmd_par_iso##*/}" if [[ "$iso_name" == "$cmd_par_iso" ]]; then out_dir="$work_dir" else out_dir="${cmd_par_iso%/*}" fi fi if [[ -z "$iso_name" ]]; then iso_name="$(insert_version_into_name "$OSX_inst_name" "$OSX_inst_ver")" || exit_with_error "Script internal error" iso_name="Install_${OSX_inst_name// /_}.iso" fi iso_name="${iso_name%.iso}.iso" [[ "${out_dir:0:1}" == "/" ]] || [[ -z "$out_dir" ]] || out_dir="$work_dir/${out_dir}" # relative path [[ -d "$out_dir/" ]] || mkdir "$out_dir/" || exit_with_error "Can't create specified output directory." unset test_name || exit_with_error test_name="$(cd "$out_dir/" 2>/dev/null && pwd)" [[ -n "$test_name" ]] && out_dir="$test_name" # replace with absolute path if possible stage_end_ok "specified on command line: \"$out_dir/$iso_name\"" fi stage_start_nl "Converting writeable image to .iso" unset iso_created || exit_with_error OSX_inst_result_image_ro="$out_dir/$iso_name" || exit_with_error OSX_inst_result_flag="$tmp_dir/output_image_is_ready" || exit_with_error rm -f "$OSX_inst_result_flag" || exit_with_error [[ -e "$OSX_inst_result_image_ro" ]] && exit_with_error "\"$OSX_inst_result_image_ro\" already exist" makehybrid_errout="$tmp_dir/hdiutil_makehybrid_erroutput" || exit_with_error { { hdiutil makehybrid -o "$OSX_inst_result_image_ro" "$OSX_inst_img_rw" -hfs -udf -default-volume-name "$OSX_inst_prt_name" 2>&1 1>&3 && \ touch "$OSX_inst_result_flag"; } | tee "$makehybrid_errout"; } 3>&1 1>&2 # output stderr to stderr and save it to file at the same time if ! [[ -e "$OSX_inst_result_flag" ]]; then if fgrep -Fiqs -e 'Operation not permitted' "$makehybrid_errout" && [[ "$have_su_rights" != "yes" ]]; then echo_warning "Creation of optimal .iso image failed without super user rights." if [[ "$allow_sudo" == "yes" ]]; then rm -f "$OSX_inst_result_image_ro" echo_warning "Next command will be executed with sudo, you may be asked for password." $sudo_prf hdiutil makehybrid -o "$OSX_inst_result_image_ro" "$OSX_inst_img_rw" -hfs -udf -default-volume-name "$OSX_inst_prt_name" && touch "$OSX_inst_result_flag" else echo_warning "Usage of sudo was disabled by command parameter" fi fi fi if [[ -e "$OSX_inst_result_flag" ]]; then img_bootable='yes' stage_end_ok "Converting succeed" else rm -f "$OSX_inst_result_image_ro" stage_end_warn "Creation of optimal .iso was failed, will try to use workarounds to build usable .iso" [[ "$img_bootable" != 'yes' ]] && echo_warning "Resulting image may not be bootable" stage_start "Shrinking image" if hdiutil resize -sectors min "$OSX_inst_img_rw" -nofinalgap; then stage_end_ok "succeed" else stage_end_warn "failed, image remains larger than required" fi stage_start_nl "Converting image to .iso-like format" OSX_inst_result_tmp_image="${OSX_inst_result_image_ro%.iso}.cdr" || exit_with_error [[ -e "$OSX_inst_result_tmp_image" ]] && OSX_inst_result_tmp_image="$tmp_dir/tmp_cdr_img.cdr" hdiutil convert "$OSX_inst_img_rw" -format UDTO -o "$OSX_inst_result_tmp_image" && \ mv -vn "$OSX_inst_result_tmp_image" "$OSX_inst_result_image_ro" && iso_created='yes' if [[ "$iso_created" != "yes" ]]; then rm -f "$OSX_inst_result_tmp_image" rm -f "$OSX_inst_result_image_ro" exit_with_error "Image converting failed" fi stage_end_ok "Converting succeed" fi echo_enh " Resulting .iso location:" echo "$OSX_inst_result_image_ro " [[ "$img_bootable" != 'yes' ]] && echo_warning "Resulting .iso may not be bootable"