Mercurial > hgrepos > FreeBSD > ports > sysutils > local-bsdtools
comparison sbin/fzfs @ 500:7d498093d4c2
fzfs: Try to unmount filesystems that have been mounted by this tool when an error occurs
| author | Franz Glasner <fzglas.hg@dom66.de> |
|---|---|
| date | Fri, 30 Aug 2024 18:50:12 +0200 |
| parents | 46406503a635 |
| children | 7d08fd78775c |
comparison
equal
deleted
inserted
replaced
| 499:562e630afb25 | 500:7d498093d4c2 |
|---|---|
| 41 ' | 41 ' |
| 42 | 42 |
| 43 | 43 |
| 44 _p_datadir="$(dirname "$0")"/../share/local-bsdtools | 44 _p_datadir="$(dirname "$0")"/../share/local-bsdtools |
| 45 . "${_p_datadir}/common.subr" | 45 . "${_p_datadir}/common.subr" |
| 46 . "${_p_datadir}/array.sh" | |
| 46 | 47 |
| 47 | 48 |
| 48 # | 49 # |
| 49 #: Implementation of the "mount" command. | 50 #: Implementation of the "mount" command. |
| 50 #: | 51 #: |
| 121 _rootds_mountpoint_prefix="${_rootds_mountpoint}/" | 122 _rootds_mountpoint_prefix="${_rootds_mountpoint}/" |
| 122 fi | 123 fi |
| 123 | 124 |
| 124 zfs list -H -o name,mountpoint,canmount,mounted -s mountpoint -t filesystem -r "${_dsname}" \ | 125 zfs list -H -o name,mountpoint,canmount,mounted -s mountpoint -t filesystem -r "${_dsname}" \ |
| 125 | { | 126 | { |
| 127 | |
| 128 # | |
| 129 # _mounted_datasets is an array of ZFS datasets that have been | |
| 130 # mounted by this routine and should be unmounted on errors | |
| 131 # -- if possible. | |
| 132 # | |
| 133 array_create _mounted_datasets | |
| 134 | |
| 126 while IFS=$'\t' read -r _name _mp _canmount _mounted ; do | 135 while IFS=$'\t' read -r _name _mp _canmount _mounted ; do |
| 127 # Skip filesystems that are already mounted | 136 # Skip filesystems that are already mounted |
| 128 [ "${_mounted}" = "yes" ] && continue | 137 [ "${_mounted}" = "yes" ] && continue |
| 129 # Skip filesystems that must not be mounted | 138 # Skip filesystems that must not be mounted |
| 130 [ "${_canmount}" = "off" ] && continue | 139 [ "${_canmount}" = "off" ] && continue |
| 149 # filesystem mount is just a single slash. | 158 # filesystem mount is just a single slash. |
| 150 # | 159 # |
| 151 if [ "${_mp}" = "${_rootds_mountpoint}" ]; then | 160 if [ "${_mp}" = "${_rootds_mountpoint}" ]; then |
| 152 if [ "${_name}" != "${_dsname}" ]; then | 161 if [ "${_name}" != "${_dsname}" ]; then |
| 153 echo "ERROR: child dataset mounts over root dataset" >&2 | 162 echo "ERROR: child dataset mounts over root dataset" >&2 |
| 163 _umount_datasets _mounted_datasets || true | |
| 154 return 1 | 164 return 1 |
| 155 fi | 165 fi |
| 156 _relative_mp="" | 166 _relative_mp="" |
| 157 _real_mp="${_mountpoint}" | 167 _real_mp="${_mountpoint}" |
| 158 else | 168 else |
| 159 _relative_mp="${_mp#${_rootds_mountpoint_prefix}}" | 169 _relative_mp="${_mp#${_rootds_mountpoint_prefix}}" |
| 160 # Eventually remove a trailing slash | 170 # Eventually remove a trailing slash |
| 161 _relative_mp="${_relative_mp%/}" | 171 _relative_mp="${_relative_mp%/}" |
| 162 if [ -z "${_relative_mp}" ]; then | 172 if [ -z "${_relative_mp}" ]; then |
| 163 echo "ERROR: got an empty relative mountpoint in child" >&2 | 173 echo "ERROR: got an empty relative mountpoint in child" >&2 |
| 174 _umount_datasets _mounted_datasets || true | |
| 164 return 1 | 175 return 1 |
| 165 fi | 176 fi |
| 166 # The real effective full mountpoint | 177 # The real effective full mountpoint |
| 167 _real_mp="${_mountpoint}/${_relative_mp}" | 178 _real_mp="${_mountpoint}/${_relative_mp}" |
| 168 fi | 179 fi |
| 173 # is given. | 184 # is given. |
| 174 # | 185 # |
| 175 if [ "${_opt_mount_natural}" = "yes" ]; then | 186 if [ "${_opt_mount_natural}" = "yes" ]; then |
| 176 if [ "${_real_mp}" != "${_mp}" ]; then | 187 if [ "${_real_mp}" != "${_mp}" ]; then |
| 177 echo "ERROR: mountpoint mismatch" >&2 | 188 echo "ERROR: mountpoint mismatch" >&2 |
| 189 _umount_datasets _mounted_datasets || true | |
| 178 return 1 | 190 return 1 |
| 179 fi | 191 fi |
| 180 fi | 192 fi |
| 181 | 193 |
| 182 if [ "${_opt_dry_run}" = "yes" ]; then | 194 if [ "${_opt_dry_run}" = "yes" ]; then |
| 183 echo "Would mount ${_name} on ${_real_mp}" | 195 echo "Would mount ${_name} on ${_real_mp}" |
| 184 else | 196 else |
| 185 mkdir -p "${_real_mp}" 1> /dev/null 2> /dev/null || \ | 197 mkdir -p "${_real_mp}" 1> /dev/null 2> /dev/null || \ |
| 186 { echo "ERROR: cannot create mountpoint ${_real_mp}" >&2; return 1; } | 198 { echo "ERROR: cannot create mountpoint ${_real_mp}" >&2; _umount_datasets _mounted_datasets || true; return 1; } |
| 187 echo "Mounting ${_name} on ${_real_mp}" | 199 echo "Mounting ${_name} on ${_real_mp}" |
| 188 mount -t zfs "${_name}" "${_real_mp}" || return 1 | 200 if mount -t zfs "${_name}" "${_real_mp}"; then |
| 201 array_append _mounted_datasets "${_name}" | |
| 202 else | |
| 203 _umount_datasets _mounted_datasets || true | |
| 204 return 1 | |
| 205 fi | |
| 189 fi | 206 fi |
| 190 ;; | 207 ;; |
| 191 *) | 208 *) |
| 192 if [ "${_opt_mount_outside}" = "yes" ]; then | 209 if [ "${_opt_mount_outside}" = "yes" ]; then |
| 193 if [ "${_opt_dry_run}" = "yes" ]; then | 210 if [ "${_opt_dry_run}" = "yes" ]; then |
| 194 echo "Would mount ${_name} on configured ZFS dataset mountpoint ${_mp}" | 211 echo "Would mount ${_name} on configured ZFS dataset mountpoint ${_mp}" |
| 195 else | 212 else |
| 196 echo "Mounting ${_name} on configured ZFS dataset mountpoint ${_mp}" | 213 echo "Mounting ${_name} on configured ZFS dataset mountpoint ${_mp}" |
| 197 zfs mount "${_name}" || return 1 | 214 if zfs mount "${_name}"; then |
| 215 array_append _mounted_datasets "${_name}" | |
| 216 else | |
| 217 _umount_datasets _mounted_datasets || true | |
| 218 return 1 | |
| 219 fi | |
| 198 fi | 220 fi |
| 199 else | 221 else |
| 200 echo "Skipping ${_name} because its configured ZFS mountpoint is not relative to given root dataset" 2>&1 | 222 echo "Skipping ${_name} because its configured ZFS mountpoint is not relative to given root dataset" 2>&1 |
| 201 fi | 223 fi |
| 202 ;; | 224 ;; |
| 203 esac | 225 esac |
| 204 done | 226 done |
| 205 | 227 array_destroy _mounted_datasets |
| 206 return 0 | 228 return 0 |
| 207 } | 229 } |
| 230 } | |
| 231 | |
| 232 | |
| 233 #: | |
| 234 #: Helper to unmount mounted ZFS filesystems | |
| 235 #: | |
| 236 #: Args: | |
| 237 #: $1 (str): The name of the array that contains the datasets to unmount to | |
| 238 #: | |
| 239 #: Returns: | |
| 240 #: 0 if successfully unmounted all given datasets, | |
| 241 #: 1 otherwise | |
| 242 #: | |
| 243 #: Unmounting is done in the reverse order. | |
| 244 #: | |
| 245 _umount_datasets() { | |
| 246 array_reversed_for_each "$1" _umount_datasets_umount | |
| 247 } | |
| 248 | |
| 249 | |
| 250 #: | |
| 251 #: Array callback to unmount a single ZFS filesystem | |
| 252 #: | |
| 253 _umount_datasets_umount() { | |
| 254 if ! zfs umount "$3" ; then | |
| 255 warn "Dataset \`${3}' cannot unmounted" | |
| 256 return 1 | |
| 257 fi | |
| 258 return 0 | |
| 208 } | 259 } |
| 209 | 260 |
| 210 | 261 |
| 211 #: | 262 #: |
| 212 #: Implement the "umount" command. | 263 #: Implement the "umount" command. |
