postinstall (5526B)
1 #!/bin/zsh 2 setopt no_unset warn_create_global extended_glob 3 zmodload -F zsh/stat b:zstat || exit $? 4 zmodload -m -F zsh/files b:zf_\* || exit $? 5 #zmodload zsh/zutil || exit $? # for zparseopts 6 zmodload zsh/datetime || exit $? # for $EPOCHREALTIME 7 8 die_ret() { 9 local ret 10 ret=$1 11 shift 12 printf >&2 '%s\n' "$@" 13 exit $ret 14 } 15 die() { 16 die_ret 1 "$@" 17 } 18 die100() { # 100: wrong usage 19 die_ret 100 "$@" 20 } 21 die111() { # 111: system call failed 22 die_ret 111 "$@" 23 } 24 25 ensure_symlink() { 26 local target 27 if ! [[ -e $1 ]]; then 28 s6-ln -s $2 $1 || return $? 29 fi 30 31 if [[ $2 == /* ]]; then 32 target=$2:A 33 else 34 target=$1:h/$2 35 target=$target:A 36 fi 37 38 if ! [[ -h $1 ]]; then 39 echo >&2 "Error: not a symlink: ${(qqq)1}" 40 return 1 41 elif [[ $1:A != $target ]]; then 42 echo >&2 "Error: ${(qqq)1} points to ${(qqq)1:A} instead of ${(qqq)target}" 43 return 1 44 fi 45 } 46 47 symlink_static_file() { 48 [[ $1 == /* ]] || die "symlink_static_file: requires absolute path" 49 local relative_base up rel1 rel2 50 rel1=./conf/static$1 51 [[ -f $rel1 ]] || die111 "Cannot symlink: file does not exist: ${(qqq)rel1}" 52 relative_base=$1:h 53 until [[ ${${:-$relative_base/$up}:P} == / ]] ; do 54 up=../$up 55 done 56 rel2=$relative_base/$up/current/conf/static$1 57 [[ $rel1:P == $rel2:P ]] || die "Directory mismatch" 58 59 if [[ ! -L $1 && -f $1 ]]; then 60 mv $1 $1.orig.$EPOCHSECONDS || exit $? 61 fi 62 ensure_symlink $1 ${up}current/conf/static$1 || return $? 63 } 64 65 link_changed() { 66 local pre post 67 if (($+preinstall_current)); then 68 pre=${${:-$preinstall_current_p/$1}:P} 69 else 70 pre= 71 fi 72 post=${${:-/current/$1}:P} 73 [[ "$pre" != "$post" ]] 74 } 75 76 setup_static_symlinks() { 77 symlink_static_file /etc/hostname || return $? 78 symlink_static_file /etc/fstab || return $? 79 symlink_static_file /etc/profile.d/slashcommand.sh || return $? 80 symlink_static_file /etc/mkinitfs/mkinitfs.conf || return $? 81 symlink_static_file /etc/ssh/sshd_config || return $? 82 symlink_static_file /etc/update-extlinux.conf || return $? 83 symlink_static_file /etc/zsh/zshrc.d/90_warn_deploy_ssh_key.zsh || return $? 84 85 # Not static, generated in ./install 86 if [[ ! -L /etc/motd && -f /etc/motd ]]; then 87 mv /etc/motd /etc/motd.orig.$EPOCHSECONDS || exit $? 88 fi 89 ensure_symlink /etc/motd ../current/motd || return $? 90 } 91 92 setup_skel() { 93 ./command/link-skel || return $? 94 } 95 96 setup_storage() { 97 } 98 99 setup_rc() { 100 local diff_ret 101 # Check if s6-rc definition changed 102 diff --recursive --unified $preinstall_current_p/s6-rc-source ./s6-rc-source; diff_ret=$? 103 (( $diff_ret == 0 || $diff_ret == 1 )) || \ 104 die111 "Could not diff s6-rc-source directories; exitcode $diff_ret" 105 if link_changed package; then 106 if (( $diff_ret == 1 )); then 107 # Both s6-rc DB source and installed software changed. 108 # s6-rc-format-upgrade to tmpdir, then s6-rc-update 109 local tmp_db=/run/old-s6-rc-db-migration.$EPOCHREALTIME 110 111 s6-rc-compile $tmp_db $preinstall_current_p/s6-rc-source || return $? 112 s6-rc-format-upgrade -v2 $tmp_db || return $? 113 s6-rc-update -v2 /current/s6-rc-db/ || return $? 114 rm -r $tmp_db || return $? 115 else 116 # Installed software changed but s6-rc DB source is the same. 117 # s6-rc-format-upgrade to new compiled DB directly 118 s6-rc-format-upgrade -v2 /current/s6-rc-db/ || return $? 119 fi 120 elif (( $diff_ret == 1 )); then 121 # s6-rc DB source changed while keeping same version of software. 122 # s6-rc-update to new compiled DB directly 123 s6-rc-update -v2 /current/s6-rc-db/ || return $? 124 fi 125 } 126 127 setup_containers() { 128 # Check if we need to regenerate containers or their service directories. 129 if link_changed bzr/containers || link_changed bzr/confz; then 130 if (( $+confz_verbose )); then 131 zsh -lc "verbose=1 confz site_containers" </dev/null 2>&1 | cat -v 132 ret=$((${(j.|.)pipestatus})) # Nonzero iff any of commands in pipeline returned nonzero. 133 else 134 zsh -lc "quiet=1 confz site_containers" </dev/null 2>&1 | cat -v 135 ret=$((${(j.|.)pipestatus})) # Nonzero iff any of commands in pipeline returned nonzero. 136 fi 137 if (($ret)); then 138 echo >&2 "Error: command failed ($ret): confz site_containers" 139 return $ret 140 fi 141 s6-svscanctl -a /run/service || return $? 142 fi 143 } 144 145 setup_fileset() { 146 local -a rsync=( 147 rsync 148 -aA 149 --delete 150 --log-format=$'%i\t%B\t%U:%G\t%M\t%l\t%n' 151 --filter='merge conf/postinstall.rsfilter' 152 --filter='- *' 153 ) 154 $rsync --delete-excluded --log-file $SETUP_DIR/rsync.log.get / $SETUP_DIR/files.pre/ || return $? 155 cp -a --reflink=auto $SETUP_DIR/files.pre $SETUP_DIR/files.post || return $? 156 ./command/fsapply $SETUP_DIR/files.post $PWD/conf/postinstall.fileset || exit $? 157 mkdir $SETUP_DIR/files.bak || return $? 158 $rsync --log-file $SETUP_DIR/rsync.log.put $SETUP_DIR/files.post/ / --backup --backup-dir=$SETUP_DIR/files.bak || return $? 159 } 160 161 postinstall() { 162 typeset -g SETUP_DIR=/versions/postinstall/$EPOCHSECONDS.$ALL_DIR:t 163 cd $ALL_DIR || exit $? 164 mkdir -p $SETUP_DIR 165 166 ensure_symlink /command current/command || return $? 167 168 setup_static_symlinks || return $? 169 170 if [[ -d /run/s6-rc/ ]]; then 171 # TODO: determine mountpoint changes 172 setup_storage || return $? 173 mount -a || return $? 174 fi 175 176 setup_fileset || return $? 177 178 if [[ -d /run/s6-rc/ ]]; then 179 setup_rc || return $? 180 fi 181 182 setup_skel || return $? 183 setup_containers || return $? 184 185 exit 0 186 } 187 typeset -ft postinstall 188 189 typeset -g ALL_DIR=$0:h:h 190 if [[ $ALL_DIR != /versions/all.* ]]; then 191 die100 "Fatal: ${(qqq)0}: This script needs to be run from versioned directory as a part of installation procedure." 192 fi 193 194 path=( $ALL_DIR/command "$path[@]" ) 195 #fpath=( $ALL_DIR/zsh-functions "$fpath[@]" ) 196 postinstall || exit $?