| 1 | ### -*-makefile-*- |
| 2 | ### |
| 3 | ### Main maintenance script for chroots |
| 4 | ### |
| 5 | ### (c) 2018 Mark Wooding |
| 6 | ### |
| 7 | |
| 8 | ###----- Licensing notice --------------------------------------------------- |
| 9 | ### |
| 10 | ### This file is part of the distorted.org.uk chroot maintenance tools. |
| 11 | ### |
| 12 | ### distorted-chroot is free software: you can redistribute it and/or |
| 13 | ### modify it under the terms of the GNU General Public License as |
| 14 | ### published by the Free Software Foundation; either version 2 of the |
| 15 | ### License, or (at your option) any later version. |
| 16 | ### |
| 17 | ### distorted-chroot is distributed in the hope that it will be useful, |
| 18 | ### but WITHOUT ANY WARRANTY; without even the implied warranty of |
| 19 | ### MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU |
| 20 | ### General Public License for more details. |
| 21 | ### |
| 22 | ### You should have received a copy of the GNU General Public License |
| 23 | ### along with distorted-chroot. If not, write to the Free Software |
| 24 | ### Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, |
| 25 | ### USA. |
| 26 | |
| 27 | all:: |
| 28 | clean:: |
| 29 | .PHONY: all clean |
| 30 | .SECONDEXPANSION: #sorry |
| 31 | |
| 32 | ###-------------------------------------------------------------------------- |
| 33 | ### Configuration. |
| 34 | |
| 35 | CONFIG_VARS = |
| 36 | |
| 37 | ## Volume group from which to allocate chroot volumes and snapshots. |
| 38 | CONFIG_VARS += VG LVPREFIX |
| 39 | VG = vg-$(shell hostname) |
| 40 | LVPREFIX = |
| 41 | |
| 42 | ## Logical volume size, as an LVM option. |
| 43 | CONFIG_VARS += LVSZ |
| 44 | LVSZ = -L8G |
| 45 | |
| 46 | ## Debian mirror. |
| 47 | CONFIG_VARS += DEBMIRROR |
| 48 | DEBMIRROR = http://deb.debian.org/debian/ |
| 49 | |
| 50 | ## APT sources configurations. (Also, $($d_APTSRC) for each $d in $(DISTS).) |
| 51 | CONFIG_VARS += APTSRC |
| 52 | APTSRC = etc/aptsrc.conf $(wildcard etc/aptsrc.local.conf) |
| 53 | |
| 54 | ## APT configuration fragment names. These will be linked into |
| 55 | ## `/etc/apt/apt.conf.d' in each chroot. To put a fragment f in a surprising |
| 56 | ## place, set $($f_APTCONFSRC). |
| 57 | CONFIG_VARS += APTCONF |
| 58 | APTCONF_DIR = etc/apt-conf.d |
| 59 | APTCONF = $(notdir $(wildcard $(APTCONF_DIR)/[0-9]*[!~])) |
| 60 | |
| 61 | ## Proxy setting. |
| 62 | CONFIG_VARS += PROXY |
| 63 | PROXY := $(shell \ |
| 64 | eval $$(apt-config $(foreach a,$(APTCONF), -c$(APTCONF_DIR)/$a) \ |
| 65 | shell proxy Acquire::http::proxy); \ |
| 66 | case $${proxy+t} in (t) echo "$$proxy" ;; (*) echo nil ;; esac) |
| 67 | |
| 68 | ## Debian distributions to support. |
| 69 | CONFIG_VARS += PRIMARY_DIST DISTS |
| 70 | PRIMARY_DIST = stretch |
| 71 | DISTS = $(PRIMARY_DIST) buster bullseye sid |
| 72 | |
| 73 | ## Host's native architecture(s). |
| 74 | CONFIG_VARS += MYARCH NATIVE_ARCHS |
| 75 | MYARCH = $(shell dpkg --print-architecture) |
| 76 | OTHERARCHS = $(shell dpkg --print-foreign-architectures) |
| 77 | NATIVE_ARCHS = $(MYARCH) $(OTHERARCHS) |
| 78 | |
| 79 | ## Foreign (emulated) architectures to support. |
| 80 | CONFIG_VARS += FOREIGN_ARCHS |
| 81 | FOREIGN_ARCHS = |
| 82 | |
| 83 | ## Master lists of chroots to build and maintain. |
| 84 | NATIVE_CHROOTS = $(foreach a,$(NATIVE_ARCHS), \ |
| 85 | $(foreach d,$(or $($a_DISTS) $(DISTS)), \ |
| 86 | $d-$a)) |
| 87 | FOREIGN_CHROOTS = $(foreach a,$(FOREIGN_ARCHS), \ |
| 88 | $(foreach d,$(or $($a_DISTS) $(DISTS)), \ |
| 89 | $d-$a)) |
| 90 | |
| 91 | ## Which host architecture to use for foreign architectures. It turns out |
| 92 | ## that it's best to use a Qemu with the same host bitness as the target |
| 93 | ## architecture; otherwise it has to do a difficult job of converting |
| 94 | ## arguments and results between kernel ABI flavours. |
| 95 | 32BIT_QEMUHOST = $(or $(filter i386,$(NATIVE_ARCHS)),$(TOOLSARCH)) |
| 96 | 64BIT_QEMUHOST = $(or $(filter amd64,$(NATIVE_ARCHS)),$(TOOLSARCH)) |
| 97 | |
| 98 | CONFIG_VARS += $(foreach a,$(FOREIGN_ARCHS), $a_QEMUHOST) |
| 99 | armel_QEMUHOST = $(32BIT_QEMUHOST) |
| 100 | armhf_QEMUHOST = $(32BIT_QEMUHOST) |
| 101 | arm64_QEMUHOST = $(64BIT_QEMUHOST) |
| 102 | i386_QEMUHOST = $(32BIT_QEMUHOST) |
| 103 | amd64_QEMUHOST = $(64BIT_QEMUHOST) |
| 104 | |
| 105 | ## Qemu architecture names. These tell us which Qemu binary to use for a |
| 106 | ## particular Debian architecture. |
| 107 | CONFIG_VARS += $(foreach a,$(FOREIGN_ARCHS), $a_QEMUARCH) |
| 108 | armel_QEMUARCH = arm |
| 109 | armhf_QEMUARCH = arm |
| 110 | arm64_QEMUARCH = aarch64 |
| 111 | i386_QEMUARCH = i386 |
| 112 | amd64_QEMUARCH = x86_64 |
| 113 | |
| 114 | ## Alias mapping for chroots. |
| 115 | CONFIG_VARS += $(foreach d,$(DISTS), $d_ALIASES) |
| 116 | stretch_ALIASES = oldstable |
| 117 | buster_ALIASES = stable |
| 118 | bullseye_ALIASE = testing |
| 119 | sid_ALIASES = unstable |
| 120 | |
| 121 | ## Which host architecture to use for commonly used tools in foreign chroots. |
| 122 | CONFIG_VARS += TOOLSARCH |
| 123 | TOOLSARCH = $(MYARCH) |
| 124 | |
| 125 | ## A directory in which we can maintain private files and state. |
| 126 | CONFIG_VARS += STATE |
| 127 | STATE = state |
| 128 | |
| 129 | ## A directory which will be spliced into chroots as `/usr/local.schroot/'. |
| 130 | ## This will be our primary point of contact with the chroot. |
| 131 | CONFIG_VARS += LOCAL |
| 132 | LOCAL = local.schroot |
| 133 | |
| 134 | ## How to run a command as a privileged user. |
| 135 | ROOTLY = sudo |
| 136 | |
| 137 | ## Files to be copied into a chroot from the host. |
| 138 | SCHROOT_COPYFILES = /etc/resolv.conf |
| 139 | SCHROOT_NSSDATABASES = passwd shadow group gshadow |
| 140 | |
| 141 | ## Local configuration hook. |
| 142 | -include local.mk |
| 143 | |
| 144 | ## All chroot names. |
| 145 | CONFIG_VARS += ALL_CHROOTS |
| 146 | ALL_CHROOTS = $(NATIVE_CHROOTS) $(FOREIGN_CHROOTS) |
| 147 | |
| 148 | ###-------------------------------------------------------------------------- |
| 149 | ### Utilities. |
| 150 | |
| 151 | ## $(call chroot-dist,D-A) -> D |
| 152 | ## $(call chroot-arch,D-A) -> A |
| 153 | ## |
| 154 | ## Parse chroot descriptions. |
| 155 | chroot-dist = $(patsubst %/,%,$(dir $(subst -,/,$1))) |
| 156 | chroot-arch = $(notdir $(subst -,/,$1)) |
| 157 | |
| 158 | ## $(call native-chroot-p,D-A) -> D | <empty> |
| 159 | ## |
| 160 | ## Answer whether D-A is a native chroot. |
| 161 | native-chroot-p = $(filter $(call chroot-arch,$1), $(NATIVE_ARCHS)) |
| 162 | |
| 163 | ## $(call chroot-qemuhost,D-A) -> AA |
| 164 | ## |
| 165 | ## Answer the apporopriate Qemu host architecture for foreign chroot D-A. |
| 166 | chroot-qemuhost = $($(call chroot-arch,$1)_QEMUHOST) |
| 167 | |
| 168 | ## $(call chroot-deps,PRE,D-A) -> PRE/DD-AA ... | <empty> |
| 169 | ## |
| 170 | ## Answer a list of additional dependencies for the chroot D-A: specifically, |
| 171 | ## if D-A is foreign then include PRE/DD-AA entries for the tools |
| 172 | ## architecture, and Qemu host architecture (if that's different). |
| 173 | chroot-deps = $(if $(call native-chroot-p,$2),, \ |
| 174 | $(addprefix $1/$(call chroot-dist,$2)-,\ |
| 175 | $(sort $(call chroot-toolsarch,$2) \ |
| 176 | $(call chroot-qemuhost,$2)))) |
| 177 | |
| 178 | ## Substituting placeholders in files. |
| 179 | SUBSTITUTIONS := local=$(shell realpath $(LOCAL)) |
| 180 | SUBSTITUTIONS += primary-dist=$(PRIMARY_DIST) |
| 181 | subst-file = { \ |
| 182 | echo "$1 GENERATED by distorted-chroot: do not edit"; \ |
| 183 | substs=""; \ |
| 184 | for v in $(SUBSTITUTIONS); do \ |
| 185 | var=$${v%%=*} value=$${v\#*=}; \ |
| 186 | substs="$$substs s\a@$$var@\a$$value\ag;"; \ |
| 187 | done; \ |
| 188 | sed "$$substs"; \ |
| 189 | } |
| 190 | |
| 191 | ## Silent-rules machinery. |
| 192 | V = 0 |
| 193 | V_AT = $(V_AT_$V) |
| 194 | V_AT_0 = @ |
| 195 | v_print = $(call v_print_$V,$1,$2) |
| 196 | v_print_0 = printf " %-8s %s\n" "$1" "$2"; |
| 197 | v_tag = $(V_AT)$(call v_print,$1,$@) |
| 198 | v_log = $(call v_log_$V,$1) |
| 199 | v_log_ = $(call v_log_1,$1) |
| 200 | v_log_0 = >$1.log 2>&1 |
| 201 | v_log_1 = 2>&1 | tee $1.log |
| 202 | CLEANFILES += *.log |
| 203 | |
| 204 | ###-------------------------------------------------------------------------- |
| 205 | ### APT configuration. |
| 206 | |
| 207 | ## In a chroot, `/etc/apt/sources.list' links to |
| 208 | ## `/usr/local.schroot/etc/apt/sources.$d' for the appropriate distribution. |
| 209 | APT_SOURCES = $(foreach d,$(DISTS), $(LOCAL)/etc/apt/sources.$d) |
| 210 | CLEANFILES += $(APT_SOURCES) |
| 211 | all:: $(APT_SOURCES) |
| 212 | |
| 213 | $(foreach d,$(DISTS), $(STATE)/etc/apt/aptsrc.$d): $(STATE)/etc/apt/aptsrc.%: |
| 214 | $(V_AT)mkdir -p $(dir $@) |
| 215 | $(call v_tag,GEN){ \ |
| 216 | echo "### -*-conf-*- GENERATED by distorted-chroot: do not edit"; \ |
| 217 | echo "subscribe"; \ |
| 218 | echo " debian : $*"; \ |
| 219 | } >$@.new && mv $@.new $@ |
| 220 | |
| 221 | $(APT_SOURCES): $(LOCAL)/etc/apt/sources.%: \ |
| 222 | $$(APTSRC) $$($$*_APTSRC) $$(STATE)/etc/apt/aptsrc.$$* |
| 223 | $(V_AT)mkdir -p $(dir $@) |
| 224 | $(call v_tag,GEN)bin/mkaptsrc \ |
| 225 | $(APTSRC) $($*_APTSRC) $(STATE)/etc/apt/aptsrc.$* \ |
| 226 | >$@.new && mv $@.new $@ |
| 227 | |
| 228 | ## In a chroot, a link `/etc/apt/apt.conf.d/FOO' is created for each file in |
| 229 | ## `/usr/local.schroot/etc/apt/apt.conf.d/FOO'. |
| 230 | APT_CONFIGS = $(addprefix $(LOCAL)/etc/apt/apt.conf.d/,$(APTCONF)) |
| 231 | all:: $(APT_CONFIGS) |
| 232 | $(APT_CONFIGS): $(LOCAL)/etc/apt/apt.conf.d/%: \ |
| 233 | $$(or $$($$*_APTCONFSRC) $$(APTCONF_DIR)/$$*) |
| 234 | $(V_AT)mkdir -p $(dir $@) |
| 235 | $(call v_tag,COPY)cp $< $@.new && mv $@.new $@ |
| 236 | |
| 237 | ###-------------------------------------------------------------------------- |
| 238 | ### `schroot' and `sbuild' configuration. |
| 239 | |
| 240 | all:: schroot-config |
| 241 | schroot-config:: |
| 242 | .PHONY: schroot-config |
| 243 | |
| 244 | %print-varlist = { \ |
| 245 | echo "\#\#\# -*-sh-*- GENERATED by distorted-chroot: do not edit"; \ |
| 246 | $(foreach v,$1, echo $v=\''$(subst ','\'\\\'\'',$($v))'\';) \ |
| 247 | } #' |
| 248 | schroot-config_HASH := \ |
| 249 | $(shell $(call %print-varlist,$(CONFIG_VARS)) | \ |
| 250 | sha256sum | cut -c1-32) |
| 251 | schroot-config_FILE = $(STATE)/config.sh-$(schroot-config_HASH) |
| 252 | $(schroot-config_FILE): |
| 253 | $(V_AT)mkdir -p $(STATE) |
| 254 | $(V_AT)rm -f $(STATE)/config.sh-* |
| 255 | $(call v_tag,STAMP)$(call %print-varlist,$(CONFIG_VARS)) \ |
| 256 | >$@.new && mv $@.new $@ |
| 257 | |
| 258 | schroot-config:: $(STATE)/config.sh |
| 259 | $(STATE)/config.sh: $(schroot-config_FILE) |
| 260 | $(call v_tag,SYMLINK)ln -sf $(notdir $<) $@ |
| 261 | |
| 262 | schroot-config:: $(STATE)/etc/schroot/sbuild.schroot |
| 263 | $(STATE)/etc/schroot/sbuild.schroot: $(STATE)/config.sh bin/mkchrootconf |
| 264 | $(V_AT)mkdir -p $(dir $@) |
| 265 | $(call v_tag,GEN)bin/mkchrootconf >$@.new && mv $@.new $@ |
| 266 | |
| 267 | schroot-config:: $(STATE)/etc/schroot/sbuild.profile/copyfiles |
| 268 | $(STATE)/etc/schroot/sbuild.profile/copyfiles: $(schroot-config_STAMP) |
| 269 | $(V_AT)mkdir -p $(dir $@) |
| 270 | $(call v_tag,GEN){ \ |
| 271 | echo "### -*-conf-*- GENERATED by distorted-chroot: do not edit"; \ |
| 272 | for i in $(SCHROOT_COPYFILES); do echo "$$i"; done; \ |
| 273 | } >$@.new && mv $@.new $@ |
| 274 | |
| 275 | schroot-config:: $(STATE)/etc/schroot/sbuild.profile/nssdatabases |
| 276 | $(STATE)/etc/schroot/sbuild.profile/nssdatabases: $(schroot-config_STAMP) |
| 277 | $(V_AT)mkdir -p $(dir $@) |
| 278 | $(call v_tag,GEN){ \ |
| 279 | echo "### -*-conf-*- GENERATED by distorted-chroot: do not edit"; \ |
| 280 | for i in $(SCHROOT_NSSDATABASES); do echo "$$i"; done; \ |
| 281 | } >$@.new && mv $@.new $@ |
| 282 | |
| 283 | schroot-config:: $(STATE)/etc/schroot/sbuild.profile/fstab |
| 284 | $(STATE)/etc/schroot/sbuild.profile/fstab: \ |
| 285 | etc/sbuild.fstab.in $(schroot-config_STAMP) |
| 286 | $(V_AT)mkdir -p $(dir $@) |
| 287 | $(call v_tag,SUBST)$(call subst-file,### -*-conf-*-) \ |
| 288 | <$< >$@.new && mv $@.new $@ |
| 289 | |
| 290 | schroot-config:: $(STATE)/etc/sbuild.conf |
| 291 | $(STATE)/etc/sbuild.conf: etc/sbuild.conf.in $(schroot-config_STAMP) |
| 292 | $(V_AT)mkdir -p $(dir $@) |
| 293 | $(call v_tag,SUBST)$(call subst-file,### -*-perl-*-) \ |
| 294 | <$< >$@.new && mv $@.new $@ |
| 295 | |
| 296 | ###-------------------------------------------------------------------------- |
| 297 | ### Constructing chroots. |
| 298 | |
| 299 | BUILD_CHROOTS = $(addprefix chroot/,$(ALL_CHROOTS)) |
| 300 | CHROOT_STAMPS = $(addprefix $(STATE)/stamp/chroot.,$(ALL_CHROOTS)) |
| 301 | all:: setup-chroots |
| 302 | setup-chroots: $(BUILD_CHROOTS) |
| 303 | $(BUILD_CHROOTS): chroot/%: $(STATE)/stamp/chroot.% |
| 304 | .PHONY: setup-chroots $(BUILD_CHROOTS) |
| 305 | |
| 306 | $(CHROOT_STAMPS): $(STATE)/stamp/chroot.%: $(STATE)/config.sh bin/mkbuildchroot |
| 307 | $(call v_tag,CHROOT)bin/mkbuildchroot \ |
| 308 | $(call chroot-dist,$*) $(call chroot-arch,$*) \ |
| 309 | $(call v_log,setup-chroot.$*) |
| 310 | |
| 311 | ###-------------------------------------------------------------------------- |
| 312 | ### Installing basic custom software. |
| 313 | |
| 314 | |
| 315 | |
| 316 | ###-------------------------------------------------------------------------- |
| 317 | ### Other maintenance targets. |
| 318 | |
| 319 | show:; : $x |
| 320 | |
| 321 | clean:: |
| 322 | rm -f $(CLEANFILES) |
| 323 | rm -rf $(STATE) |
| 324 | |
| 325 | realclean:: clean |
| 326 | rm -rf $(LOCAL) |
| 327 | |
| 328 | ###----- That's all, folks -------------------------------------------------- |