├── .github └── workflows │ └── build.yml ├── .gitignore ├── COPYING ├── ChangeLog ├── README.md ├── ci ├── docker-run ├── make-and-test └── privileged-run ├── cvmfs2-wrapper ├── cvmfsexec ├── makedist ├── mountrepo ├── singcvmfs └── umountrepo /.github/workflows/build.yml: -------------------------------------------------------------------------------- 1 | name: Make distributions and test 2 | 3 | on: 4 | # run workflows on main master and release/** branches 5 | push: 6 | branches: 7 | - main 8 | - master 9 | - release/** 10 | # run workflows on pull requests against the same branches 11 | pull_request: 12 | branches: 13 | - main 14 | - master 15 | - release/** 16 | 17 | # automatically cancel redundant builds 18 | concurrency: 19 | group: ${{ github.workflow }}-${{ github.ref }} 20 | cancel-in-progress: true 21 | 22 | jobs: 23 | makeandtest: 24 | name: ${{ matrix.distro }}:${{ matrix.version }} 25 | strategy: 26 | fail-fast: false 27 | matrix: 28 | include: 29 | - distro: eurolinux/centos-7 30 | version: latest 31 | - distro: rockylinux 32 | version: 8 33 | - distro: rockylinux 34 | version: 9 35 | - distro: opensuse/leap 36 | version: 15 37 | - distro: debian 38 | version: 11 39 | - distro: debian 40 | version: 12 41 | - distro: ubuntu 42 | version: 22.04 43 | - distro: ubuntu 44 | version: 24.04 45 | runs-on: ubuntu-24.04 46 | steps: 47 | - name: Get source code 48 | uses: actions/checkout@v3 49 | 50 | - name: Run make-and-test under docker 51 | run: ./ci/docker-run ${{ matrix.distro }}:${{ matrix.version }} 52 | -------------------------------------------------------------------------------- /.gitignore: -------------------------------------------------------------------------------- 1 | dist 2 | log 3 | mnt 4 | -------------------------------------------------------------------------------- /COPYING: -------------------------------------------------------------------------------- 1 | Fermilab Software Legal Information (BSD License) 2 | Copied from http://fermitools.fnal.gov/about/terms.html 3 | 4 | Copyright (c) 2019, FERMI NATIONAL ACCELERATOR LABORATORY 5 | All rights reserved. 6 | 7 | Redistribution and use in source and binary forms, with or without 8 | modification, are permitted provided that the following conditions are 9 | met: 10 | 11 | * Redistributions of source code must retain the above copyright 12 | notice, this list of conditions and the following disclaimer. 13 | * Redistributions in binary form must reproduce the above 14 | copyright notice, this list of conditions and the following 15 | disclaimer in the documentation and/or other materials provided 16 | with the distribution. 17 | * Neither the name of the FERMI NATIONAL ACCELERATOR LABORATORY, 18 | nor the names of its contributors may be used to endorse or 19 | promote products derived from this software without specific 20 | prior written permission. 21 | 22 | THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS 23 | "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT 24 | LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR 25 | A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT 26 | HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, 27 | SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT 28 | LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, 29 | DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY 30 | THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT 31 | (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE 32 | OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 33 | -------------------------------------------------------------------------------- /ChangeLog: -------------------------------------------------------------------------------- 1 | cvmfsexec-4.47 - 19 May 2025 2 | - Remove setting X509_USER_PROXY because it is no longer used. 3 | 4 | cvmfsexec-4.46 - 2 April 2025 5 | - Go back to selecting the cvmfs version from the egi and osg distribution. 6 | - Properly sort the cvmfs version number from the downloaded list of packages. 7 | - For osg use 24-main instead of 23-main. 8 | - For suse15 switch to getting some packages from el8 instead of el7. 9 | - Retry rpm downloads up to 3 times if they fail. 10 | 11 | cvmfsexec-4.45 - 5 March 2025 12 | - Change to try downloading cvmfs packages from cvmrepo.s3.cern.ch and 13 | fall back to cvmrepo.web.cern.ch if that doesn't work. 14 | 15 | cvmfsexec-4.44 - 5 February 2025 16 | - Add translations in makedist from debian 11 & 12 and ubuntu 22 & 24 to 17 | rhel8 & rhel9. 18 | 19 | cvmfsexec-4.43 - 6 January 2025 20 | - Adjust the URL for downloading osg packages after the layout changed. 21 | - Add the variable SINGCVMFS_LOGDIR to override the location of the 22 | cvmfs logs. 23 | 24 | cvmfsexec-4.42 - 24 September 2024 25 | - Add rhel9-aarch64 and rhel9-ppc64le machine types. 26 | - In makedist help, split machine types from different distributions 27 | onto different lines. 28 | 29 | cvmfsexec-4.41 - 9 September 2024 30 | - Switch to the archive for el7 epel packages. 31 | - Add CI checks on every pull request for a fairly through test of 32 | all the combinations of modes, distributions, and machine types. 33 | 34 | cvmfsexec-4.40 - 5 July 2024 35 | - Switch to vault.centos.org for el7 fuse-libs package. 36 | 37 | cvmfsexec-4.39 - 26 January 2024 38 | - Skip installing cvmfs-x509-helper with the "default" configuration. 39 | 40 | cvmfsexec-4.38 - 25 January 2024 41 | - Support scitokens with authenticated repositories. 42 | - Switch osg el8 & el9 to use the 23-main repositories instead of 3.6. 43 | - Skip cvmfs-libs if the cvmfs minor version is less than 10. 44 | - Fail when an rpm extraction fails. 45 | 46 | cvmfsexec-4.37 - 7 September 2023 47 | - Include the cvmfs-libs rpm in the cvmfs distribution. The rpm was 48 | added in cvmfs-2.10.0 and started being required by the cvmfs package 49 | in cvmfs-2.11.0. 50 | 51 | cvmfsexec-4.36 - 5 July 2023 52 | - Fix making rhel8-ppc64le distributions, which was broken in 4.34. 53 | 54 | cvmfsexec-4.35 - 21 June 2023 55 | - The previous fix was not actually able to distinguish between -s and 56 | not -s on el9. So instead, makedist now always creates a file 57 | .cvmfsexecdist at the top level which says what type it is, "sing" or 58 | "standard", and also what the machine type was. makedist -o requires 59 | that file only with -s (for now), so anyone with a makedist -s 60 | distribution will have to remake their distribution if they want to 61 | use -o. 62 | 63 | cvmfsexec-4.34 - 21 June 2023 64 | - Fix makedist -o when cross-building between el9 and non-el9 hosts so 65 | that it doesn't need to be passed the -m option again to match what 66 | was given to makedist without -o. It also was not able to distinguish 67 | on el9 between distributions that had been made with and without -s. 68 | 69 | cvmfsexec-4.33 - 11 June 2023 70 | - Add rhel8-aarch64 machine type. 71 | - Avoid error messages from extra attempted downloads of the fuse2 library 72 | on the suse15-x86_64 machine type. 73 | 74 | cvmfsexec-4.32 - 11 May 2023 75 | - Fix typo in version 4.31 that caused config repo to be ignored. 76 | 77 | cvmfsexec-4.31 - 4 May 2023 78 | - Add a `none` distribution type in makedist, for no cvmfs config repo. 79 | - Fix mountrepo for the case where a config repo is not set. 80 | - Fix fuse3-libs package repo on EL8 when building for singcvmfs. 81 | 82 | cvmfsexec-4.30 - 6 February 2023 83 | - Fix rhel9 support in makedist -o. 84 | 85 | cvmfsexec-4.29 - 6 February 2023 86 | - Add support for machine type rhel9-x86_64 in makedist. 87 | 88 | cvmfsexec-4.28 - 21 December 2022 89 | - Fix a bug in the code handling inaccessible binds, introduced in 4.26. 90 | - Change rpm downloads to all use https 91 | - Change the source of the fuse3-libs on el8 for makedist -s to be alma8 92 | instead of epel7, now that the version is updated there to be new enough. 93 | 94 | cvmfsexec-4.27 - 2 November 2022 95 | - Set X509_USER_PROXY and/or BEARER_TOKEN_FILE if they are not set, 96 | because the cvmfs authorization helper runs under the fake root user 97 | and so it by default looks at the 0 id instead of the user's id. 98 | 99 | cvmfsexec-4.26 - 1 November 2022 100 | - Skip binding in something from the host if it is inaccessible. 101 | Previously cvmfsexec assumed it was a file, but it could be an 102 | inaccessible directory and cause a bind mount failure. 103 | 104 | cvmfsexec-4.25 - 28 September 2022 105 | - Set APPTAINER_BINDPATH in addition to SINGULARITY_BINDPATH in singcvmfs 106 | for supporting apptainer. 107 | - Add support in singcvmfs for using an ext3 image file for the cvmfs cache. 108 | (Note: for this, non-setuid apptainer 1.1.0 requires the /var/lib/cvmfs 109 | directory to be pre-created in the image). 110 | 111 | cvmfsexec-4.24 - 7 September 2022 112 | - Fix makedist of suse machine type; the libfuse2 download link had an extra 113 | "Details" reference on the end that was confusing it. 114 | - Make makedist of rhel8-ppc64le work again. It was broken by update in 4.22. 115 | - Use a unique name for each copr repo referenced, because otherwise 116 | yumdownloader's caching gets confused. 117 | - Remove makedist support for rhel6 machine type. 118 | 119 | cvmfsexec-4.23 - 19 August 2022 120 | - Fix bug with cvmfsexec mode 2, on an older RHEL 7 kernel where USERFUSE 121 | gets set to false, that caused repositories to be unmounted early if the 122 | -N option was used. 123 | 124 | cvmfsexec-4.22 - 18 July 2022 125 | - Update the download URL for suse15, the old one doesn't work anymore 126 | - Put a more explicit message in as to why rhel8 does not work with egi 127 | - Remove old fallback code for osg rhel8 to download from osg-testing repo 128 | 129 | cvmfsexec-4.21 - 7 July 2022 130 | - Set LD_LIBRARY_PATH for fuse2fs to find libfuse from the dist directory. 131 | - Get rid of fuse2fs warnings by waiting for clean unmount when possible, 132 | and by instructing to create the filesystem without a journal. 133 | 134 | cvmfsexec-4.20 - 7 July 2022 135 | - Add `-m` option to mount a scratch filesystem with fuse2fs. 136 | 137 | cvmfsexec-4.19 - 23 June 2022 138 | - Add rhel8-ppc64le supported type in makedist. Does not include support 139 | for authenticated mounts because of no cvmfs-x509-helper. 140 | - Switch to Almalinux for rhel8-x86_64 fuse-libs (because Rocky doesn't 141 | have ppc64le) in makedist 142 | - Have makedist abort with clear error if not using one of the supported 143 | machine types 144 | 145 | cvmfsexec-4.18 - 10 April 2022 146 | - Change makedist osg to use osg3.6 instead of osg3.5 147 | 148 | cvmfsexec-4.17 - 10 February 2022 149 | - Change makedist on el8 to download from Rocky Linux repository instead 150 | of CentOS. Also add el9 to download from CentOS 9 Stream. 151 | 152 | cvmfsexec-4.16 - 21 December 2021 153 | - Change that to /proc/driver, not /proc/device 154 | 155 | cvmfsexec-4.15 - 16 December 2021 156 | - Avoid using new pid namespace also if /proc/device is mounted, as 157 | happens under docker with --gpus 158 | 159 | cvmfsexec-4.14 - 17 August 2021 160 | - Exclude 32bit fuse library from suse distribution 161 | 162 | cvmfsexec-4.13 - 17 August 2021 163 | - Change mountrepo to edit directory names starting with /var first, in 164 | case the working directory begins with /var. 165 | 166 | cvmfsexec-4.12 - 15 June 2021 167 | - Change mountrepo to avoid editing directory names that begin with "/cvmfs" 168 | but are longer, for example if someone names something "/cvmfsexec". 169 | - Suport mounting ligo.osgstorage.org. (Also needs changes in config 170 | repo and updates to cvmfs that are now in nightly builds and will be 171 | in cvmfs-2.8.2). 172 | 173 | cvmfsexec-4.11 - 3 May 2021 174 | - Complete the implementation of -N by closing CVMFSEXEC_CMDFD. 175 | - Avoid hangs when using -N while systempaths are masked. 176 | 177 | cvmfsexec-4.10 - 29 April 2021 178 | - Add -N option. 179 | 180 | cvmfsexec-4.9 - 28 April 2021 181 | - Fix bug introduced in 4.7 that caused mountrepo inside of cvmfsexec to 182 | hang after mounting. 183 | - Prevent mountrepo inside of cvmfsexec from hanging if CVMFSEXEC_CMDFD 184 | is closed. 185 | 186 | cvmfsexec-4.8 - 23 April 2021 187 | - When /proc is masked, wait for cleanup to happen before exiting. 188 | 189 | cvmfsexec-4.7 - 23 March 2021 190 | - Check the return code of mount /proc in cvmfsexec and exit immediately 191 | with a helpful message if it fails. 192 | - When /proc is "masked" like in the default settings of docker and 193 | kubernetes, do not use a separate pid namespace and instead cleanly 194 | unmount all the repositories before exiting. 195 | - If running as fake root inside of umountrepo use umount instead of 196 | fusermount -u. 197 | 198 | cvmfsexec-4.6 - 5 February 2021 199 | - Add support for instance commands to singcvmfs. Contributed by Ben 200 | Tovar. 201 | 202 | cvmfsexec-4.5 - 28 October 2020 203 | - Implement fill "source" processing of config files in mountrepo, to 204 | handle the double sourcing of files recently introduced in the OSG 205 | configuration repository. 206 | - Change cvmfsexec to properly return error codes from mountrepo. 207 | 208 | cvmfsexec-4.4 - 13 August 2020 209 | - Add support for suse to makedist. 210 | - Add makedist -m machinetype option to make distributions for 211 | non-native machine types. 212 | - Make sure /usr/sbin is in the cvmfsexec PATH, for finding pivot_root. 213 | - Prevent cvmfsexec from exiting until repositories are unmounted. 214 | 215 | cvmfsexec-4.3 - 23 June 2020 216 | - Have makedist -o and mountrepo also look for fuse library in dist/lib* in 217 | order to support el6. 218 | - Order default WPAD servers to prioritize fnal for osg and cern for 219 | other distributions. 220 | 221 | cvmfsexec-4.2 - 1 June 2020 222 | - In singcvmfs when cvmfs debugging is enabled, also save the initial 223 | output of cvmfs2 in the debug log file. 224 | - On osg el8, get rpms from testing yum repository if they're missing 225 | from the release repository. 226 | 227 | cvmfsexec-4.1 - 4 May 2020 228 | - Change makedist -s to make sure cvmfs-fuse3 exists 229 | - Include cvmfs2-wrapper in makedist -s -o self-extracting script 230 | 231 | cvmfsexec-4.0 - 1 May 2020 232 | - Change singcvmfs to directly pass commands that start with exec, run, 233 | shell, or version to singularity, so it can be used as a drop-in 234 | replacement for singularity. When used in this mode, $SINGCVMFS_IMAGE 235 | is not required. 236 | - Change $SINGCVMFS_LOGLEVEL to only apply to cvmfs debugging. Instead, 237 | singularity debugging along with any other singularity global option 238 | can be passed directly on the command line before the command. 239 | - Change the -v option of singcvmfs that reported its version to -V. 240 | - Change the name of $SINGCVMFS_CVMFSOPTSFILE to $SINGCVMFS_OPTSFILE. 241 | - Change the extraction directory for a self-extracting singcvmfs 242 | made by makedist -s -o to be .singcvmfs instead of $HOME/.singcvmfs 243 | 244 | cvmfsexec-3.2 - 29 April 2020 245 | - Change makedist without -s (that is, for cvmfsexec) to include fuse-libs 246 | for systems that do not have it. 247 | - Change makedist to turn symlinks with full path targets into relative 248 | paths. This was preventing singcvmfs from working on systems that 249 | didn't already have cvmfs installed. 250 | - Remove the cvmfs mounting messages in singcvmfs that otherwise start 251 | happening with singularity-3.6. 252 | - Change singcvmfs to send syslog messages to log/.log. 253 | - Add SINGCVMFS_LOGLEVEL=debug which enables debugging for singularity & 254 | cvmfs. The cvmfs debug messages go to log/-debug.log. 255 | 256 | cvmfsexec-3.1 - 15 April 2020 257 | - Change makedist to fail with better error messages when it can't 258 | download packages it needs. 259 | - Change makedist -s to download fuse3 from EPEL7 when on RHEL8, because 260 | the RHEL8.1 fuse3 version is too old and the fact that it moved to 261 | the base OS caused it to be removed from EPEL8. 262 | - Change makedist to exclude .build-id files. 263 | - Add "http://grid-wpad/wpad.dat;http://wpad/wpad.dat" to the beginning 264 | of the default Proxy Auto Config URLs. 265 | - Change singcvmfs to set CVMFS_NFILES in a default.d config file, to 266 | avoid showing a cvmfs warning with singularity >= 3.6. 267 | 268 | cvmfsexec-3.0 - 10 April 2020 269 | - Add singcvmfs command and makedist -s option. 270 | - Support unprivileged namespace fuse mounts in cvmfsexec on RHEL 7.8. 271 | 272 | cvmfsexec-2.6 - 30 March 2020 273 | - Avoid relocating OASIS_CERTIFICATES variable in oasis.opensciencegrid.org. 274 | 275 | cvmfsexec-2.5 - 24 March 2020 276 | - Exclude cvmfs-x509-helper-debug in makedist. 277 | 278 | cvmfsexec-2.4 - 23 March 2020 279 | - Add support in mountrepo for ". ../" in config files, as it is used in 280 | the EGI config repository for reading common.conf. 281 | 282 | cvmfsexec-2.3 - 23 December 2019 283 | - Fix support of cvmfs-2.7.0 by using its new CVMFS_LIBRARY_PATH. 284 | 285 | cvmfsexec-2.2 - 4 December 2019 286 | - allow multiple settings of CVMFS_CONFIG_REPOSITORY in default.d files. 287 | 288 | cvmfsexec-2.1 - 9 October 2019 289 | - Direct logs to per-repository files in "log" directory instead of syslog. 290 | - Add makedist -o option to create one self-extracting script with the 291 | cvmfs distribution and cvmfsexec tools. 292 | 293 | cvmfsexec-2.0 - 7 October 2019 294 | - Take advantage of user namespace fuse mounts on kernels >= 4.18 (CentOS 8). 295 | This enables cleaning up mountpoints even with kill -9. 296 | - Replace the $CVMFSEXEC interface with a simpler $CVMFSMOUNT/$CVMFSUMOUNT 297 | interface that also leaves no extra processes in the process tree. 298 | - Always use --rbind instead of --bind when doing underlay mounts. 299 | - Add cvmfs-x509-helper in makedist when it is present. 300 | 301 | cvmfsexec-1.1 - 12 September 2019 302 | - Preserve whitespace in parameters. 303 | - Enable adding additional mounted repositories by invoking $CVMFSEXEC. 304 | - Don't attempt to mount repositories that are already mounted. 305 | - Always mount the config repository first. 306 | - Enable cvmfs debug option when CVMFS_DEBUGLOG is set. 307 | 308 | cvmfsexec-1.0 - 6 September 2019 309 | - Initial release. 310 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # cvmfsexec package 2 | 3 | Whenever possible it is best to install standard 4 | [cvmfs](https://cernvm.cern.ch/fs/) from native OS packages, but 5 | sometimes that is not an option. 6 | This package is for mounting cvmfs as an unprivileged user, without the 7 | cvmfs package being installed by a system administrator. The package can 8 | do this in 4 different ways: 9 | 10 | 1. On systems where only fusermount is available, the `mountrepo` and 11 | `umountrepo` commands can be used to mount cvmfs repositories in the 12 | user's own file space. That path can then be bindmounted at /cvmfs 13 | by a container manager such as 14 | [apptainer](https://github.com/apptainer/apptainer) 15 | (formerly known as singularity). 16 | A big disadvantage compared to mode 3 below is that if the processes 17 | are hard-killed (kill -9), mountpoints are left behind and difficult 18 | to clean up. 19 | 2. On systems where fusermount is available and unprivileged user 20 | namespaces are enabled, but unprivileged namespace fuse mounts are not 21 | available (in particular RHEL <=7.7 with 22 | `sysctl user.max_user_namespaces` > 0), 23 | the `cvmfsexec` command can mount cvmfs repositories, map them into 24 | /cvmfs, and unmount them when it exits. apptainer may even be 25 | run unprivileged from cvmfs from within cvmfsexec (it has to run 26 | unprivileged because setuid-root does not work inside a user 27 | namespace). 28 | This mode shares the disadvantage that mode 1 has compared to mode 3 29 | in that if the processes are hard-killed, mountpoints are left behind. 30 | 3. On systems where unprivileged namespace fuse mounts are available 31 | (newer kernels >= 4.18 as on RHEL8 or >= 3.10.0-1127 as on RHEL 7.8), 32 | the `cvmfsexec` command can entirely manage mounting and unmounting 33 | of cvmfs repositories in the namespace, so if they get killed 34 | everything gets cleanly unmounted. fusermount is not needed in this 35 | case. 36 | 4. On systems that have no fusermount nor unprivileged user namespace 37 | fuse mounts but do have a setuid installation of singularity >= 3.4 38 | or apptainer, 39 | an entirely separate command in this package `singcvmfs` can mount 40 | cvmfs repositories inside a container using the `--fusemount` feature. 41 | With singularity >= 3.6 and RHEL >= 7.8 and 42 | unprivileged user namespaces enabled, 43 | this can also be used with unprivileged singularity or apptainer. 44 | 45 | # Supported operating systems 46 | 47 | Operating systems currently supported by this package are Red Hat 48 | Enterprise Linux (versions 7, 8, and 9) and its derivatives (CentOS, 49 | Scientific Linux, Rocky Linux, Alma Linux) 50 | and SUSE Linux Enterprise (version 15) 51 | and its derivatives (openSUSE Leap). 52 | Debian (11 and 12) and Ubuntu (22.04 & 24.04) are also supported 53 | with modes 1 to 3, 54 | by using rhel8 and rhel9 binaries; 55 | those binaries aren't compatible enough for mode 4, however. 56 | All of those support the x86_64 architecture, 57 | and rhel8 also supports ppc64le and aarch64. 58 | 59 | Even though RHEL7 is now officially End of Life, cvmfsexec will still 60 | support it for a while because some people continue to use it with 61 | extended support. 62 | 63 | # Making the cvmfs distribution 64 | 65 | All of the ways this package supports unprivileged cvmfs make use of a 66 | copy of the cvmfs software. The cvmfs software and configuration are 67 | expected to be in a `dist` subdirectory under where the scripts are. The 68 | easiest way to create the dist directory is to use `makedist`. It takes a 69 | parameter of `osg`, `egi`, or `default` to download the latest cvmfs and 70 | configuration rpm from one of those three sources. Note: `egi` does not 71 | currently provide rpms for RHEL8 or 9. Additionally, specifying `none` 72 | will download from the `default` source but exclude the 73 | `cvmfs-config-default` package. 74 | 75 | The `makedist` command does require 3 tools that are not always 76 | installed on Linux distributions: `curl`, `rpm2cpio`, and `cpio`. 77 | If those cannot be installed, you should be able to run the makedist 78 | command on a host that does have them and copy the distribution to 79 | the system where you need it. 80 | 81 | By default a distribution for `cvmfsexec` and `mountrepo/umountrepo` is 82 | created. To instead make a distribution for `singcvmfs`, add the `-s` 83 | makedist option. By default the distribution made will match the 84 | operating system it runs on, but another distribution can be selected 85 | with the `-m` option. See the makedist usage for supported machine types. 86 | 87 | To customize any cvmfs configuration settings, put them in 88 | `dist/etc/cvmfs/default.local`. In particular you may want to set 89 | CVMFS_HTTP_PROXY, although the default is to use WLCG Web Proxy Auto 90 | Discovery. You may also want to set CVMFS_QUOTA_LIMIT, otherwise the 91 | default is 4000 MB. The default CVMFS_CACHE_BASE for the cache 92 | shared between the cvmfs repository is under the dist directory, 93 | `dist/var/lib/cvmfs`, unless the `-m` option is used to add an e2fs 94 | filesystem (details [below](#optionally-mount-a-scratch-filesystem)). 95 | Make sure that the cache does not get shared between multiple machines. 96 | 97 | ## Self-contained distribution 98 | 99 | For the cases where `cvmfsexec` or `singcvmfs` can be used, you can also 100 | make a self-contained distribution in a single file that contains both 101 | the command and all supporting files. This makes it easy to share the 102 | distribution with other users or distribute it to many machines. 103 | 104 | After running makedist and making any customizations you want, use 105 | this to make a cvmfsexec distribution: 106 | ``` 107 | makedist -o /tmp/cvmfsexec 108 | ``` 109 | or this to make a singcvmfs distribution: 110 | ``` 111 | makedist -s -o /tmp/singcvmfs 112 | ``` 113 | 114 | Executing a cvmfsexec file that is created in that way leaves behind a 115 | .cvmfsexec directory in the directory where it is run from, and running 116 | a singcvmfs file leaves behind a .singcvmfs directory. 117 | 118 | # cvmfsexec command (modes 2 and 3) 119 | 120 | The cvmfsexec command requires unprivileged user namespaces. On RHEL8/9 121 | unprivileged user namepaces (and user namespace fuse mounts) are 122 | available by default, but on RHEL7 they need to be enabled by setting a 123 | sysctl parameter as detailed in the 124 | [OSG unprivileged apptainer instructions](https://osg-htc.org/docs/worker-node/install-apptainer/#enabling-unprivileged-apptainer). 125 | In addition cvmfsexec requires fusermount on kernels older than 126 | those that come with RHEL7.8. 127 | 128 | To execute a command in an environment where cvmfs repositories are 129 | mounted at /cvmfs and automatically unmounted upon exit, use 130 | `cvmfsexec repository.name ... -- [command]` where the default command 131 | is $SHELL. It will automatically mount the configuration repository if 132 | one is defined. 133 | 134 | Unless disabled with the `-N` option, 135 | inside the command you can mount additional repositories by using 136 | `$CVMFSMOUNT repository.name`. Since the mounts have to happen outside 137 | the user namespace, it actually sends a message to the original process 138 | to mount, and makes the current process wait until completion. 139 | Repositories that are already mounted are ignored. You can also unmount 140 | repositories from within the command with `$CVMFSUMOUNT repository.name`. 141 | If you want to use this feature and also 142 | invoke additional processes within the original process that are 143 | not trustworthy, such as user payloads that are invoked with 144 | `--contain` option of singularity or apptainer, 145 | then close the $CVMFSEXEC_CMDFD file descriptor 146 | for those processes. This can be done in bash with 147 | `exec {CVMFSEXEC_CMDFD}>&-`. 148 | 149 | Note that setuid-root programs do not work inside an unprivileged user 150 | namepace, so if you use singularity or apptainer it has to be run unprivileged. 151 | 152 | Cache considerations: by default cvmfsexec starts a cache manager 153 | process for all the cvmfs repositories it mounts, which means only one 154 | cvmfsexec process can share a cache on a single machine. The cvmfs 155 | configuration could be set to use a different path for a cache for 156 | different invocations (the default is `dist/var/lib/cvmfs`), or it could 157 | be set to use cvmfs alien cache mode which doesn't use a cache manager, 158 | but the best approach is to start cvmfsexec from a pilot process and run 159 | only one pilot per machine. If possible the cache should be on local 160 | disk, because otherwise the many file accesses can overwhelm a shared 161 | filesystem's metadata server. Also, many network filesystems types 162 | cannot handle the locks that cvmfs creates. 163 | If there is no local disk the next best 164 | option is to mount a filesystem separately for each worker 165 | node from a big enough file on the shared filesystem, or alternatively 166 | a RAM disk on the local node if there is sufficient RAM. 167 | The `-m` option (described in the next section) can mount that separate 168 | scratch filesystem for you in the cvmfsexec namespace. 169 | Otherwise, if the cache directory needs to be changed that can be done 170 | by setting CVMFS_CACHE_BASE in `dist/etc/cvmfs/default.local`, 171 | or you can just install the whole distribution in the local filesystem. 172 | 173 | ## Optionally mount a scratch filesystem 174 | 175 | If there is no local disk available, cvmfsexec can mount a scratch 176 | ext2/3/4 filesystem with the `-m` option, using the fuse2fs command. 177 | The filesystem will appear in the cvmfsexec namespace at `/e2fs`. 178 | If you have not set CVMFS_CACHE_BASE in `dist/etc/cvmfs/default.local` 179 | then this filesystem will automatically be used for cvmfs cache, and 180 | it can also be used as scratch workspace for jobs. 181 | 182 | Make sure that there is a unique file for each running copy of cvmfsexec. 183 | Create the file with commands like this: 184 | ``` 185 | truncate -s 600G scratch.img 186 | mkfs.ext4 -F -O ^has_journal scratch.img 187 | ``` 188 | Choose a count of the number of gigabytes you want. The default cache 189 | size is 4000 megabytes, and the recommendation is to reserve an 190 | additional 1000 megabytes plus 20%, so make it at least 6 gigabytes 191 | and add any additional space you want to use as scratch workspace. 192 | It's a sparse file so there's little penalty for creating it bigger if 193 | the space is never used. 194 | Then start cvmfsexec with `-m`. For example, to mount only the 195 | cvmfs configuration repository and run a shell do 196 | ``` 197 | cvmfsexec -m scratch.img -- 198 | ``` 199 | Then check out `/e2fs`. 200 | 201 | NOTE: although this functions easily and well, fuse2fs performance is 202 | not great so if a more performant option is available that is likely 203 | to be preferred. 204 | 205 | ## Better cvmfsexec operation on newer kernels (mode 3) 206 | 207 | A caveat on older kernels (for example RHEL7.7 and older) is that a 208 | kill -9 of all the processes will not clean up the mounts, and they 209 | have to be separately unmounted later with `umountrepo` or `fusermount -u`. 210 | On kernels >= 4.18 (for example RHEL8) or >= 3.10.0-1127 (for example on 211 | RHEL7.8) the operation changes to do fuse mounts only inside of 212 | unprivileged user namespaces, which always completely cleans up mounts 213 | even with kill -9. This also normally uses a pid namespace to ensure 214 | that all fuse processes are always cleaned up when the command exits 215 | (the exception is when running under docker and kubernetes default 216 | configurations that "mask" /proc). 217 | 218 | $CVMFSMOUNT/$CVMFSUMOUNT still send a request to a parent process to 219 | mount/umount but it's not the original process, it's an intermediate 220 | process that has fakeroot access in the user namespace. 221 | 222 | ## mountrepo/umountrepo without cvmfsexec (mode 1) 223 | 224 | When not using cvmfsexec, but with fusermount available use 225 | `mountrepo repository.name` to mount a repository. Note that the osg 226 | configuration requires "config-osg.opensciencegrid.org" to be mounted 227 | first, and the egi configuration requires "config-egi.egi.eu". 228 | 229 | If you are using a container system, bind mount $PWD/dist/cvmfs into the 230 | container as /cvmfs. 231 | 232 | To unmount all repositories, use `umountrepo -a`, or to unmount an 233 | individual repository use `umountrepo repository.name`. Make sure that 234 | all the processes do not get killed or the repositories will remain 235 | mounted but inaccessible. 236 | 237 | Cache considerations for this mode are the same as with the cvmfsexec 238 | command. 239 | 240 | ## Debugging 241 | 242 | Syslog messages from cvmfs go in the `log` subdirectory alongside 243 | `dist`. A separate log file is created for each repository. cvmfs 244 | debugging logs can also be enabled in the usual way, by setting 245 | CVMFS_DEBUGLOG in the cvmfs configuration. 246 | 247 | ## Running from docker 248 | 249 | Docker supports unprivileged user namespaces including unprivileged fuse 250 | mounts on the kernels that support it, without using the `--privileged` 251 | option or adding capabilities. The following set of docker options is 252 | sufficient: 253 | 254 | ``` 255 | --security-opt seccomp=unconfined --security-opt systempaths=unconfined --device=/dev/fuse 256 | ``` 257 | 258 | If you have no need for running any setuid executables in docker then 259 | you can improve security further by adding: 260 | ``` 261 | --security-opt no-new-privileges 262 | ``` 263 | Singularity and apptainer always have the equivalent protection enabled for the 264 | containers they run. 265 | 266 | # singcvmfs command (mode 4) 267 | 268 | When a privileged setuid installation of singularity >= 3.4 or 269 | any version of apptainer is 270 | available, the `singcvmfs` command can be used to mount cvmfs 271 | repositories inside a container. With singularity >= 3.6 and 272 | RHEL >= 7.8 or a kernel >= 4.18 273 | with unprivileged user namespaces enabled 274 | this can also be used with an 275 | unprivileged non-setuid singularity or apptainer installation. 276 | The command line interface is different than cvmfsexec because it is 277 | designed for ease of use by end users on a laptop/desktop and as a 278 | drop-in replacement for singularity when it executes containers. 279 | 280 | Put cvmfs repositories to mount comma-separated in a 281 | `SINGCVMFS_REPOSITORIES` environment variable. If a configuration 282 | repository is needed it will be automatically mounted. Then you can use 283 | singcvmfs exactly like singularity with one of its exec, instance, run, 284 | or shell commands (note: it cannot read an image from cvmfs). For example, 285 | once you have [made a singcvmfs distribution](#making-the-cvmfs-distribution) 286 | the following should work (replace `centos:7` with a container matching 287 | the operating system you're running on): 288 | 289 | ``` 290 | $ export SINGCVMFS_REPOSITORIES="grid.cern.ch,atlas.cern.ch" 291 | $ singcvmfs -s exec -cip docker://centos:7 bash 292 | Singularity> ls /cvmfs 293 | atlas.cern.ch config-osg.opensciencegrid.org grid.cern.ch 294 | Singularity> ls /cvmfs/atlas.cern.ch 295 | repo 296 | Singularity> exit 297 | 298 | # or using singularity instances: 299 | $ export SINGCVMFS_REPOSITORIES="grid.cern.ch,atlas.cern.ch" 300 | $ singcvmfs -s instance start docker://centos:7 myexampleinstance 301 | $ singcvmfs -s run instance://myexampleinstance ls /cvmfs 302 | atlas.cern.ch config-osg.opensciencegrid.org grid.cern.ch 303 | $ singcvmfs -s run instance://myexampleinstance ls /cvmfs/atlas.cern.ch 304 | repo 305 | $ singcvmfs -s instance stop myexampleinstance 306 | ``` 307 | 308 | The first time you run the above it will take a long time as singularity 309 | downloads the image from dockerhub and cvmfs fills its cache, but 310 | running it again should be very fast. 311 | 312 | Alternatively, to make it easier to execute repeatedly interactively 313 | from the command line, you can put the singularity container path in a 314 | `SINGCVMFS_IMAGE` environment variable and leave out the singularity 315 | command. The image cannot come from cvmfs, but it can come from docker, 316 | shub, a local image file, or a local "sandbox" unpacked image directory. 317 | Then the usage is `singcvmfs [command]` where the default command is 318 | $SHELL. For example: 319 | 320 | ``` 321 | $ export SINGCVMFS_REPOSITORIES="grid.cern.ch,atlas.cern.ch" 322 | $ export SINGCVMFS_IMAGE="docker://centos:7" 323 | $ singcvmfs ls /cvmfs 324 | atlas.cern.ch config-osg.opensciencegrid.org grid.cern.ch 325 | $ singcvmfs ls /cvmfs/atlas.cern.ch 326 | repo 327 | ``` 328 | 329 | There are other optional environment variables that may be set. 330 | Run `singcvmfs -h` for more details. 331 | 332 | Caveat: singcvmfs works by bind-mounting all of the files from the cvmfs 333 | distribution into the container, including the fuse3 libraries. It 334 | expects other base system libraries to be available inside the 335 | container, so if the container uses a different base OS distribution it 336 | will likely not work unless compatible libraries are in the container. 337 | 338 | Cache considerations: by default singcvmfs starts a cache manager for all 339 | the cvmfs repositories it mounts, which means that caches cannot be shared 340 | between different invocations of singcvmfs on the same machine. 341 | This tends to be more of a problem than with the cvmfsexec command 342 | because it is more common to run many payload jobs on a machine with 343 | singularity than it is to run many pilots. You can 344 | select a different cache directory for each invocation by setting 345 | SINGCVMFS_CACHEDIR. Alternatively it's possible to use the [cvmfs alien 346 | cache](https://cvmfs.readthedocs.io/en/stable/cpt-configure.html#alien-cache) 347 | feature to share the cache, but you would have to make sure that the 348 | cache doesn't grow too big and that it gets cleaned up at some point. 349 | Make sure that caches are not on shared filesystems because they're 350 | likely to do too many metadata operations. 351 | 352 | There is also a SINGCVMFS_CACHEIMAGE variable which can be set to an 353 | ext3 filesystem image for the cache. If set, it must point to a 354 | file with such a filesystem including a directory that is writable by 355 | the user or a `shared` directory within it that is writable by the user. 356 | The directory within the filesystem can be changed by setting 357 | SINGCVMFS_CACHEDIR but defaults to the root directory, `/`. 358 | If running as an unprivileged user, this can directory can be created 359 | using the `mkfs.ext3 -d` option. Unfortunately the version of 360 | `mkfs.ext3` on RHEL7 is too old, but it can be compiled from 361 | [source](https://github.com/tytso/e2fsprogs/blob/master/INSTALL). 362 | Then to make the image file these commands should work: 363 | 364 | ``` 365 | $ truncate -s 6G scratch.img 366 | $ mkdir -p tmp/shared 367 | $ mkfs.ext3 -F -O ^has_journal -d tmp scratch.img 368 | ``` 369 | 370 | By default the cvmfs logs are written to a top-level `log` directory, alongside 371 | the top-level `dist` directory. The variable `SINGCVMFS_LOGDIR` can be used to 372 | write them to a different directory, which will be created if it doesn't exist. 373 | -------------------------------------------------------------------------------- /ci/docker-run: -------------------------------------------------------------------------------- 1 | #!/bin/bash -e 2 | # Run docker as shown at 3 | # https://djw8605.github.io/2016/05/03/building-centos-packages-on-travisci/ 4 | # 5 | # This more complicated setup is needed for github actions too because 6 | # they do not provide a mechanism for reliably enabling user namespaces. 7 | # Github actions does at least start a VM with docker already running. 8 | 9 | # Assumes running on Ubuntu 24+ 10 | 11 | DOCKER_HUB_URI="$1" 12 | docker pull "$DOCKER_HUB_URI" 13 | 14 | DOCKER_CONTAINER_NAME="test_${OS_TYPE##*/}_${OS_VERSION//./_}" 15 | 16 | set -x 17 | docker run --privileged --network=host -v "$(pwd):/source:rw" \ 18 | -e DOCKER_HUB_URI="$DOCKER_HUB_URI" \ 19 | --name "$DOCKER_CONTAINER_NAME" "$DOCKER_HUB_URI" /bin/bash -exc \ 20 | "cd /source && ./ci/privileged-run" 21 | 22 | docker ps -a 23 | docker stop "$DOCKER_CONTAINER_NAME" 24 | docker rm -v "$DOCKER_CONTAINER_NAME" 25 | -------------------------------------------------------------------------------- /ci/make-and-test: -------------------------------------------------------------------------------- 1 | #!/bin/bash 2 | # Now running as an unprivileged user with user namespaces enabled in a 3 | # container and required packages installed. Make distributions and test. 4 | 5 | . /etc/os-release 6 | 7 | set -ex 8 | if [[ "$VERSION_ID" = 7* ]]; then 9 | # installing yum-utils for yumdownloader to get fuse2fs fails, skip it 10 | CACHEPAT="/var/lib/cvmfs" 11 | else 12 | truncate -s 6G scratch.img 13 | mkdir -p scratch/shared 14 | /sbin/mkfs.ext3 -F -O ^has_journal -d scratch scratch.img 15 | # for mode 4 16 | export SINGCVMFS_CACHEIMAGE=scratch.img 17 | CACHEPAT="/var/lib/cvmfs.*fuse" 18 | fi 19 | for DIST in default osg egi; do 20 | if [ "$DIST" = egi ] && [[ "$VERSION_ID" != 7* ]]; then 21 | # egi not yet supported for el8 or el9 22 | continue 23 | fi 24 | rm -rf dist /tmp/cvmfsexec 25 | : test makedist 26 | ./makedist $DIST 27 | : test mode 3 28 | ./cvmfsexec atlas.cern.ch -- ls /cvmfs/atlas.cern.ch/repo 29 | : test self-extracting distribution 30 | ./makedist -o /tmp/cvmfsexec 31 | if [ -f scratch.img ]; then 32 | /tmp/cvmfsexec -m $PWD/scratch.img atlas.cern.ch -- ls /cvmfs/atlas.cern.ch/repo /e2fs/lost+found 33 | else 34 | /tmp/cvmfsexec atlas.cern.ch -- ls /cvmfs/atlas.cern.ch/repo 35 | fi 36 | : test mode 1 37 | rm -rf dist/var/lib/cvmfs/shared 38 | ./mountrepo `cd dist/cvmfs; echo *config*` 39 | ./mountrepo atlas.cern.ch 40 | ls dist/cvmfs/atlas.cern.ch/repo 41 | if [[ "$ID" == *suse* ]]; then 42 | # the sle15 cvmfs suse build as of 2.11.5 does not support fuse3 43 | ./umountrepo -a 44 | continue 45 | fi 46 | : test mode 4 47 | if [ ! -d apptainer ]; then 48 | # get singularity or apptainer from oasis cvmfs 49 | ./mountrepo oasis.opensciencegrid.org 50 | if [[ "$VERSION_ID" == 7* ]]; then 51 | APPT=dist/cvmfs/oasis.opensciencegrid.org/mis/singularity/current 52 | else 53 | APPT=dist/cvmfs/oasis.opensciencegrid.org/mis/apptainer/current 54 | fi 55 | mkdir apptainer 56 | cp -r $APPT/`arch` $APPT/bin apptainer 57 | fi 58 | ./umountrepo -a 59 | rm -rf dist /tmp/cvmfsexec 60 | if [ "$ID" = debian ] || [ "$ID" = ubuntu ]; then 61 | # skip singcvmfs test on debian & ubuntu 62 | continue 63 | fi 64 | ./makedist -s $DIST 65 | ./makedist -s -o /tmp/cvmfsexec 66 | SINGCVMFS_REPOSITORIES=atlas.cern.ch PATH=$PATH:$PWD/apptainer/bin \ 67 | ./singcvmfs exec -cip docker://$DOCKER_HUB_URI sh -c \ 68 | "ls /cvmfs/atlas.cern.ch/repo && mount|grep $CACHEPAT" 69 | if [[ "$VERSION_ID" == 8* ]] || [[ "$VERSION_ID" == 9* ]]; then 70 | : try to at least make other supported architecture distributions 71 | for arch in aarch64 ppc64le; do 72 | rm -rf dist /tmp/cvmfsexec 73 | ./makedist -m rhel8-$arch $DIST 74 | ./makedist -o /tmp/cvmfsexec 75 | rm -rf dist /tmp/cvmfsexec 76 | ./makedist -s -m rhel8-$arch $DIST 77 | ./makedist -s -o /tmp/cvmfsexec 78 | done 79 | fi 80 | done 81 | -------------------------------------------------------------------------------- /ci/privileged-run: -------------------------------------------------------------------------------- 1 | #!/bin/bash 2 | # Running in a privileged container. Install required packages and 3 | # switch to an unprivileged user to run the tests. 4 | 5 | set -ex 6 | if [ -f /usr/bin/zypper ]; then 7 | # suse 8 | zypper install -y tar gzip procps openssl-1_1 fuse fuse3 e2fsprogs fuse2fs 9 | elif [ -f /usr/bin/apt ]; then 10 | # debian or ubuntu 11 | apt-get update 12 | apt-get install -y procps curl rpm2cpio cpio fuse3 fuse2fs 13 | else 14 | # rhel 15 | yum install -y procps-ng cpio findutils fuse fuse3 e2fsprogs 16 | if [[ $DOCKER_HUB_URI == *:8 ]] || [[ $DOCKER_HUB_URI == *:9 ]]; then 17 | yum install -y yum-utils 18 | fi 19 | fi 20 | 21 | # because host kernel is Ubuntu 24+, this enables user namespaces 22 | sysctl kernel.apparmor_restrict_unprivileged_userns=0 23 | 24 | # switch to an unprivileged user 25 | useradd -u 1001 --create-home -s /bin/bash testuser 26 | # leave .git as original owner for post job cleanup 27 | chown testuser . 28 | chown -R testuser * 29 | su testuser -c ci/make-and-test 30 | -------------------------------------------------------------------------------- /cvmfs2-wrapper: -------------------------------------------------------------------------------- 1 | #!/bin/bash 2 | # This is used by singcvmfs to execute cvmfs2 inside a container 3 | 4 | 5 | if [ "$1" = "-o" ] && [ "$2" = "debug" ]; then 6 | # This redirect is for the initial output of cvmfs2. Later it 7 | # appends to the same file because of the CVMFS_DEBUGLOG setting. 8 | exec >>/var/log/cvmfs/$3-debug.log 2>&1 9 | if [ "${@:$#}" = "-f" ]; then 10 | # -f is added by singularity >= 3.6; remove it 11 | set -- "${@:1:$(($#-1))}" 12 | fi 13 | exec /usr/bin/cvmfs2 "$@" 14 | fi 15 | exec /usr/bin/cvmfs2 "$@" >/dev/null 2>&1 16 | -------------------------------------------------------------------------------- /cvmfsexec: -------------------------------------------------------------------------------- 1 | #!/bin/bash 2 | # Mount cvmfs repository in a user namespace and change to that space. 3 | # Requires being able to run unshare -rm and either fusermount or 4 | # user namespace fuse mounts (kernel >= 4.18). 5 | # Additional repositories can be mounted from within the command with 6 | # $CVMFSMOUNT and repositories can be umounted with $CVMFSUMOUNT. 7 | # Written by Dave Dykstra September 2019 8 | 9 | #set -x 10 | #PS4='c$$+ ' 11 | 12 | VERSION=4.47 13 | 14 | usage() 15 | { 16 | echo "Usage: cvmfsexec [-vN] [-m e2fs_image] [repo ...] -- [command]" >&2 17 | echo " -v: print current version and exit" >&2 18 | echo " -N: disable the option of nesting [u]mountrepo commands" >&2 19 | echo " -m: mount given ext2/3/4 filesystem image at /e2fs" >&2 20 | exit 1 21 | } 22 | 23 | HERE="$(cd `dirname $0` && pwd)" 24 | 25 | # needed for pivot_root 26 | PATH=$PATH:/usr/sbin 27 | 28 | KERNEL_VERSION="$(uname -r)" 29 | MAJORKERN=${KERNEL_VERSION/.*/} 30 | RESTKERN=${KERNEL_VERSION#$MAJORKERN.} 31 | MINORKERN=${RESTKERN/.*/} 32 | REVKERN=${KERNEL_VERSION#*-} 33 | REVKERN=${REVKERN/.*/} 34 | USERFUSE=false 35 | if [ "$MAJORKERN" -gt 4 ] || [ "$MAJORKERN" -eq 4 -a "$MINORKERN" -ge 18 ]; then 36 | USERFUSE=true 37 | elif [ "$MAJORKERN" -eq 3 -a "$MINORKERN" -eq 10 -a "$REVKERN" -ge 1127 ]; then 38 | # RHEL 7.8+ kernel 39 | USERFUSE=true 40 | fi 41 | 42 | TMPDIR=$(mktemp -d) 43 | trap "rm -rf $TMPDIR" 0 # note that trap does not carry past exec 44 | CMDFIFO1=$TMPDIR/cmd1 45 | WAITFIFO1=$TMPDIR/wait1 46 | CMDFIFO2=$TMPDIR/cmd2 47 | WAITFIFO2=$TMPDIR/wait2 48 | FUNCS=$TMPDIR/funcs 49 | 50 | # create the fifos used for interprocess communication 51 | mkfifo $CMDFIFO1 $WAITFIFO1 $CMDFIFO2 $WAITFIFO2 52 | export CVMFSEXEC_WAITFIFO=$WAITFIFO1 53 | 54 | # bash syntax {NAME}<&N doesn't work on older bashes such as the 55 | # version 3.2.x on macOS Big Sur, and in fact it fails with an error 56 | # message but not an error code, so test for it first to be able to 57 | # gracefully die 58 | 59 | if [ -n "$({TESTX}<&0 2>&1)" ]; then 60 | echo "Cannot assign file descriptors to variables, bash version too old" >&2 61 | exit 1 62 | fi 63 | 64 | # make a copy of stdin fd, for use in '&' and by unshare 65 | exec {STDINCOPYFD}<&0 66 | 67 | # set up standard token path if not already set because the 68 | # authorization helper runs as a fake root user. 69 | if [ -z "$BEARER_TOKEN_FILE" ]; then 70 | export BEARER_TOKEN_FILE="${XDG_RUNTIME_DIR:-/tmp}/bt_u$UID" 71 | fi 72 | 73 | ORIGPWD=$PWD 74 | 75 | NONESTING=false 76 | E2FSIMAGE="" 77 | # can't use OPTIND because it can't distinguish between -- there or missing 78 | NOPTS=0 79 | while getopts "vNm:" OPTION; do 80 | let NOPTS+=1 81 | case $OPTION in 82 | v) echo "$VERSION" 83 | exit 84 | ;; 85 | N) NONESTING=true 86 | ;; 87 | m) E2FSIMAGE=$OPTARG 88 | shift 89 | ;; 90 | \?) usage 91 | ;; 92 | esac 93 | done 94 | shift $NOPTS 95 | 96 | REPOS="" 97 | for ARG; do 98 | if [ "$ARG" == "--" ]; then 99 | break 100 | fi 101 | if [[ " $REPOS " != *" $ARG "* ]]; then 102 | REPOS="$REPOS $ARG" 103 | fi 104 | shift 105 | done 106 | 107 | if [ "$ARG" != "--" ]; then 108 | usage 109 | fi 110 | shift 111 | 112 | # Add the config repo if not already asked for 113 | if [ -n "`find $HERE/dist/etc/cvmfs/default.d -name "*.conf" 2>/dev/null`" ]; then 114 | CONFIG_REPO="`grep -h '^CVMFS_CONFIG_REPOSITORY=' $HERE/dist/etc/cvmfs/default.d/*.conf 2>/dev/null|tail -1|sed 's/^CVMFS_CONFIG_REPOSITORY=//'`" 115 | if [[ " $REPOS " != *" $CONFIG_REPO "* ]]; then 116 | REPOS="$CONFIG_REPO $REPOS" 117 | fi 118 | fi 119 | 120 | MOUNTED_REPOS="" 121 | # function to process mount/umount commands from child processes 122 | proccmd() 123 | { 124 | if [ "$1" = "-n" ]; then 125 | NOTIFY=false 126 | shift 127 | else 128 | NOTIFY=true 129 | fi 130 | REPO="$2" 131 | RET=0 132 | if [ "$1" == MOUNTREPO ]; then 133 | if [[ " $MOUNTED_REPOS " != *" $REPO "* ]]; then 134 | # not already mounted 135 | cd "$HERE" 136 | ./mountrepo "$REPO" 137 | RET=$? 138 | if [ $? == 0 ]; then 139 | if $USERFUSE; then 140 | mkdir -p "/cvmfs/$REPO" 141 | mount --bind "$HERE/dist/cvmfs/$REPO" "/cvmfs/$REPO" 142 | RET=$? 143 | fi 144 | # put new one at the beginning so config repo will 145 | # be unmounted last 146 | MOUNTED_REPOS="$REPO $MOUNTED_REPOS" 147 | fi 148 | cd - >/dev/null 149 | fi 150 | elif [ "$1" == UMOUNTREPO ]; then 151 | if [[ " $MOUNTED_REPOS " == *" $REPO "* ]]; then 152 | # is mounted 153 | if $USERFUSE; then 154 | # first remove the bind mount at /cvmfs 155 | umount "/cvmfs/$REPO" 156 | RET=$? 157 | rmdir "/cvmfs/$REPO" 158 | fi 159 | if [ "$RET" == 0 ]; then 160 | cd "$HERE" 161 | ./umountrepo "$REPO" 162 | RET=$? 163 | MOUNTED_REPOS="`echo " $MOUNTED_REPOS "|sed "s/ $REPO / /"`" 164 | # remove extra blanks 165 | MOUNTED_REPOS="`echo $MOUNTED_REPOS`" 166 | cd - >/dev/null 167 | fi 168 | else 169 | echo "$REPO not mounted" >&2 170 | RET=1 171 | fi 172 | elif [ "$1" == UMOUNTALL ]; then 173 | for R in $MOUNTED_REPOS; do 174 | proccmd -n UMOUNTREPO $R >/dev/null 175 | done 176 | else 177 | echo "Unrecognized command $1" >&2 178 | RET=1 179 | fi 180 | if $NOTIFY; then 181 | echo "$RET" >$CVMFSEXEC_WAITFIFO 182 | fi 183 | } 184 | # this function is needed from within unshare so write it to a file 185 | declare -f proccmd >$FUNCS 186 | 187 | if $USERFUSE; then 188 | if mount|egrep -q " /proc/(sys |driver)"; then 189 | # inside of docker or kubernetes with systempaths "masked" 190 | # or using docker --gpus 191 | UNSHAREOPTS="" 192 | else 193 | # use a separate PID namespace to always clean up fuse processes 194 | UNSHAREOPTS="-pf" 195 | fi 196 | # the fakeroot process will process mount requests 197 | CMDFIFO2=$CMDFIFO1 198 | else 199 | # mount the repositories as the unprivileged user in the 200 | # shared system namespace. 201 | 202 | # mount the repos, keeping track of them for cleanup 203 | cd $HERE 204 | for REPO in $REPOS; do 205 | if ./mountrepo $REPO; then 206 | # put new one at the beginning so config repo will 207 | # be unmounted last 208 | MOUNTED_REPOS="$REPO $MOUNTED_REPOS" 209 | else 210 | RET="$?" 211 | for REPO in $MOUNTED_REPOS; do 212 | ./umountrepo $REPO 213 | done 214 | exit $RET 215 | fi 216 | done 217 | cd $ORIGPWD 218 | 219 | UNSHAREOPTS="--propagation unchanged" 220 | 221 | ( 222 | # This is the background process for accepting mount/umount commands 223 | # from children and for cleaning up on exit 224 | trap "" 1 2 3 15 # ignore ordinary signals 225 | # read from user namespace process and write to fakeroot process 226 | while read -u $CMDINFD CMD PARAM; do 227 | proccmd "$CMD" "$PARAM" 228 | done <&$STDINCOPYFD {STDINCOPYFD}<&- {CMDINFD}<$CMDFIFO1 229 | # do unmounts and cleanup after user command exits 230 | cd $HERE 231 | for REPO in $MOUNTED_REPOS; do 232 | if [ "$REPO" == "$CONFIG_REPO" ]; then 233 | # give a little extra time for the others to exit 234 | sleep 1 235 | fi 236 | ./umountrepo $REPO >/dev/null 237 | done 238 | rm -rf $TMPDIR 239 | ) & 240 | fi 241 | 242 | rm -rf "$HERE/mnt" 243 | 244 | export STDINCOPYFD 245 | 246 | # Note that within the here document, unprotected $ substitutions are 247 | # done by the surrounding shell, and \$ is within the unshare shell 248 | unshare -rm $UNSHAREOPTS /bin/bash /dev/stdin "${@:-$SHELL}" </proc/"\$PARAM"/gid_map 292 | echo "\$(awk '{print \$2; exit}' /proc/self/uid_map) 0 1" >/proc/"\$PARAM"/uid_map 293 | echo "ready" >$WAITFIFO2 294 | elif $USERFUSE; then 295 | proccmd "\$CMD" "\$PARAM" 296 | fi 297 | done <&$STDINCOPYFD {CMDINFD}<$CMDFIFO2 298 | # shutting down 299 | if [ -n "$E2FSIMAGE" ] || ($USERFUSE && [ -z "$UNSHAREOPTS" ]); then 300 | # automatic cleanup doesn't happen in these cases, so unmount all 301 | proccmd -n UMOUNTALL 302 | if [ -n "$E2FSIMAGE" ]; then 303 | # wait a little for fuse processes to exit 304 | umountwait() { 305 | N=0 306 | while [ "\$N" -lt 20 ]; do 307 | if [ -z "\$(ps -e|grep \$1)" ]; then 308 | break 309 | fi 310 | sleep 0.1 311 | let N+=1 312 | done 313 | } 314 | umountwait cvmfs2 315 | umount /e2fs 316 | umountwait fuse2fs 317 | fi 318 | fi 319 | ) & 320 | 321 | # Change to the new root. Would use chroot but it doesn't work. 322 | cd $HERE/mnt 323 | mkdir -p .old-root 324 | pivot_root . .old-root 325 | cd $ORIGPWD 326 | 327 | if $USERFUSE; then 328 | if [ -n "$UNSHAREOPTS" ]; then 329 | # mount a new /proc for the new pid space 330 | mount -t proc proc /proc 331 | RET="\$?" 332 | if [ "\$RET" != 0 ]; then 333 | echo "mount /proc failed" 334 | exit \$RET 335 | fi 336 | fi 337 | 338 | cd $HERE 339 | 340 | if [ "$E2FSIMAGE" != "" ]; then 341 | echo "Mounting $E2FSIMAGE at /e2fs" 342 | mkdir -p /e2fs 343 | PATH=$PATH:$HERE/dist/usr/sbin LD_LIBRARY_PATH=$HERE/dist/usr/lib64:$HERE/dist/usr/lib fuse2fs $E2FSIMAGE /e2fs 344 | fi 345 | 346 | # mount the initial repos 347 | for REPO in $REPOS; do 348 | ./mountrepo \$REPO 349 | RET="\$?" 350 | if [ "\$RET" != 0 ]; then 351 | echo "mountrepo \$REPO failed" 352 | exit \$RET 353 | fi 354 | 355 | mkdir -p /cvmfs/\$REPO 356 | mount --bind $HERE/dist/cvmfs/\$REPO /cvmfs/\$REPO 357 | done 358 | cd - >/dev/null 359 | 360 | else 361 | # map cvmfs repos mounted by parent 362 | mount --rbind $HERE/dist/cvmfs /cvmfs 363 | fi 364 | 365 | export CVMFSEXEC_CMDFD 366 | exec {CVMFSEXEC_CMDFD}>$CMDFIFO1 367 | 368 | if [ -z "$UNSHAREOPTS" ] || [ $USERFUSE = false ]; then 369 | # running without new process namespace, so more cleanup 370 | # needs to be done and our exit needs to wait for the 371 | # background process to finish cleaning up 372 | EXEC="" 373 | elif [ -n "$E2FSIMAGE" ]; then 374 | # fuse2fs complains if this doesn't get unmounted cleanly 375 | EXEC="" 376 | else 377 | EXEC=exec 378 | fi 379 | 380 | # quoting the here document's delimeter makes this nested shell not 381 | # interpret $ substitutions, but the previous one still does 382 | \$EXEC unshare -U /bin/bash /dev/stdin "\${@:-$SHELL}" <<'!EOF-2!' 383 | #set -x 384 | #PS4='c\$$+ ' 385 | # now in the user namespace 386 | 387 | if [ "$CMDFIFO1" == "$CMDFIFO2" ]; then 388 | echo "PID \$$" >&\$CVMFSEXEC_CMDFD 389 | else 390 | # open & close the command fifo, so background process will exit 391 | echo "PID \$$" >$CMDFIFO2 392 | fi 393 | read X <$WAITFIFO2 394 | 395 | if $NONESTING; then 396 | exec {CVMFSEXEC_CMDFD}>&- 397 | unset CVMFSEXEC_CMDFD 398 | unset CVMFSEXEC_WAITFIFO 399 | else 400 | export CVMFSMOUNT="$HERE/mountrepo" 401 | export CVMFSUMOUNT="$HERE/umountrepo" 402 | fi 403 | 404 | if [ \$$ -eq 1 ]; then 405 | # Leave this bash running as PID 1, because most other 406 | # programs won't handle signals & child reaping correctly, 407 | # and also for the cleanup trap because all other 408 | # processes in the namespaces will get a SIGKILL when 409 | # PID 1 exits. 410 | EXEC="" 411 | trap "rm -rf $TMPDIR" 0 412 | trap "" 1 2 3 15 # ignore all ordinary signals 413 | else 414 | EXEC=exec 415 | fi 416 | export -n STDINCOPYFD 417 | \$EXEC "\$@" <&\$STDINCOPYFD {STDINCOPYFD}<&- 418 | !EOF-2! 419 | 420 | RET="\$?" 421 | exec {CVMFSEXEC_CMDFD}>&- 422 | # wait for background process to clean up 423 | wait 424 | exit \$RET 425 | 426 | !EOF-1! 427 | 428 | RET="$?" 429 | # wait for background process to clean up 430 | wait 431 | exit $RET 432 | -------------------------------------------------------------------------------- /makedist: -------------------------------------------------------------------------------- 1 | #!/bin/bash 2 | # 3 | # Create the cvmfs dist directory, downloading the latest rpms from 4 | # the three major sources. 5 | # Written by Dave Dykstra 17 April 2019 6 | # 7 | 8 | SUPPORTEDTYPES="rhel7-x86_64 rhel8-aarch64 rhel8-x86_64 rhel8-ppc64le rhel9-aarch64 rhel9-x86_64 rhel9-ppc64le suse15-x86_64" 9 | REQUIREDCMDS="curl rpm2cpio cpio" 10 | 11 | CURLOPTS="--connect-timeout 5 -Y 125000 -y 10 -LsS" 12 | 13 | supportedtypes() { 14 | typeset LASTDISTRO="" 15 | typeset TYPES="" 16 | typeset TYPE THISDISTRO 17 | for TYPE in $SUPPORTEDTYPES; do 18 | THISDISTRO="${TYPE%-*}" 19 | if [ "$THISDISTRO" != "$LASTDISTRO" ]; then 20 | if [ -n "$TYPES" ]; then 21 | echo "$1$TYPES" >&2 22 | fi 23 | LASTDISTRO="$THISDISTRO" 24 | TYPES="$TYPE" 25 | else 26 | TYPES="$TYPES $TYPE" 27 | fi 28 | done 29 | echo "$1$TYPES" >&2 30 | } 31 | 32 | usage() 33 | { 34 | ( 35 | echo "Usage: makedist [-s] [ -m machinetype ] {osg|egi|default|none}" 36 | echo " makedist [-s] -o " 37 | echo " The first usage creates a distribution in 'dist' directory." 38 | echo " The -m option selects machinetype for the distribution." 39 | echo " The default is the current machine. Supported types:" 40 | supportedtypes " " 41 | echo " Debian and Ubuntu hosts get translated to corresponding rhel types." 42 | echo " The second usage puts 'dist' and cvmfsexec tools into one script with the" 43 | echo " given file name that self extracts and executes cvmfsexec." 44 | echo " After extraction, files are left behind under '.cvmfsexec' in the same" 45 | echo " directory as the script." 46 | echo " The -s option makes both operations work for singcvmfs instead" 47 | echo " of cvmfsexec, and files are left in .singcvmfs" 48 | ) >&2 49 | exit 2 50 | } 51 | 52 | SING=false 53 | MACHTYPE="" 54 | while true; do 55 | if [ "$1" = "-s" ]; then 56 | SING=true 57 | shift 58 | elif [ "$1" = "-m" ]; then 59 | MACHTYPE="$2" 60 | shift 2 61 | else 62 | break 63 | fi 64 | done 65 | 66 | distroname() { 67 | if [ -n "$MACHTYPE" ]; then 68 | echo "$MACHTYPE"|sed 's/[0-9].*//' 69 | elif [ -f /etc/os-release ]; then 70 | source /etc/os-release 71 | case " $ID $ID_LIKE " in 72 | *" rhel "*) echo rhel;; 73 | *" suse "*) echo suse;; 74 | *" ubuntu "*) echo ubuntu;; 75 | *" debian "*) echo debian;; 76 | *) echo "Operating system in /etc/os-release not supported" >&2 77 | exit 2;; 78 | esac 79 | elif [ -f /etc/redhat-release ]; then 80 | echo "rhel" 81 | fi 82 | } 83 | 84 | # return the distroname as encountered in yum package repo URLS, 85 | # i.e https://cvmrepo.web.cern.ch/cvmrepo/yum/cvmfs/EL/9/ 86 | distroname_yum() { 87 | case " $1 " in 88 | *" ubuntu "*) echo EL;; 89 | *" debian "*) echo EL;; 90 | *" rhel "*) echo EL;; 91 | *" suse "*) echo suse;; 92 | *) echo "Distro name $1 not supported" >&2 93 | exit 2;; 94 | esac 95 | } 96 | 97 | distroversion() { 98 | if [ -n "$MACHTYPE" ]; then 99 | echo "$MACHTYPE"|sed 's/^[^0-9]*\([0-9]*\)-.*/\1/' 100 | elif [ -f /etc/os-release ]; then 101 | source /etc/os-release 102 | echo "${VERSION_ID/.*/}" 103 | elif [ -f /etc/redhat-release ]; then 104 | read LINE &2 140 | exit 2 141 | fi 142 | case "$VERS" in 143 | 11) DISTRO=rhel; VERS=8;; 144 | 12) DISTRO=rhel; VERS=9;; 145 | *) echo "debian$VERS not supported, only 11 & 12 are" >&2 146 | exit 2;; 147 | esac 148 | elif [ "$DISTRO" = "ubuntu" ]; then 149 | if $SING; then 150 | echo "ubuntu not supported with -s" >&2 151 | exit 2 152 | fi 153 | case "$VERS" in 154 | 22|24) DISTRO=rhel; VERS=9;; 155 | *) echo "ubuntu$VERS not supported, only 22 & 24 are" >&2 156 | exit 2;; 157 | esac 158 | fi 159 | MACHTYPE=$DISTRO$VERS-$ARCH 160 | fi 161 | 162 | if [[ " $SUPPORTEDTYPES " != *" $MACHTYPE "* ]]; then 163 | echo "$MACHTYPE not a supported machine type" >&2 164 | echo "Supported types are:" >&2 165 | supportedtypes " " >&2 166 | exit 1 167 | fi 168 | 169 | EL=$VERS 170 | MACH=el$EL 171 | if [ "$DISTRO" = "suse" ]; then 172 | EL=8 # we get some suse stuff from rhel8 173 | MACH=sle$VERS 174 | fi 175 | 176 | MISSINGCMDS="" 177 | for CMD in $REQUIREDCMDS; do 178 | if [ -z "$(type -p "$CMD")" ]; then 179 | MISSINGCMDS="$MISSINGCMDS $CMD" 180 | fi 181 | done 182 | if [ -n "$MISSINGCMDS" ]; then 183 | echo "Required command(s)$MISSINGCMDS not found" >&2 184 | exit 2 185 | fi 186 | 187 | HERE="$(cd `dirname $0` && pwd)" 188 | 189 | DIST="$HERE/dist" 190 | 191 | DISTTYPE="" 192 | INCLUDEHELPER=true 193 | case $1 in 194 | -o) 195 | if [ $# != 2 ]; then 196 | usage 197 | fi 198 | BASENAME=cvmfsexec 199 | TOOLS="cvmfsexec mountrepo umountrepo" 200 | SEDOPTS="" 201 | REQUIRES="makedist (without -s)" 202 | if $SING; then 203 | BASENAME=singcvmfs 204 | TOOLS="singcvmfs cvmfs2-wrapper" 205 | SEDOPTS="-e s/cvmfsexec/$BASENAME/" 206 | REQUIRES="makedist -s" 207 | fi 208 | # For now (as of 6-21-23), only require $DIST/.cvmfsexecdist for -s 209 | # mode, so those not using -s don't have to re-make their distribution. 210 | # Eventually this can be changed to always require that file instead 211 | # of $DISTLIB. 212 | HASSING=false 213 | if [ -f $DIST/.cvmfsexecdist ]; then 214 | read X DISTTYPE Y <$DIST/.cvmfsexecdist 215 | if [ "$DISTTYPE" = "sing" ]; then 216 | HASSING=true 217 | fi 218 | fi 219 | DISTLIB=libcvmfs_fuse.so 220 | if ([ ! -f $DIST/usr/lib*/$DISTLIB ] && [ ! -f $DIST/lib*/$DISTLIB ]) \ 221 | || [ $SING != $HASSING ]; then 222 | echo "Must be run from where cvmfs distribution was made by $REQUIRES" >&2 223 | exit 1 224 | fi 225 | sed -e 's/^[ \t]*//' $SEDOPTS >$2 <<'!EOF!' 226 | #!/bin/bash 227 | BASEDIR="$(cd `dirname $0` && pwd)" 228 | BASE="$BASEDIR/.cvmfsexec" 229 | if [ $0 -nt $BASE ]; then 230 | rm -rf $BASE 231 | mkdir $BASE 232 | TAR_START="`awk '/^__TAR_BELOW__/ {print NR + 1; exit 0; }' $0`" 233 | tail -n+$TAR_START $0 | tar -xzf - -C $BASE 234 | fi 235 | exec $BASE/cvmfsexec "$@" 236 | __TAR_BELOW__ 237 | !EOF! 238 | tar --exclude 'dist/var/run/cvmfs/*' --exclude 'dist/var/lib/cvmfs/*' -czvf - -C $HERE $TOOLS dist >>"$2" 239 | chmod +x "$2" 240 | exit 241 | ;; 242 | osg) 243 | if [ $EL -lt 8 ]; then 244 | REL=3.6 245 | EXT="" 246 | else 247 | REL=24-main 248 | EXT="/Packages/c" 249 | fi 250 | REPO=release 251 | BASEURL="https://repo.opensciencegrid.org/osg/$REL/el$EL/$REPO/x86_64$EXT" 252 | BASELIST="$(get_cvmfs_pkg_list $BASEURL)";; 253 | egi) 254 | OS=centos$EL 255 | if [ $EL -gt 8 ]; then 256 | BASEURL="https://repository.egi.eu/sw/production/umd/5/al9/release/x86_64/" 257 | elif [ $EL -eq 7 ]; then 258 | BASEURL="https://repository.egi.eu/sw/production/umd/4/centos7/x86_64/updates" 259 | else 260 | echo "ERROR: unsupported OS for egi! only centos7, almalinux9 supported." >&2 261 | exit 1 262 | fi 263 | BASELIST="$(get_cvmfs_pkg_list $BASEURL)";; 264 | default|none) 265 | INCLUDEHELPER=false 266 | BASEURL="https://cvmrepo.s3.cern.ch/cvmrepo/yum/cvmfs/EL/$EL/x86_64" 267 | # for the listing, we need to query the "s3-website" variant of the s3 url 268 | BASELIST="$(get_cvmfs_pkg_list ${BASEURL/cvmrepo.s3/cvmrepo.s3-website})";; 269 | *) usage;; 270 | esac 271 | DISTTYPE=$1 272 | 273 | 274 | if [ -d $DIST ]; then 275 | echo "$DIST already exists" >&2 276 | exit 1 277 | fi 278 | 279 | SINGMSG="" 280 | if $SING; then 281 | SINGMSG="singcvmfs " 282 | fi 283 | echo "Making $SINGMSG$DISTTYPE distribution for $MACHTYPE" 284 | 285 | getcoprurl() { 286 | if [ ! -f /usr/bin/yumdownloader ]; then 287 | echo "yumdownloader not found, skipping trying to get $1 from copr" >&2 288 | return 289 | fi 290 | typeset TMPF=$(mktemp) 291 | typeset REPONAME=makedist-$1 292 | cat >$TMPF <&2 302 | fi 303 | done 304 | rm -f $TMPF 305 | } 306 | 307 | if [ "$ARCH" != "x86_64" ]; then 308 | # There's no cvmfs-x509-helper yet for non-x86 architectures, and 309 | # we're looking at x86_64 version repositories for the config rpm 310 | INCLUDEHELPER=false 311 | fi 312 | if [ "$DISTTYPE" = egi ] && [ "$EL" = 8 ]; then 313 | echo "egi's UMD does not yet support rhel8" 2>&1 314 | exit 1 315 | fi 316 | 317 | 318 | URLS="" 319 | CVMFSURL="" 320 | CVMFSRPMURL="" 321 | CVMFS_BASEURL_MIRROR1="https://cvmrepo.s3.cern.ch/cvmrepo" 322 | CVMFS_BASEURL_MIRROR2="https://cvmrepo.web.cern.ch/cvmrepo" 323 | CVMFS_BASEURL=$CVMFS_BASEURL_MIRROR1 324 | if [ "$ARCH" = "ppc64le" ]; then 325 | # Grab cvmfs package from copr, using yumdownloader to calculate 326 | # the URL 327 | CVMFSRPMURL="$(getcoprurl cvmfs)" 328 | if [ -z "$CVMFSRPMURL" ]; then 329 | echo "Failed to get $ARCH cvmfs rpm from copr" >&2 330 | exit 1 331 | fi 332 | CVMFSURL="$(dirname $CVMFSRPMURL)" 333 | CVMFSRPMNAME="$(basename $CVMFSRPMURL)" 334 | CVMFSVERSION="`echo "$CVMFSRPMNAME" 's/.*cvmfs-\([^-]*\)-.*/\1/'`" 335 | else 336 | # Get CVMFS package download urls from CERN yum repo ( with possible fallback ) 337 | # but using the version number found from the base distribution 338 | DISTRO_YUM="`distroname_yum $DISTRO`" 339 | CVMFSURL="$CVMFS_BASEURL/yum/cvmfs/$DISTRO_YUM/$VERS/$ARCH" 340 | CVMFSVERSION="$(get_cvmfs_latest_version_from_pkg_list "$BASELIST")" 341 | if [ -z "CVMFSVERSION" ]; then 342 | echo "WARN: Couldn't find package listing in $BASEURL, switching to backup.." >&2 343 | CVMFS_BASEURL="$CVMFS_BASE_URL_MIRROR2" 344 | CVMFSURL="$CVMFS_BASEURL/yum/cvmfs/$DISTRO_YUM/$VERS/$ARCH" 345 | CVMFS_BASELIST="$(get_cvmfs_pkg_list $CVMFSURL)" 346 | CVMFSVERSION="$(get_cvmfs_latest_version_from_pkg_list "$CVMFS_BASELIST")" 347 | if [ -z "CVMFSVERSION" ]; then 348 | echo "ERROR: Couldn't find package listing in mirror $CVMFS_BASEURL, and no mirrors left! " >&2 349 | exit 1 350 | fi 351 | fi 352 | CVMFSRPMNAME="cvmfs-$CVMFSVERSION-1.$MACH.$ARCH.rpm" 353 | CVMFSRPMURL="$CVMFSURL/$CVMFSRPMNAME" 354 | fi 355 | 356 | CVMFSRPMURL_LIBS="" 357 | MINORVERSION="`echo "$CVMFSVERSION"|cut -d. -f2`" 358 | if [ "$MINORVERSION" -ge 10 ]; then 359 | # include cvmfs-libs 360 | CVMFSRPMURL_LIBS="$CVMFSURL/`echo $CVMFSRPMNAME|sed 's/cvmfs-/cvmfs-libs-/'`" 361 | fi 362 | 363 | URLS="$URLS $CVMFSRPMURL $CVMFSRPMURL_LIBS" 364 | 365 | if [ "$DISTTYPE" != "none" ]; then 366 | if [ "$DISTTYPE" != "default" ]; then 367 | CONFIGREPO="`echo "$BASELIST"|grep "^cvmfs-config-$DISTTYPE-[0-9]"|tail -1`" 368 | if [ -z "$CONFIGREPO" ]; then 369 | echo "cvmfs-config not found at $BASEURL!" >&2 370 | exit 1 371 | fi 372 | URLS="$URLS $BASEURL/$CONFIGREPO" 373 | else 374 | URLS="$URLS $CVMFS_BASEURL/yum/cvmfs-config-default-latest.noarch.rpm" 375 | fi 376 | fi 377 | 378 | # return the url of the latest version of a package given 379 | # $1 - base repository url 380 | # $2 - package name 381 | # $3 - true if base url has one-character subdirectories, otherwise false 382 | LATESTRETRY=0 383 | latesturl() 384 | { 385 | typeset URL="$1" 386 | if [ "$3" = true ]; then 387 | URL="${URL%/}" 388 | URL="$URL/${2:0:1}" 389 | fi 390 | typeset PKG="$(curl $CURLOPTS "$URL"|grep ${2}-[0-9].*$ARCH|grep -v 32bit|grep -v mirrorlist|tail -1|sed 's/.*href="//;s/".*//')" 391 | if [ -n "$PKG" ]; then 392 | LATESTRETRY=0 393 | echo "$URL/$PKG" 394 | elif [ "$LATESTRETRY" -lt 3 ]; then 395 | let LATESTRETRY=$LATESTRETRY+1 396 | latesturl "$URL" "$2" false 397 | else 398 | LATESTRETRY=0 399 | return 1 400 | fi 401 | } 402 | 403 | if $INCLUDEHELPER; then 404 | HELPER="`echo "$BASELIST"|grep "^cvmfs-x509-helper-[0-9]"|tail -1`" 405 | if [ -z "$HELPER" ]; then 406 | echo "cvmfs-x509-helper not found at $BASEURL!" >&2 407 | exit 1 408 | fi 409 | URLS="$URLS $BASEURL/$HELPER" 410 | if [ "$EL" -lt 8 ]; then 411 | EPELURL="https://archives.fedoraproject.org/pub/archive/epel/$EL/$ARCH/Packages" 412 | else 413 | EPELURL="https://download.fedoraproject.org/pub/epel/$EL/Everything/$ARCH/Packages" 414 | fi 415 | URL="`latesturl $EPELURL scitokens-cpp true`" 416 | if [ -z "$URL" ]; then 417 | echo "No scitokens-cpp package found from $EPELURL" >&2 418 | exit 1 419 | fi 420 | URLS="$URLS $URL" 421 | fi 422 | 423 | FUSESUBDIR=false 424 | CVMFSFUSE3URL="$CVMFSURL/`echo $CVMFSRPMNAME|sed 's/cvmfs-/cvmfs-fuse3-/'`" 425 | if $SING; then 426 | URLS="$URLS $CVMFSFUSE3URL" 427 | if [ "$EL" -lt 8 ]; then 428 | FUSEURL="https://archives.fedoraproject.org/pub/archive/epel/$EL/$ARCH/Packages" 429 | FUSESUBDIR=true 430 | elif [ "$EL" -eq 8 ]; then 431 | FUSEURL="https://repo.almalinux.org/almalinux/$EL/BaseOS/$ARCH/os/Packages" 432 | else 433 | FUSEURL="https://repo.almalinux.org/almalinux/$EL/AppStream/$ARCH/os/Packages" 434 | fi 435 | URL="`latesturl $FUSEURL fuse3-libs $FUSESUBDIR`" 436 | if [ -z "$URL" ]; then 437 | echo "No fuse3-libs package found from $FUSEURL" >&2 438 | exit 1 439 | fi 440 | URLS="$URLS $URL" 441 | else 442 | if [ "$DISTRO" = suse ]; then 443 | FUSEURL="https://download.opensuse.org/distribution/openSUSE-stable/repo/oss/x86_64" 444 | FUSELIB=libfuse2 445 | else 446 | if [ "$EL" -lt 8 ]; then 447 | FUSEURL="https://vault.centos.org/centos/$EL/os/$ARCH/Packages/" 448 | elif [ "$EL" -eq 8 ]; then 449 | FUSEURL="https://repo.almalinux.org/almalinux/$EL/BaseOS/$ARCH/os/Packages" 450 | else 451 | FUSEURL="https://repo.almalinux.org/almalinux/$EL/AppStream/$ARCH/os/Packages" 452 | fi 453 | if [ "$EL" -lt 9 ]; then 454 | FUSELIB=fuse-libs 455 | else 456 | FUSELIB=fuse3-libs 457 | URLS="$URLS $CVMFSFUSE3URL" 458 | fi 459 | fi 460 | URL="`latesturl $FUSEURL $FUSELIB $FUSESUBDIR`" 461 | if [ -z "$URL" ]; then 462 | echo "No $FUSELIB package found from $FUSEURL" >&2 463 | exit 1 464 | fi 465 | URLS="$URLS $URL" 466 | fi 467 | 468 | if [ "$EL" -eq 7 ]; then 469 | # add fuse2fs only on EL7, it is standard elsewhere 470 | URLS="$URLS $(getcoprurl fuse2fs)" 471 | fi 472 | 473 | mkdir -p $DIST/etc 474 | cd $DIST 475 | 476 | # make an os-release subset for repository configs that need that, 477 | # in particular for osgstorage-auth.conf 478 | cat >etc/os-release <&2 490 | exit 1 491 | fi 492 | echo "failed, retrying ..." >&2 493 | done 494 | done 495 | find * -type l|while read LINK; do 496 | LINKDEST="`readlink $LINK`" 497 | if [ "${LINKDEST:0:1}" = "/" ]; then 498 | # turn full path symlink target into relative path 499 | NEWDEST="$(echo $(dirname $LINK)|sed 's,[^/]*,..,g')$LINKDEST" 500 | echo "$LINK -> $NEWDEST" 501 | rm -f $LINK 502 | ln -s $NEWDEST $LINK 503 | fi 504 | done 505 | 506 | echo "./etc/cvmfs/default.local" 507 | (echo 'CVMFS_HTTP_PROXY="auto;DIRECT"' 508 | if [ "$DISTTYPE" = osg ]; then 509 | WLCGPACS="http://cernvm-wpad.fnal.gov/wpad.dat;http://cernvm-wpad.cern.ch/wpad.dat" 510 | else 511 | WLCGPACS="http://cernvm-wpad.cern.ch/wpad.dat;http://cernvm-wpad.fnal.gov/wpad.dat" 512 | fi 513 | echo "CVMFS_PAC_URLS=\"http://grid-wpad/wpad.dat;http://wpad/wpad.dat;$WLCGPACS\"" 514 | ) >etc/cvmfs/default.local 515 | 516 | if $INCLUDEHELPER; then 517 | echo "Wrapping authz helper commands" 518 | HERE=$PWD 519 | cd usr/libexec/cvmfs/authz 520 | cat >.wrapper <<'!EOF!' 521 | #!/bin/bash 522 | BASEME=${0##*/} 523 | HERE="${0%/*}" 524 | if [[ "$HERE" != /* ]]; then 525 | HERE="$PWD/$HERE" 526 | fi 527 | PARENT="${HERE%/*}" 528 | GGPARENT="${PARENT%/*/*}" 529 | if [ -n "$LD_LIBRARY_PATH" ]; then 530 | LD_LIBRARY_PATH=":$LD_LIBRARY_PATH" 531 | fi 532 | LD_LIBRARY_PATH=$GGPARENT/lib64:$GGPARENT/lib$LD_LIBRARY_PATH exec -a $0 $HERE/.$BASEME "$@" 533 | !EOF! 534 | chmod +x .wrapper 535 | for CMD in *; do 536 | mv $CMD .$CMD 537 | ln -s .wrapper $CMD 538 | done 539 | cd $HERE 540 | fi 541 | 542 | echo "./.cvmfsexecdist" 543 | ( 544 | if $SING; then 545 | echo "disttype: sing" 546 | else 547 | echo "disttype: standard" 548 | fi 549 | echo "machtype: $MACHTYPE" 550 | ) >.cvmfsexecdist 551 | -------------------------------------------------------------------------------- /mountrepo: -------------------------------------------------------------------------------- 1 | #!/bin/bash 2 | # 3 | # Mount a cvmfs repository as an unprivileged user. 4 | # Works with fusermount or with a kernel (>= 4.18) that supports mounting 5 | # fuse repositories in unprivileged "fakeroot" namespaces. 6 | # Mounts in cvmfs subdirectory of the directory where the command is found. 7 | # Written by Dave Dykstra 17 April 2019 8 | # 9 | 10 | usage() 11 | { 12 | echo "Usage: mountrepo repo.name" >&2 13 | exit 1 14 | } 15 | 16 | if [ $# != 1 ]; then 17 | usage 18 | fi 19 | 20 | REPO="$1" 21 | 22 | if [ -n "$CVMFSEXEC_CMDFD" ] && [ -n "$CVMFSEXEC_WAITFIFO" ]; then 23 | # this is within cvmfsexec, requesting to mount another repo 24 | if [ -z "$CVMFSMOUNT" ]; then 25 | echo "$0: mount within cvmfsexec only works through \$CVMFSMOUNT interface" >&2 26 | exit 1 27 | fi 28 | 29 | # Send command to the "parent" process still outside the namespace. 30 | # "Parent" is in quotes because the linux process tree gets reversed and 31 | # it is actually a linux child. It is a parent environment-wise though. 32 | set -e 33 | echo MOUNTREPO $REPO >&$CVMFSEXEC_CMDFD 34 | exec {CVMFSEXEC_CMDFD}>&- # close it, no longer needed 35 | # wait until that process is finished mounting 36 | read RET <$CVMFSEXEC_WAITFIFO 37 | exit $RET 38 | fi 39 | 40 | HERE="$(cd `dirname $0` && pwd)" 41 | DIST="$HERE/dist" 42 | 43 | if [ ! -f $DIST/usr/bin/cvmfs2 ] || [ ! -f $DIST/etc/cvmfs/default.conf ]; then 44 | echo "$DIST should be rpm2cpio of cvmfs rpm" >&2 45 | exit 1 46 | fi 47 | 48 | CONFFILE="`mktemp`" 49 | trap "rm -f $CONFFILE" 0 50 | 51 | # recursively substitute a ". " or "source " with the contents of the 52 | # sourced file. 53 | procsource() 54 | { 55 | for FILE; do 56 | while read LINE; do 57 | case "$LINE" in 58 | ". "*) eval procsource "${LINE/. /}";; 59 | "source "*) eval procsource "${LINE/source /}";; 60 | *) echo "$LINE";; 61 | esac 62 | done <$FILE 63 | done 64 | } 65 | 66 | # relocate the given files and process them for sourced files the same way 67 | # that cvmfs does 68 | relocate() 69 | { 70 | cd ${1%/*} 71 | # do /var first in case $DIST begins with /var 72 | procsource $* 2>/dev/null | \ 73 | sed -e "s,^\([^/]*\)/var,\1$DIST/var," \ 74 | -e "s,^\([^/]*\)/etc,\1$DIST/etc," \ 75 | -e "s,^\([^/]*\)/cvmfs$,\1$DIST/cvmfs," \ 76 | -e "s,^\([^/]*\)/cvmfs/,\1$DIST/cvmfs/," 77 | cd - >/dev/null 78 | } 79 | 80 | DOMAIN="`echo "$REPO"|cut -d. -f2-`" 81 | ( 82 | DEFD_FILES="`find $DIST/etc/cvmfs/default.d -name "*.conf" 2>/dev/null`" 83 | if [ -n "$DEFD_FILES" ]; then 84 | CONFIG_REPO="`sed -n 's/^CVMFS_CONFIG_REPOSITORY=//p' $DIST/etc/cvmfs/default.d/*.conf`" 85 | fi 86 | # these are used in some configuration repository includes, set them 87 | # for procsource 88 | CVMFS_CONFIG_REPOSITORY=$CONFIG_REPO 89 | CVMFS_MOUNT_DIR=$DIST/cvmfs 90 | 91 | relocate $DIST/etc/cvmfs/default.conf 92 | if [ -n "$DEFD_FILES" ]; then 93 | relocate $DIST/etc/cvmfs/default.d/*.conf 94 | fi 95 | if [ -n "$CONFIG_REPO" -a "$REPO" != "$CONFIG_REPO" ]; then 96 | relocate $DIST/cvmfs/$CONFIG_REPO/etc/cvmfs/default.conf 97 | fi 98 | 99 | DEFLOCAL=$DIST/etc/cvmfs/default.local 100 | relocate $DEFLOCAL 101 | # set some defaults if they weren't already in the dist's default.local 102 | if ! grep -q "^CVMFS_NFILES=" $DEFLOCAL 2>/dev/null; then 103 | echo "CVMFS_NFILES=`ulimit -Hn`" 104 | fi 105 | if ! grep -q "^CVMFS_USYSLOG=" $DEFLOCAL 2>/dev/null; then 106 | mkdir -p $HERE/log 107 | echo "CVMFS_USYSLOG=$HERE/log/$REPO.log" 108 | fi 109 | if ! grep -q "^CVMFS_CACHE_BASE=" $DEFLOCAL 2>/dev/null && [ -d /e2fs ]; then 110 | mkdir -p /e2fs/cvmfscache 111 | echo "CVMFS_CACHE_BASE=/e2fs/cvmfscache" 112 | fi 113 | 114 | if [ -n "$CONFIG_REPO" -a "$REPO" != "$CONFIG_REPO" ]; then 115 | relocate $DIST/cvmfs/$CONFIG_REPO/etc/cvmfs/domain.d/$DOMAIN.conf 116 | fi 117 | relocate $DIST/etc/cvmfs/domain.d/$DOMAIN.conf 118 | relocate $DIST/etc/cvmfs/domain.d/$DOMAIN.local 119 | if [ -n "$CONFIG_REPO" -a "$REPO" != "$CONFIG_REPO" ]; then 120 | REPOCONF=$DIST/cvmfs/$CONFIG_REPO/etc/cvmfs/config.d/$REPO.conf 121 | if [ "$REPO" = oasis.opensciencegrid.org ]; then 122 | # OASIS_CERTIFICATES is one special variable we do not want relocated 123 | relocate $REPOCONF | sed 's,^\(OASIS_CERTIFICATES\)=.[^/]*,\1=/cvmfs,' 124 | else 125 | relocate $REPOCONF 126 | fi 127 | fi 128 | relocate $DIST/etc/cvmfs/config.d/$REPO.conf 129 | relocate $DIST/etc/cvmfs/config.d/$REPO.local 130 | 131 | # this is for finding an authz helper 132 | echo CVMFS_AUTHZ_CVMFS_DIST=$DIST 133 | 134 | ) > $CONFFILE 135 | 136 | OPTS="" 137 | if grep -q ^CVMFS_DEBUGLOG=. $CONFFILE; then 138 | OPTS="$OPTS,debug" 139 | fi 140 | 141 | mkdir -p $DIST/var/run/cvmfs 142 | mkdir -p $DIST/cvmfs/$REPO 143 | if [ -f $DIST/usr/lib/libcvmfs_fuse.so ]; then 144 | LPATH=$DIST/usr/lib 145 | LDPATH=$LPATH 146 | if [ ! -f $LPATH/libfuse.so.2 ]; then 147 | # for el6 148 | LDPATH=$LPATH:$DIST/lib 149 | fi 150 | else 151 | LPATH=$DIST/usr/lib64 152 | LDPATH=$LPATH 153 | if [ ! -f $LPATH/libfuse.so.2 ]; then 154 | # for el6 155 | LDPATH=$LPATH:$DIST/lib64 156 | fi 157 | fi 158 | LD_LIBRARY_PATH=$LDPATH CVMFS_LIBRARY_PATH=$LPATH $DIST/usr/bin/cvmfs2 -o config=$CONFFILE$OPTS $REPO $DIST/cvmfs/$REPO 159 | -------------------------------------------------------------------------------- /singcvmfs: -------------------------------------------------------------------------------- 1 | #!/bin/bash 2 | # Run a singularity container including cvmfs repositories mounted 3 | # with the singularity --fusemount option. 4 | # Written by Dave Dykstra March 2020 5 | 6 | VERSION=4.47 7 | 8 | ME="`basename $0`" 9 | 10 | usage() 11 | { 12 | cat <&2 48 | 49 | HERE="$(cd `dirname $0` && pwd)" 50 | 51 | ORIGPWD=$PWD 52 | 53 | if [ "$1" = "-V" ]; then 54 | echo "$VERSION" 55 | exit 56 | fi 57 | 58 | if [ ! -f $HERE/dist/usr/lib*/libcvmfs_fuse3.so ]; then 59 | echo "$ME: Must be run from where cvmfs distribution was made by 'makedist -s'" >&2 60 | exit 1 61 | fi 62 | 63 | if [ -z "$SINGCVMFS_REPOSITORIES" ]; then 64 | echo "$ME: SINGCVMFS_REPOSITORIES not set" >&2 65 | usage 66 | exit 1 67 | fi 68 | 69 | REPOS="$SINGCVMFS_REPOSITORIES" 70 | # Add the config repo if not already asked for 71 | CONFIG_REPO="`grep -h '^CVMFS_CONFIG_REPOSITORY=' $HERE/dist/etc/cvmfs/default.d/*.conf 2>/dev/null|tail -1|sed 's/^CVMFS_CONFIG_REPOSITORY=//'`" 72 | if [[ ",$REPOS," != *",$CONFIG_REPO,"* ]]; then 73 | REPOS="$CONFIG_REPO,$REPOS" 74 | fi 75 | 76 | CVMFSDEBUG="" 77 | EXEC=exec 78 | DEBUGCONF=$HERE/dist/etc/cvmfs/default.d/00-debug.conf 79 | if [ "$SINGCVMFS_LOGLEVEL" = "debug" ]; then 80 | CVMFSDEBUG="-o debug" 81 | echo "CVMFS_DEBUGLOG=/var/log/cvmfs/@fqrn@-debug.log" >$DEBUGCONF 82 | # would rather not leave this around because it interferes with 83 | # use of cvmfsexec in same directory. 84 | EXEC="" 85 | trap "rm -f $DEBUGCONF" 0 86 | else 87 | rm -f $DEBUGCONF 88 | fi 89 | 90 | declare -a MOUNT_ARGS 91 | for R in ${REPOS//,/ }; do 92 | MOUNT_ARGS+=(--fusemount "\"container:cvmfs2-wrapper $CVMFSDEBUG $R /cvmfs/$R\"") 93 | done 94 | if [ -n "$APPTAINER_BINDPATH" ]; then 95 | SINGULARITY_BINDPATH="$APPTAINER_BINDPATH" 96 | fi 97 | SINGULARITY_BINDPATH="$SINGULARITY_BINDPATH,$HERE/cvmfs2-wrapper:/usr/bin/cvmfs2-wrapper" 98 | 99 | cd $HERE/dist 100 | 101 | if [ -n "$SINGCVMFS_OPTSFILE" ]; then 102 | cp $SINGCVMFS_OPTSFILE etc/cvmfs/default.local 103 | fi 104 | 105 | echo "CVMFS_NFILES=`ulimit -Hn`" >etc/cvmfs/default.d/00-nfiles.conf 106 | echo "CVMFS_USYSLOG=/var/log/cvmfs/@fqrn@.log" >etc/cvmfs/default.d/00-usyslog.conf 107 | if [ -n "$SINGCVMFS_LOGDIR" ]; then 108 | LOGDIR=$SINGCVMFS_LOGDIR 109 | else 110 | LOGDIR=$HERE/log 111 | fi 112 | mkdir -p $LOGDIR 113 | SINGULARITY_BINDPATH="$SINGULARITY_BINDPATH,$LOGDIR:/var/log/cvmfs" 114 | 115 | for P in `find * ! -type d ! -path '*/doc/*' ! -path 'var/lib/cvmfs/*'| \ 116 | sed 's,/cvmfs/.*,/cvmfs,'|uniq`; do 117 | SINGULARITY_BINDPATH="$SINGULARITY_BINDPATH,$PWD/$P:/$P" 118 | done 119 | SINGULARITY_BINDPATH="${SINGULARITY_BINDPATH#,}" # remove leading comma 120 | export SINGULARITY_BINDPATH 121 | export APPTAINER_BINDPATH="$SINGULARITY_BINDPATH" 122 | 123 | CACHEBIND="" 124 | if [ -n "$SINGCVMFS_CACHEIMAGE" ]; then 125 | CACHEBIND="$SINGCVMFS_CACHEIMAGE:/var/lib/cvmfs:image-src=${SINGCVMFS_CACHEDIR:-/}" 126 | else 127 | CACHEBIND="${SINGCVMFS_CACHEDIR:-$PWD/var/lib/cvmfs}:/var/lib/cvmfs" 128 | fi 129 | 130 | cd $ORIGPWD 131 | 132 | SINGGLOBALOPTS="" 133 | while [ $# -gt 0 ]; do 134 | if [[ "$1" = -* ]]; then 135 | SINGGLOBALOPTS="$SINGGLOBALOPTS $1" 136 | shift 137 | else 138 | break 139 | fi 140 | done 141 | 142 | SINGCMD="" 143 | SINGINSTCMD="" 144 | case "$1" in 145 | version) 146 | exec singularity $SINGGLOBALOPTS "$@" 147 | ;; 148 | version|exec|run|shell) 149 | SINGCMD="$1" 150 | shift 151 | SINGCVMFS_IMAGE="" # just in case it is set 152 | ;; 153 | instance) 154 | SINGCMD="$1" 155 | shift 156 | # consume subcommand for instance 157 | SINGINSTCMD=$1 158 | shift 159 | SINGCVMFS_IMAGE="" # just in case it is set 160 | ;; 161 | *) if [ -z "$SINGCVMFS_IMAGE" ]; then 162 | echo "$ME: SINGCVMFS_IMAGE not set" >&2 163 | usage 164 | exit 1 165 | fi 166 | SINGCMD=run 167 | ;; 168 | esac 169 | 170 | if [ "$SINGCMD" = instance -a "$SINGINSTCMD" != start ]; 171 | then 172 | $EXEC singularity $SINGGLOBALOPTS $SINGCMD $SINGINSTCMD "$@" 173 | else 174 | $EXEC singularity $SINGGLOBALOPTS $SINGCMD $SINGINSTCMD \ 175 | -S /var/run/cvmfs -B $CACHEBIND \ 176 | "${MOUNT_ARGS[@]}" ${SINGCVMFS_SINGOPTS[@]} $SINGCVMFS_IMAGE "$@" 177 | fi 178 | 179 | -------------------------------------------------------------------------------- /umountrepo: -------------------------------------------------------------------------------- 1 | #!/bin/bash 2 | # 3 | # unmount cvmfs repositories that were mounted with mountrepo 4 | # Written by Dave Dykstra 17 April 2019 5 | # 6 | 7 | 8 | usage() 9 | { 10 | echo "Usage: umountrepo [-z] {repo.name|-a}" >&2 11 | exit 1 12 | } 13 | 14 | LAZY=false 15 | if [ "$1" = "-z" ]; then 16 | LAZY=true 17 | shift 18 | fi 19 | 20 | if [ $# != 1 ]; then 21 | usage 22 | fi 23 | 24 | if [ -n "$CVMFSEXEC_CMDFD" ] && [ -n "$CVMFSEXEC_WAITFIFO" ]; then 25 | # this is within cvmfsexec, requesting to umount a repo 26 | if [ -z "$CVMFSUMOUNT" ]; then 27 | echo "$0: umount within cvmfsexec only works through \$CVMFSUMOUNT interface" >&2 28 | exit 1 29 | fi 30 | if $LAZY; then 31 | echo "$0: lazy umount not supported within cvmfsexec" >&2 32 | exit 1 33 | fi 34 | if [ "$1" == "-a" ]; then 35 | echo "$0: umount within cvmfsexec only works with one repo" >&2 36 | exit 1 37 | fi 38 | REPO="$1" 39 | 40 | # Send command to the "parent" process still outside the namespace. 41 | # "Parent" is in quotes because the linux process tree gets reversed and 42 | # it is actually a linux child. It is a parent environment-wise though. 43 | echo UMOUNTREPO $REPO >&$CVMFSEXEC_CMDFD 44 | exec {CVMFSEXEC_CMDFD}>&- # close it, no longer needed 45 | # wait until that process is finished mounting 46 | read RET <$CVMFSEXEC_WAITFIFO 47 | exit $RET 48 | fi 49 | 50 | 51 | HERE="$(cd `dirname $0` && pwd)" 52 | DIST="$HERE/dist" 53 | 54 | if [ "$1" = "-a" ]; then 55 | set -- `mount|grep " $DIST"|awk '{print $3}'` 56 | else 57 | set -- $DIST/cvmfs/$1 58 | fi 59 | 60 | if [ "`id -u`" == 0 ]; then 61 | # most likely this is actually a "fake" root 62 | ISROOT=true 63 | else 64 | ISROOT=false 65 | fi 66 | 67 | for REPO; do 68 | if $LAZY; then 69 | echo "Lazily unmounting $REPO" 70 | if $ISROOT; then 71 | umount -l $REPO 72 | else 73 | fusermount -uz $REPO 74 | fi 75 | else 76 | echo "Unmounting $REPO" 77 | if $ISROOT; then 78 | umount $REPO 79 | else 80 | fusermount -u $REPO 81 | fi 82 | rmdir $REPO 83 | fi 84 | done 85 | --------------------------------------------------------------------------------