4 * The contents of this file are subject to the terms of the
5 * Common Development and Distribution License (the "License").
6 * You may not use this file except in compliance with the License.
8 * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
9 * or https://opensource.org/licenses/CDDL-1.0.
10 * See the License for the specific language governing permissions
11 * and limitations under the License.
13 * When distributing Covered Code, include this CDDL HEADER in each
14 * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
15 * If applicable, add the following below this CDDL HEADER, with the
16 * fields enclosed by brackets "[]" replaced with your own identifying
17 * information: Portions Copyright [yyyy] [name of copyright owner]
23 * Copyright 2015 Nexenta Systems, Inc. All rights reserved.
24 * Copyright (c) 2005, 2010, Oracle and/or its affiliates. All rights reserved.
25 * Copyright (c) 2014, 2021 by Delphix. All rights reserved.
26 * Copyright 2016 Igor Kozhukhov <ikozhukhov@gmail.com>
27 * Copyright 2017 RackTop Systems.
28 * Copyright (c) 2018 Datto Inc.
29 * Copyright 2018 OmniOS Community Edition (OmniOSce) Association.
43 #include <sys/mntent.h>
44 #include <sys/mount.h>
47 #include <sys/dsl_crypt.h>
50 #include "../../libzfs_impl.h"
51 #include <thread_pool.h>
53 #define ZS_COMMENT 0x00000000 /* comment */
54 #define ZS_ZFSUTIL 0x00000001 /* caller is zfs(8) */
56 typedef struct option_map
{
58 unsigned long mntmask
;
59 unsigned long zfsmask
;
62 static const option_map_t option_map
[] = {
63 /* Canonicalized filesystem independent options from mount(8) */
64 { MNTOPT_NOAUTO
, MS_COMMENT
, ZS_COMMENT
},
65 { MNTOPT_DEFAULTS
, MS_COMMENT
, ZS_COMMENT
},
66 { MNTOPT_NODEVICES
, MS_NODEV
, ZS_COMMENT
},
67 { MNTOPT_DEVICES
, MS_COMMENT
, ZS_COMMENT
},
68 { MNTOPT_DIRSYNC
, MS_DIRSYNC
, ZS_COMMENT
},
69 { MNTOPT_NOEXEC
, MS_NOEXEC
, ZS_COMMENT
},
70 { MNTOPT_EXEC
, MS_COMMENT
, ZS_COMMENT
},
71 { MNTOPT_GROUP
, MS_GROUP
, ZS_COMMENT
},
72 { MNTOPT_NETDEV
, MS_COMMENT
, ZS_COMMENT
},
73 { MNTOPT_NOFAIL
, MS_COMMENT
, ZS_COMMENT
},
74 { MNTOPT_NOSUID
, MS_NOSUID
, ZS_COMMENT
},
75 { MNTOPT_SUID
, MS_COMMENT
, ZS_COMMENT
},
76 { MNTOPT_OWNER
, MS_OWNER
, ZS_COMMENT
},
77 { MNTOPT_REMOUNT
, MS_REMOUNT
, ZS_COMMENT
},
78 { MNTOPT_RO
, MS_RDONLY
, ZS_COMMENT
},
79 { MNTOPT_RW
, MS_COMMENT
, ZS_COMMENT
},
80 { MNTOPT_SYNC
, MS_SYNCHRONOUS
, ZS_COMMENT
},
81 { MNTOPT_USER
, MS_USERS
, ZS_COMMENT
},
82 { MNTOPT_USERS
, MS_USERS
, ZS_COMMENT
},
83 /* acl flags passed with util-linux-2.24 mount command */
84 { MNTOPT_ACL
, MS_POSIXACL
, ZS_COMMENT
},
85 { MNTOPT_NOACL
, MS_COMMENT
, ZS_COMMENT
},
86 { MNTOPT_POSIXACL
, MS_POSIXACL
, ZS_COMMENT
},
88 * Case sensitive options are just listed here to silently
89 * ignore the error if passed with zfs mount command.
91 { MNTOPT_CASESENSITIVE
, MS_COMMENT
, ZS_COMMENT
},
92 { MNTOPT_CASEINSENSITIVE
, MS_COMMENT
, ZS_COMMENT
},
93 { MNTOPT_CASEMIXED
, MS_COMMENT
, ZS_COMMENT
},
95 { MNTOPT_NOATIME
, MS_NOATIME
, ZS_COMMENT
},
96 { MNTOPT_ATIME
, MS_COMMENT
, ZS_COMMENT
},
99 { MNTOPT_NODIRATIME
, MS_NODIRATIME
, ZS_COMMENT
},
100 { MNTOPT_DIRATIME
, MS_COMMENT
, ZS_COMMENT
},
103 { MNTOPT_RELATIME
, MS_RELATIME
, ZS_COMMENT
},
104 { MNTOPT_NORELATIME
, MS_COMMENT
, ZS_COMMENT
},
106 #ifdef MS_STRICTATIME
107 { MNTOPT_STRICTATIME
, MS_STRICTATIME
, ZS_COMMENT
},
108 { MNTOPT_NOSTRICTATIME
, MS_COMMENT
, ZS_COMMENT
},
111 { MNTOPT_LAZYTIME
, MS_LAZYTIME
, ZS_COMMENT
},
113 { MNTOPT_CONTEXT
, MS_COMMENT
, ZS_COMMENT
},
114 { MNTOPT_FSCONTEXT
, MS_COMMENT
, ZS_COMMENT
},
115 { MNTOPT_DEFCONTEXT
, MS_COMMENT
, ZS_COMMENT
},
116 { MNTOPT_ROOTCONTEXT
, MS_COMMENT
, ZS_COMMENT
},
118 { MNTOPT_IVERSION
, MS_I_VERSION
, ZS_COMMENT
},
121 { MNTOPT_NBMAND
, MS_MANDLOCK
, ZS_COMMENT
},
122 { MNTOPT_NONBMAND
, MS_COMMENT
, ZS_COMMENT
},
124 /* Valid options not found in mount(8) */
125 { MNTOPT_BIND
, MS_BIND
, ZS_COMMENT
},
127 { MNTOPT_RBIND
, MS_BIND
|MS_REC
, ZS_COMMENT
},
129 { MNTOPT_COMMENT
, MS_COMMENT
, ZS_COMMENT
},
131 { MNTOPT_NOSUB
, MS_NOSUB
, ZS_COMMENT
},
134 { MNTOPT_QUIET
, MS_SILENT
, ZS_COMMENT
},
136 /* Custom zfs options */
137 { MNTOPT_XATTR
, MS_COMMENT
, ZS_COMMENT
},
138 { MNTOPT_NOXATTR
, MS_COMMENT
, ZS_COMMENT
},
139 { MNTOPT_ZFSUTIL
, MS_COMMENT
, ZS_ZFSUTIL
},
143 * Break the mount option in to a name/value pair. The name is
144 * validated against the option map and mount flags set accordingly.
147 parse_option(char *mntopt
, unsigned long *mntflags
,
148 unsigned long *zfsflags
, int sloppy
)
150 const option_map_t
*opt
;
151 char *ptr
, *name
, *value
= NULL
;
154 name
= strdup(mntopt
);
158 for (ptr
= name
; ptr
&& *ptr
; ptr
++) {
162 VERIFY3P(value
, !=, NULL
);
167 for (opt
= option_map
; opt
->name
!= NULL
; opt
++) {
168 if (strncmp(name
, opt
->name
, strlen(name
)) == 0) {
169 *mntflags
|= opt
->mntmask
;
170 *zfsflags
|= opt
->zfsmask
;
179 /* If required further process on the value may be done here */
185 * Translate the mount option string in to MS_* mount flags for the
186 * kernel vfs. When sloppy is non-zero unknown options will be ignored
187 * otherwise they are considered fatal are copied in to badopt.
190 zfs_parse_mount_options(const char *mntopts
, unsigned long *mntflags
,
191 unsigned long *zfsflags
, int sloppy
, char *badopt
, char *mtabopt
)
193 int error
= 0, quote
= 0, flag
= 0, count
= 0;
194 char *ptr
, *opt
, *opts
;
196 opts
= strdup(mntopts
);
204 * Scan through all mount options which must be comma delimited.
205 * We must be careful to notice regions which are double quoted
206 * and skip commas in these regions. Each option is then checked
207 * to determine if it is a known option.
209 for (ptr
= opts
; ptr
&& !flag
; ptr
++) {
222 if ((*ptr
== ',') || (*ptr
== '\0')) {
225 error
= parse_option(opt
, mntflags
, zfsflags
, sloppy
);
232 if (!(*mntflags
& MS_REMOUNT
) &&
233 !(*zfsflags
& ZS_ZFSUTIL
) &&
236 strlcat(mtabopt
, ",", MNT_LINE_MAX
);
238 strlcat(mtabopt
, opt
, MNT_LINE_MAX
);
252 append_mntopt(const char *name
, const char *val
, char *mntopts
,
253 char *mtabopt
, boolean_t quote
)
255 char tmp
[MNT_LINE_MAX
];
257 snprintf(tmp
, MNT_LINE_MAX
, quote
? ",%s=\"%s\"" : ",%s=%s", name
, val
);
260 strlcat(mntopts
, tmp
, MNT_LINE_MAX
);
263 strlcat(mtabopt
, tmp
, MNT_LINE_MAX
);
267 zfs_selinux_setcontext(zfs_handle_t
*zhp
, zfs_prop_t zpt
, const char *name
,
268 char *mntopts
, char *mtabopt
)
270 char context
[ZFS_MAXPROPLEN
];
272 if (zfs_prop_get(zhp
, zpt
, context
, sizeof (context
),
273 NULL
, NULL
, 0, B_FALSE
) == 0) {
274 if (strcmp(context
, "none") != 0)
275 append_mntopt(name
, context
, mntopts
, mtabopt
, B_TRUE
);
280 zfs_adjust_mount_options(zfs_handle_t
*zhp
, const char *mntpoint
,
281 char *mntopts
, char *mtabopt
)
283 char prop
[ZFS_MAXPROPLEN
];
286 * Checks to see if the ZFS_PROP_SELINUX_CONTEXT exists
287 * if it does, create a tmp variable in case it's needed
288 * checks to see if the selinux context is set to the default
289 * if it is, allow the setting of the other context properties
290 * this is needed because the 'context' property overrides others
291 * if it is not the default, set the 'context' property
293 if (zfs_prop_get(zhp
, ZFS_PROP_SELINUX_CONTEXT
, prop
, sizeof (prop
),
294 NULL
, NULL
, 0, B_FALSE
) == 0) {
295 if (strcmp(prop
, "none") == 0) {
296 zfs_selinux_setcontext(zhp
, ZFS_PROP_SELINUX_FSCONTEXT
,
297 MNTOPT_FSCONTEXT
, mntopts
, mtabopt
);
298 zfs_selinux_setcontext(zhp
, ZFS_PROP_SELINUX_DEFCONTEXT
,
299 MNTOPT_DEFCONTEXT
, mntopts
, mtabopt
);
300 zfs_selinux_setcontext(zhp
,
301 ZFS_PROP_SELINUX_ROOTCONTEXT
, MNTOPT_ROOTCONTEXT
,
304 append_mntopt(MNTOPT_CONTEXT
, prop
,
305 mntopts
, mtabopt
, B_TRUE
);
309 /* A hint used to determine an auto-mounted snapshot mount point */
310 append_mntopt(MNTOPT_MNTPOINT
, mntpoint
, mntopts
, NULL
, B_FALSE
);
314 * By default the filesystem by preparing the mount options (i.e. parsing
315 * some flags from the "opts" parameter into the "flags" parameter) and then
316 * directly calling the system call mount(2). We don't need the mount utility
317 * or update /etc/mtab, because this is a symlink on all modern systems.
319 * If the environment variable ZFS_MOUNT_HELPER is set, we fall back to the
321 * The filesystem is mounted by invoking the system mount utility rather
322 * than by the system call mount(2). This ensures that the /etc/mtab
323 * file is correctly locked for the update. Performing our own locking
324 * and /etc/mtab update requires making an unsafe assumption about how
325 * the mount utility performs its locking. Unfortunately, this also means
326 * in the case of a mount failure we do not have the exact errno. We must
327 * make due with return value from the mount process.
330 do_mount(zfs_handle_t
*zhp
, const char *mntpt
, const char *opts
, int flags
)
332 const char *src
= zfs_get_name(zhp
);
335 if (!libzfs_envvar_is_set("ZFS_MOUNT_HELPER")) {
336 char badopt
[MNT_LINE_MAX
] = {0};
337 unsigned long mntflags
= flags
, zfsflags
= 0;
338 char myopts
[MNT_LINE_MAX
] = {0};
340 if (zfs_parse_mount_options(opts
, &mntflags
,
341 &zfsflags
, 0, badopt
, NULL
)) {
344 strlcat(myopts
, opts
, MNT_LINE_MAX
);
345 zfs_adjust_mount_options(zhp
, mntpt
, myopts
, NULL
);
346 if (mount(src
, mntpt
, MNTTYPE_ZFS
, mntflags
, myopts
)) {
351 (char *)"/bin/mount",
352 (char *)"--no-canonicalize",
353 (char *)"-t", (char *)MNTTYPE_ZFS
,
354 (char *)"-o", (char *)opts
,
359 /* Return only the most critical mount error */
360 error
= libzfs_run_process(argv
[0], argv
,
361 STDOUT_VERBOSE
|STDERR_VERBOSE
);
363 if (error
& MOUNT_FILEIO
) {
365 } else if (error
& MOUNT_USER
) {
367 } else if (error
& MOUNT_SOFTWARE
) {
369 } else if (error
& MOUNT_BUSY
) {
371 } else if (error
& MOUNT_SYSERR
) {
373 } else if (error
& MOUNT_USAGE
) {
376 error
= ENXIO
; /* Generic error */
384 do_unmount(zfs_handle_t
*zhp
, const char *mntpt
, int flags
)
388 if (!libzfs_envvar_is_set("ZFS_MOUNT_HELPER")) {
389 int rv
= umount2(mntpt
, flags
);
391 return (rv
< 0 ? errno
: 0);
395 (char *)"/bin/umount",
396 (char *)"-t", (char *)MNTTYPE_ZFS
,
397 NULL
, NULL
, NULL
, NULL
};
400 if (flags
& MS_FORCE
)
401 argv
[count
++] = (char *)"-f";
403 if (flags
& MS_DETACH
)
404 argv
[count
++] = (char *)"-l";
406 argv
[count
] = (char *)mntpt
;
407 rc
= libzfs_run_process(argv
[0], argv
, STDOUT_VERBOSE
|STDERR_VERBOSE
);
409 return (rc
? EINVAL
: 0);
413 zfs_mount_delegation_check(void)
415 return ((geteuid() != 0) ? EACCES
: 0);
418 /* Called from the tail end of zpool_disable_datasets() */
420 zpool_disable_datasets_os(zpool_handle_t
*zhp
, boolean_t force
)
422 (void) zhp
, (void) force
;
425 /* Called from the tail end of zfs_unmount() */
427 zpool_disable_volume_os(const char *name
)