@@ -98,7 +98,8 @@ display_help() {
9898 echo " -r | --repository CFG - configuration file or identifier defining the"
9999 echo " repository to use; can be given multiple times;"
100100 echo " CFG may include suffixes ',access={ro,rw},mode={bind,fuse}' to"
101- echo " overwrite the global access and/or mount mode for this repository"
101+ echo " overwrite the global access and/or mount mode for this repository;"
102+ echo " use 'None' to not mount any repositories"
102103 echo " [default: software.eessi.io via CVMFS config available"
103104 echo " via default container, see --container]"
104105 echo " -u | --resume DIR/TGZ - resume a previous run from a directory or tarball,"
@@ -123,6 +124,74 @@ display_help() {
123124 echo " '--' to let eessi_container.sh stop parsing arguments."
124125}
125126
127+ # function to parse and check bind paths
128+ # returns:
129+ # 0 if target found with matching source (no conflict)
130+ # 1 if target found with different source (conflict)
131+ # 2 if target not found
132+ check_bind_paths_for_target () {
133+ local search_target=" $1 "
134+ local search_src=" $2 "
135+ local bind_paths=" $3 " # typically used to pass value of $BIND_PATHS
136+
137+ # handle empty BIND_PATHS
138+ if [[ -z " ${bind_paths} " ]]; then
139+ return 2
140+ fi
141+
142+ # split by comma and process each entry
143+ IFS=' ,' read -ra BIND_ENTRIES <<< " ${bind_paths}"
144+
145+ for entry in " ${BIND_ENTRIES[@]} " ; do
146+ # skip empty entries
147+ [[ -z " ${entry} " ]] && continue
148+
149+ local bind_src bind_target
150+
151+ # split entry by ':'
152+ IFS=' :' read -ra PARTS <<< " ${entry}"
153+
154+ bind_src=" ${PARTS[0]} "
155+
156+ if [[ ${# PARTS[@]} -ge 2 ]]; then
157+ bind_target=" ${PARTS[1]} "
158+ else
159+ # no target given, use src
160+ bind_target=${bind_src}
161+ fi
162+
163+ # trim any possible whitespace
164+ bind_src=$( echo " ${bind_src} " | xargs)
165+ bind_target=$( echo " ${bind_target} " | xargs)
166+
167+ [[ ${VERBOSE} -eq 1 ]] && echo " Parsed bind entry: src='${bind_src} ' target='${bind_target} '"
168+
169+ # check if this entry matches our target
170+ if [[ " ${bind_target} " == " ${search_target} " ]]; then
171+ # found target -> need to compare normalised sources
172+ # try to normalise source paths, but don't fail if they don't exist (yet)
173+
174+ bind_src_normalised=$( readlink -f " ${bind_src} " 2> /dev/null)
175+ search_src_normalised=$( readlink -f " ${search_src} " 2> /dev/null)
176+
177+ # decide which path to use - normalised or original
178+ local bind_src_compare=" ${bind_src_normalised:- ${bind_src} } "
179+ local search_src_compare=" ${search_src_normalised:- ${search_src} } "
180+
181+ [[ ${VERBOSE} -eq 1 ]] && echo " Comparing: '${bind_src_compare} ' vs '${search_src_compare} '"
182+
183+ if [[ " ${bind_src_compare} " == " ${search_src_compare} " ]]; then
184+ return 0 # found target with same source (all good)
185+ else
186+ echo " ${bind_src} " # return the conflicting source for error message
187+ return 1 # found target with different source (conflict)
188+ fi
189+ fi
190+ done
191+
192+ return 2 # target not found in bind paths
193+ }
194+
126195# set defaults for command line arguments
127196ACCESS=" ro"
128197CONTAINER=" docker://ghcr.io/eessi/build-node:debian12"
@@ -285,6 +354,14 @@ if [[ ${#REPOSITORIES[@]} -eq 0 ]]; then
285354 REPOSITORIES+=(${eessi_default_cvmfs_repo} )
286355fi
287356
357+ # if the first element of REPOSITORIES is "none" (case-insensitive),
358+ # make sure it is an empty list from here on, i.e. no repositories will be mounted
359+ if [[ ${REPOSITORIES[0],,} == " none" ]]; then
360+ REPOSITORIES=()
361+ # also prevent the cvmfs-config repo from being mounted
362+ EESSI_DO_NOT_MOUNT_CVMFS_CONFIG_CERN_CH=1
363+ fi
364+
288365# 1. check if argument values are valid
289366# (arg -a|--access) check if ACCESS is supported
290367# use the value as global setting, suffix to --repository can specify an access mode per repository
@@ -719,17 +796,38 @@ if [[ ! -z ${http_proxy} ]]; then
719796 HTTP_PROXY_IPV4=$( get_ipv4_address ${PROXY_HOST} )
720797 [[ ${VERBOSE} -eq 1 ]] && echo " HTTP_PROXY_IPV4='${HTTP_PROXY_IPV4} '"
721798 echo " CVMFS_HTTP_PROXY=\" ${http_proxy} |http://${HTTP_PROXY_IPV4} :${PROXY_PORT} \" " \
722- >> ${EESSI_TMPDIR} /repos_cfg/default.local
799+ >> ${EESSI_TMPDIR} /repos_cfg/default.local
723800 [[ ${VERBOSE} -eq 1 ]] && echo " contents of default.local"
724801 [[ ${VERBOSE} -eq 1 ]] && cat ${EESSI_TMPDIR} /repos_cfg/default.local
725802
726803 # if default.local is not BIND mounted into container, add it to BIND_PATHS
727804 src=${EESSI_TMPDIR} /repos_cfg/default.local
728805 target=/etc/cvmfs/default.local
729- if [[ ${BIND_PATHS} =~ " ${target} " ]]; then
730- fatal_error " BIND target in '${src} :${target} ' is already in paths to be bind mounted into the container ('${BIND_PATHS} ')" ${REPOSITORY_ERROR_EXITCODE}
731- fi
732- BIND_PATHS=" ${BIND_PATHS} ,${src} :${target} "
806+
807+ # check if target already exists in BIND_PATHS, and, if so, if sources are
808+ # the same
809+ conflict_src=$( check_bind_paths_for_target " ${target} " " ${src} " " ${BIND_PATHS} " )
810+ check_result=$?
811+
812+ case ${check_result} in
813+ 0)
814+ # target already bound with same source - no action needed
815+ [[ ${VERBOSE} -eq 1 ]] && echo " Bind mount already configured: ${src} :${target} "
816+ ;;
817+ 1)
818+ # target already bound with different source - conflict!
819+ fatal_error " BIND target '${target} ' conflict: already bound from '${conflict_src} ', cannot bind from '${src} '" ${REPOSITORY_ERROR_EXITCODE}
820+ ;;
821+ 2)
822+ # target not found - safe to add
823+ if [[ -z ${BIND_PATH} ]]; then
824+ BIND_PATHS=" ${src} :${target} "
825+ else
826+ BIND_PATHS=" ${BIND_PATHS} ,${src} :${target} "
827+ fi
828+ [[ ${VERBOSE} -eq 1 ]] && echo " Added bind mount: ${src} :${target} "
829+ ;;
830+ esac
733831fi
734832
735833# 4. set up vars and dirs specific to a scenario
0 commit comments