postinstall (5360B)
1 #!/bin/zsh 2 setopt no_unset warn_create_global extended_glob 3 4 # error handling 5 typeset -ga revert 6 7 die_ret() { 8 local ret step 9 ret=$1 10 shift 11 printf >&2 '%s\n' "$@" 12 for step in $revert; do 13 printf >&2 '* Running revert step: %s\n' $step 14 $step 15 done 16 exit $ret 17 } 18 die() { 19 die_ret 1 "$@" 20 } 21 die100() { # 100: wrong usage 22 die_ret 100 "$@" 23 } 24 die111() { # 111: system call failed 25 die_ret 111 "$@" 26 } 27 -() { 28 "$@" || die_ret $? "Command failed: $*" 29 } 30 fatal100() { 31 die_ret 100 "Fatal: ${(qqq)this_command:t}: $@" 32 } 33 fatal111() { 34 die_ret 111 "Fatal: ${(qqq)this_command:t}: $@" 35 } 36 37 # modules 38 - zmodload -F zsh/stat b:zstat 39 - zmodload -m -F zsh/files b:zf_\* 40 - zmodload zsh/datetime # for $EPOCHREALTIME 41 42 # functions 43 link_changed() { 44 local prev curr 45 prev=${${:-$prev_env/$1}:P} 46 curr=${${:-$current_env/$1}:P} 47 [[ "$prev" != "$curr" ]] 48 } 49 50 setup_rc() { 51 local diff_ret prev_source curr_source 52 prev_source=$prev_env/config/s6-rc-source 53 curr_source=./config/s6-rc-source 54 curr_db=./config/s6-rc-db 55 # Check if s6-rc definition changed 56 diff -r -q $prev_source $curr_source; diff_ret=$? 57 (( $diff_ret == 0 || $diff_ret == 1 )) || \ 58 die111 "Could not diff s6-rc-source directories; exitcode $diff_ret" 59 if link_changed command/s6-rc; then 60 if (( $diff_ret == 1 )); then 61 # Both s6-rc DB source and installed software changed. 62 # s6-rc-format-upgrade to tmpdir, then s6-rc-update 63 local tmp_db=/run/old-s6-rc-db-migration.$EPOCHREALTIME 64 65 s6-rc-compile $tmp_db $prev_source || return $? 66 s6-rc-format-upgrade -v2 $tmp_db || return $? 67 s6-rc-update -v2 $curr_db:P || return $? 68 zf_rm -r $tmp_db || return $? 69 else 70 # Installed software changed but s6-rc DB source is the same. 71 # s6-rc-format-upgrade to new compiled DB directly 72 s6-rc-format-upgrade -v2 $curr_db:P || return $? 73 fi 74 elif (( $diff_ret == 1 )); then 75 # s6-rc DB source changed while keeping same version of software. 76 # s6-rc-update to new compiled DB directly 77 s6-rc-update -v2 $curr_db:P || return $? 78 fi 79 s6-rc -v2 -u -t 30000 change ok-all 80 true 81 } 82 83 setup_containers() { 84 # Check if we need to regenerate containers or their service directories. 85 if link_changed bzr/containers || link_changed bzr/confz; then 86 if (( $+confz_verbose )); then 87 zsh -lc "verbose=1 confz site_containers" </dev/null 2>&1 | cat -v 88 ret=$((${(j.|.)pipestatus})) # Nonzero iff any of commands in pipeline returned nonzero. 89 else 90 zsh -lc "quiet=1 confz site_containers" </dev/null 2>&1 | cat -v 91 ret=$((${(j.|.)pipestatus})) # Nonzero iff any of commands in pipeline returned nonzero. 92 fi 93 if (($ret)); then 94 echo >&2 "Error: command failed ($ret): confz site_containers" 95 return $ret 96 fi 97 s6-svscanctl -a /run/service || return $? 98 fi 99 } 100 101 setup_fileset() { 102 local -a rsync=( 103 rsync 104 -a # TODO compile rsync with ACL support 105 --delete 106 --log-format=$'%i\t%B\t%U:%G\t%M\t%l\t%n' 107 --filter="merge config/postinstall.rsfilter" 108 --filter='- *' 109 ) 110 $rsync --delete-excluded --log-file $SETUP_DIR/rsync.log.get / $SETUP_DIR/files.pre/ || return $? 111 cp -a --reflink=auto $SETUP_DIR/files.pre $SETUP_DIR/files.post || return $? 112 ./command/fileset ./config/postinstall.fileset >$SETUP_DIR/files.sh || exit $? 113 (cd $SETUP_DIR/files.post && exec sh ../files.sh) || exit $? 114 zf_mkdir $SETUP_DIR/files.bak || return $? 115 revert+=( revert_fileset ) 116 $rsync --log-file $SETUP_DIR/rsync.log.put $SETUP_DIR/files.post/ / --backup --backup-dir=$SETUP_DIR/files.bak || return $? 117 } 118 119 revert_fileset() { 120 rsync -a --log-format=$'%i\t%B\t%U:%G\t%M\t%l\t%n' --log-file $SETUP_DIR/rsync.log.revert $SETUP_DIR/files.bak/ / 121 } 122 123 setup_containers() { 124 execlineb -P ./config/s6-rc-source/containers/up || return $? 125 } 126 127 # main function 128 postinstall() { 129 - cd $current 130 typeset -g SETUP_DIR 131 if (( $# )); then 132 SETUP_DIR=$versions/postinstall/$EPOCHSECONDS.${current_env:t}..${prev_env:t} 133 else 134 SETUP_DIR=$versions/postinstall/$EPOCHSECONDS.${current_env:t} 135 fi 136 - zf_mkdir -p $SETUP_DIR 137 138 - setup_fileset 139 140 if (( $# )); then 141 - setup_rc 142 - setup_containers 143 fi 144 exit 0 145 } 146 typeset -ft postinstall 147 148 typeset -g versions current 149 current=/run/current 150 versions=/versions 151 152 typeset -g this_command this_conf current_command current_env current_conf 153 this_command=$0 154 this_conf=$0:P:h:h 155 current_command=$current/command/install-as-current-environment.postinstall 156 current_env=$current_command:h:P:h 157 current_conf=$current_command:P:h:h 158 159 # arguments and validation 160 if (( $# > 1 )); then 161 fatal100 "Too many arguments" 162 fi 163 if [[ $0:P != $versions/* ]]; then 164 fatal100 "This script expects to be installed under ${(qqq)versions}." 165 fi 166 this_command=$current/command/install-as-current-environment.postinstall 167 if [[ $0:P != $current_command:P ]]; then 168 fatal111 "Fatal: This script needs to be run after installing the given environment as ${(qqq)current}." 169 fi 170 if (( $# )); then 171 typeset -g prev_command prev_env prev_conf 172 prev_command=$1/command/install-as-current-environment.postinstall 173 prev_env=$1:P 174 prev_conf=$prev_command:P:h:h 175 if [[ $prev_env != $versions/* ]]; then 176 fatal111 "Old version doesn't seem to be inside ${(qqq)versions}: ${(qqq)prev_env}." 177 fi 178 if ! [[ $prev_env:t == env.* ]]; then 179 fatal111 "Unexpected previous environment name: ${(qqq)prev_env}" 180 fi 181 fi 182 if ! [[ $current_env:t == env.* ]]; then 183 fatal111 "Unexpected current environment name: ${(qqq)current_env}" 184 fi 185 186 - postinstall "$@"