]>
Commit | Line | Data |
---|---|---|
d53368f6 BB |
1 | /* |
2 | * CDDL HEADER START | |
3 | * | |
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. | |
7 | * | |
8 | * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE | |
9 | * or http://www.opensolaris.org/os/licensing. | |
10 | * See the License for the specific language governing permissions | |
11 | * and limitations under the License. | |
12 | * | |
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] | |
18 | * | |
19 | * CDDL HEADER END | |
20 | */ | |
21 | ||
22 | /* | |
23 | * Copyright (c) 2005, 2010, Oracle and/or its affiliates. All rights reserved. | |
24 | * Copyright (c) 2011 Lawrence Livermore National Security, LLC. | |
25 | */ | |
26 | ||
27 | #include <libintl.h> | |
28 | #include <unistd.h> | |
29 | #include <sys/file.h> | |
30 | #include <sys/mount.h> | |
0282c413 | 31 | #include <sys/mntent.h> |
d53368f6 BB |
32 | #include <sys/stat.h> |
33 | #include <libzfs.h> | |
e89f1295 | 34 | #include <libzutil.h> |
92e91da2 | 35 | #include <locale.h> |
d93b45ae | 36 | #include <getopt.h> |
6d723925 | 37 | #include <fcntl.h> |
93ce2b4c | 38 | #include <errno.h> |
d53368f6 | 39 | |
0282c413 BB |
40 | #define ZS_COMMENT 0x00000000 /* comment */ |
41 | #define ZS_ZFSUTIL 0x00000001 /* caller is zfs(8) */ | |
42 | ||
d53368f6 BB |
43 | libzfs_handle_t *g_zfs; |
44 | ||
45 | typedef struct option_map { | |
46 | const char *name; | |
47 | unsigned long mntmask; | |
48 | unsigned long zfsmask; | |
49 | } option_map_t; | |
50 | ||
51 | static const option_map_t option_map[] = { | |
52 | /* Canonicalized filesystem independent options from mount(8) */ | |
53 | { MNTOPT_NOAUTO, MS_COMMENT, ZS_COMMENT }, | |
54 | { MNTOPT_DEFAULTS, MS_COMMENT, ZS_COMMENT }, | |
55 | { MNTOPT_NODEVICES, MS_NODEV, ZS_COMMENT }, | |
56 | { MNTOPT_DIRSYNC, MS_DIRSYNC, ZS_COMMENT }, | |
57 | { MNTOPT_NOEXEC, MS_NOEXEC, ZS_COMMENT }, | |
58 | { MNTOPT_GROUP, MS_GROUP, ZS_COMMENT }, | |
59 | { MNTOPT_NETDEV, MS_COMMENT, ZS_COMMENT }, | |
60 | { MNTOPT_NOFAIL, MS_COMMENT, ZS_COMMENT }, | |
61 | { MNTOPT_NOSUID, MS_NOSUID, ZS_COMMENT }, | |
62 | { MNTOPT_OWNER, MS_OWNER, ZS_COMMENT }, | |
63 | { MNTOPT_REMOUNT, MS_REMOUNT, ZS_COMMENT }, | |
64 | { MNTOPT_RO, MS_RDONLY, ZS_COMMENT }, | |
65 | { MNTOPT_RW, MS_COMMENT, ZS_COMMENT }, | |
66 | { MNTOPT_SYNC, MS_SYNCHRONOUS, ZS_COMMENT }, | |
67 | { MNTOPT_USER, MS_USERS, ZS_COMMENT }, | |
68 | { MNTOPT_USERS, MS_USERS, ZS_COMMENT }, | |
a5f36651 | 69 | /* acl flags passed with util-linux-2.24 mount command */ |
70 | { MNTOPT_ACL, MS_POSIXACL, ZS_COMMENT }, | |
71 | { MNTOPT_NOACL, MS_COMMENT, ZS_COMMENT }, | |
72 | { MNTOPT_POSIXACL, MS_POSIXACL, ZS_COMMENT }, | |
d53368f6 BB |
73 | #ifdef MS_NOATIME |
74 | { MNTOPT_NOATIME, MS_NOATIME, ZS_COMMENT }, | |
75 | #endif | |
76 | #ifdef MS_NODIRATIME | |
77 | { MNTOPT_NODIRATIME, MS_NODIRATIME, ZS_COMMENT }, | |
78 | #endif | |
79 | #ifdef MS_RELATIME | |
80 | { MNTOPT_RELATIME, MS_RELATIME, ZS_COMMENT }, | |
81 | #endif | |
82 | #ifdef MS_STRICTATIME | |
67600771 CC |
83 | { MNTOPT_STRICTATIME, MS_STRICTATIME, ZS_COMMENT }, |
84 | #endif | |
85 | #ifdef MS_LAZYTIME | |
86 | { MNTOPT_LAZYTIME, MS_LAZYTIME, ZS_COMMENT }, | |
d53368f6 | 87 | #endif |
11b9ec23 MT |
88 | { MNTOPT_CONTEXT, MS_COMMENT, ZS_COMMENT }, |
89 | { MNTOPT_FSCONTEXT, MS_COMMENT, ZS_COMMENT }, | |
90 | { MNTOPT_DEFCONTEXT, MS_COMMENT, ZS_COMMENT }, | |
91 | { MNTOPT_ROOTCONTEXT, MS_COMMENT, ZS_COMMENT }, | |
d53368f6 BB |
92 | #ifdef MS_I_VERSION |
93 | { MNTOPT_IVERSION, MS_I_VERSION, ZS_COMMENT }, | |
94 | #endif | |
95 | #ifdef MS_MANDLOCK | |
96 | { MNTOPT_NBMAND, MS_MANDLOCK, ZS_COMMENT }, | |
97 | #endif | |
98 | /* Valid options not found in mount(8) */ | |
99 | { MNTOPT_BIND, MS_BIND, ZS_COMMENT }, | |
100 | #ifdef MS_REC | |
101 | { MNTOPT_RBIND, MS_BIND|MS_REC, ZS_COMMENT }, | |
102 | #endif | |
103 | { MNTOPT_COMMENT, MS_COMMENT, ZS_COMMENT }, | |
104 | #ifdef MS_NOSUB | |
105 | { MNTOPT_NOSUB, MS_NOSUB, ZS_COMMENT }, | |
106 | #endif | |
107 | #ifdef MS_SILENT | |
108 | { MNTOPT_QUIET, MS_SILENT, ZS_COMMENT }, | |
109 | #endif | |
110 | /* Custom zfs options */ | |
2cf7f52b | 111 | { MNTOPT_XATTR, MS_COMMENT, ZS_COMMENT }, |
d53368f6 BB |
112 | { MNTOPT_NOXATTR, MS_COMMENT, ZS_COMMENT }, |
113 | { MNTOPT_ZFSUTIL, MS_COMMENT, ZS_ZFSUTIL }, | |
114 | { NULL, 0, 0 } }; | |
115 | ||
116 | /* | |
117 | * Break the mount option in to a name/value pair. The name is | |
118 | * validated against the option map and mount flags set accordingly. | |
119 | */ | |
120 | static int | |
121 | parse_option(char *mntopt, unsigned long *mntflags, | |
122 | unsigned long *zfsflags, int sloppy) | |
123 | { | |
124 | const option_map_t *opt; | |
125 | char *ptr, *name, *value = NULL; | |
126 | int error = 0; | |
127 | ||
128 | name = strdup(mntopt); | |
129 | if (name == NULL) | |
130 | return (ENOMEM); | |
131 | ||
132 | for (ptr = name; ptr && *ptr; ptr++) { | |
133 | if (*ptr == '=') { | |
134 | *ptr = '\0'; | |
135 | value = ptr+1; | |
03514b01 | 136 | VERIFY3P(value, !=, NULL); |
d53368f6 BB |
137 | break; |
138 | } | |
139 | } | |
140 | ||
141 | for (opt = option_map; opt->name != NULL; opt++) { | |
142 | if (strncmp(name, opt->name, strlen(name)) == 0) { | |
143 | *mntflags |= opt->mntmask; | |
144 | *zfsflags |= opt->zfsmask; | |
d53368f6 BB |
145 | error = 0; |
146 | goto out; | |
147 | } | |
148 | } | |
149 | ||
150 | if (!sloppy) | |
151 | error = ENOENT; | |
152 | out: | |
153 | /* If required further process on the value may be done here */ | |
154 | free(name); | |
155 | return (error); | |
156 | } | |
157 | ||
158 | /* | |
159 | * Translate the mount option string in to MS_* mount flags for the | |
160 | * kernel vfs. When sloppy is non-zero unknown options will be ignored | |
161 | * otherwise they are considered fatal are copied in to badopt. | |
162 | */ | |
163 | static int | |
3aff7755 BB |
164 | parse_options(char *mntopts, unsigned long *mntflags, unsigned long *zfsflags, |
165 | int sloppy, char *badopt, char *mtabopt) | |
d53368f6 | 166 | { |
3aff7755 | 167 | int error = 0, quote = 0, flag = 0, count = 0; |
d53368f6 BB |
168 | char *ptr, *opt, *opts; |
169 | ||
170 | opts = strdup(mntopts); | |
171 | if (opts == NULL) | |
172 | return (ENOMEM); | |
173 | ||
174 | *mntflags = 0; | |
175 | opt = NULL; | |
176 | ||
177 | /* | |
178 | * Scan through all mount options which must be comma delimited. | |
179 | * We must be careful to notice regions which are double quoted | |
180 | * and skip commas in these regions. Each option is then checked | |
181 | * to determine if it is a known option. | |
182 | */ | |
183 | for (ptr = opts; ptr && !flag; ptr++) { | |
184 | if (opt == NULL) | |
185 | opt = ptr; | |
186 | ||
187 | if (*ptr == '"') | |
188 | quote = !quote; | |
189 | ||
190 | if (quote) | |
191 | continue; | |
192 | ||
193 | if (*ptr == '\0') | |
194 | flag = 1; | |
195 | ||
196 | if ((*ptr == ',') || (*ptr == '\0')) { | |
197 | *ptr = '\0'; | |
198 | ||
199 | error = parse_option(opt, mntflags, zfsflags, sloppy); | |
200 | if (error) { | |
201 | strcpy(badopt, opt); | |
202 | goto out; | |
3aff7755 BB |
203 | |
204 | } | |
205 | ||
206 | if (!(*mntflags & MS_REMOUNT) && | |
207 | !(*zfsflags & ZS_ZFSUTIL)) { | |
208 | if (count > 0) | |
209 | strlcat(mtabopt, ",", MNT_LINE_MAX); | |
210 | ||
211 | strlcat(mtabopt, opt, MNT_LINE_MAX); | |
212 | count++; | |
d53368f6 BB |
213 | } |
214 | ||
215 | opt = NULL; | |
216 | } | |
217 | } | |
218 | ||
219 | out: | |
220 | free(opts); | |
221 | return (error); | |
222 | } | |
223 | ||
224 | /* | |
0c1171dc BB |
225 | * Return the pool/dataset to mount given the name passed to mount. This |
226 | * is expected to be of the form pool/dataset, however may also refer to | |
227 | * a block device if that device contains a valid zfs label. | |
d53368f6 BB |
228 | */ |
229 | static char * | |
230 | parse_dataset(char *dataset) | |
231 | { | |
232 | char cwd[PATH_MAX]; | |
0c1171dc BB |
233 | struct stat64 statbuf; |
234 | int error; | |
a6cba65c | 235 | int len; |
d53368f6 | 236 | |
0c1171dc BB |
237 | /* |
238 | * We expect a pool/dataset to be provided, however if we're | |
239 | * given a device which is a member of a zpool we attempt to | |
240 | * extract the pool name stored in the label. Given the pool | |
241 | * name we can mount the root dataset. | |
242 | */ | |
243 | error = stat64(dataset, &statbuf); | |
244 | if (error == 0) { | |
245 | nvlist_t *config; | |
246 | char *name; | |
247 | int fd; | |
248 | ||
249 | fd = open(dataset, O_RDONLY); | |
250 | if (fd < 0) | |
251 | goto out; | |
252 | ||
7d90f569 | 253 | error = zpool_read_label(fd, &config, NULL); |
0c1171dc BB |
254 | (void) close(fd); |
255 | if (error) | |
256 | goto out; | |
257 | ||
258 | error = nvlist_lookup_string(config, | |
259 | ZPOOL_CONFIG_POOL_NAME, &name); | |
c76955ea BB |
260 | if (error) { |
261 | nvlist_free(config); | |
262 | } else { | |
0c1171dc | 263 | dataset = strdup(name); |
c76955ea BB |
264 | nvlist_free(config); |
265 | return (dataset); | |
266 | } | |
0c1171dc BB |
267 | } |
268 | out: | |
269 | /* | |
270 | * If a file or directory in your current working directory is | |
271 | * named 'dataset' then mount(8) will prepend your current working | |
272 | * directory to the dataset. There is no way to prevent this | |
273 | * behavior so we simply check for it and strip the prepended | |
274 | * patch when it is added. | |
275 | */ | |
ec49a5f0 BB |
276 | if (getcwd(cwd, PATH_MAX) == NULL) |
277 | return (dataset); | |
278 | ||
a6cba65c BB |
279 | len = strlen(cwd); |
280 | ||
281 | /* Do not add one when cwd already ends in a trailing '/' */ | |
d1d7e268 | 282 | if (strncmp(cwd, dataset, len) == 0) |
a6cba65c | 283 | return (dataset + len + (cwd[len-1] != '/')); |
d53368f6 BB |
284 | |
285 | return (dataset); | |
286 | } | |
287 | ||
288 | /* | |
289 | * Update the mtab_* code to use the libmount library when it is commonly | |
290 | * available otherwise fallback to legacy mode. The mount(8) utility will | |
291 | * manage the lock file for us to prevent racing updates to /etc/mtab. | |
292 | */ | |
293 | static int | |
294 | mtab_is_writeable(void) | |
295 | { | |
296 | struct stat st; | |
297 | int error, fd; | |
298 | ||
79251738 | 299 | error = lstat("/etc/mtab", &st); |
d53368f6 BB |
300 | if (error || S_ISLNK(st.st_mode)) |
301 | return (0); | |
302 | ||
79251738 | 303 | fd = open("/etc/mtab", O_RDWR | O_CREAT, 0644); |
d53368f6 BB |
304 | if (fd < 0) |
305 | return (0); | |
306 | ||
307 | close(fd); | |
308 | return (1); | |
309 | } | |
310 | ||
311 | static int | |
312 | mtab_update(char *dataset, char *mntpoint, char *type, char *mntopts) | |
313 | { | |
314 | struct mntent mnt; | |
315 | FILE *fp; | |
316 | int error; | |
317 | ||
318 | mnt.mnt_fsname = dataset; | |
319 | mnt.mnt_dir = mntpoint; | |
320 | mnt.mnt_type = type; | |
321 | mnt.mnt_opts = mntopts ? mntopts : ""; | |
322 | mnt.mnt_freq = 0; | |
323 | mnt.mnt_passno = 0; | |
324 | ||
79251738 | 325 | fp = setmntent("/etc/mtab", "a+"); |
d53368f6 BB |
326 | if (!fp) { |
327 | (void) fprintf(stderr, gettext( | |
79251738 | 328 | "filesystem '%s' was mounted, but /etc/mtab " |
d53368f6 | 329 | "could not be opened due to error %d\n"), |
79251738 | 330 | dataset, errno); |
d53368f6 BB |
331 | return (MOUNT_FILEIO); |
332 | } | |
333 | ||
334 | error = addmntent(fp, &mnt); | |
335 | if (error) { | |
336 | (void) fprintf(stderr, gettext( | |
79251738 | 337 | "filesystem '%s' was mounted, but /etc/mtab " |
d53368f6 | 338 | "could not be updated due to error %d\n"), |
79251738 | 339 | dataset, errno); |
d53368f6 BB |
340 | return (MOUNT_FILEIO); |
341 | } | |
342 | ||
343 | (void) endmntent(fp); | |
344 | ||
345 | return (MOUNT_SUCCESS); | |
346 | } | |
347 | ||
11b9ec23 | 348 | static void |
0282c413 BB |
349 | append_mntopt(const char *name, const char *val, char *mntopts, |
350 | char *mtabopt, boolean_t quote) | |
11b9ec23 MT |
351 | { |
352 | char tmp[MNT_LINE_MAX]; | |
353 | ||
0282c413 BB |
354 | snprintf(tmp, MNT_LINE_MAX, quote ? ",%s=\"%s\"" : ",%s=%s", name, val); |
355 | ||
356 | if (mntopts) | |
357 | strlcat(mntopts, tmp, MNT_LINE_MAX); | |
358 | ||
359 | if (mtabopt) | |
360 | strlcat(mtabopt, tmp, MNT_LINE_MAX); | |
11b9ec23 MT |
361 | } |
362 | ||
363 | static void | |
364 | zfs_selinux_setcontext(zfs_handle_t *zhp, zfs_prop_t zpt, const char *name, | |
365 | char *mntopts, char *mtabopt) | |
366 | { | |
367 | char context[ZFS_MAXPROPLEN]; | |
368 | ||
369 | if (zfs_prop_get(zhp, zpt, context, sizeof (context), | |
370 | NULL, NULL, 0, B_FALSE) == 0) { | |
371 | if (strcmp(context, "none") != 0) | |
02730c33 | 372 | append_mntopt(name, context, mntopts, mtabopt, B_TRUE); |
11b9ec23 MT |
373 | } |
374 | } | |
375 | ||
d53368f6 BB |
376 | int |
377 | main(int argc, char **argv) | |
378 | { | |
379 | zfs_handle_t *zhp; | |
11b9ec23 | 380 | char prop[ZFS_MAXPROPLEN]; |
287be44f | 381 | uint64_t zfs_version = 0; |
d53368f6 BB |
382 | char mntopts[MNT_LINE_MAX] = { '\0' }; |
383 | char badopt[MNT_LINE_MAX] = { '\0' }; | |
3aff7755 | 384 | char mtabopt[MNT_LINE_MAX] = { '\0' }; |
33364b15 | 385 | char mntpoint[PATH_MAX]; |
386 | char *dataset; | |
c171ea71 | 387 | unsigned long mntflags = 0, zfsflags = 0, remount = 0; |
d53368f6 BB |
388 | int sloppy = 0, fake = 0, verbose = 0, nomtab = 0, zfsutil = 0; |
389 | int error, c; | |
390 | ||
391 | (void) setlocale(LC_ALL, ""); | |
392 | (void) textdomain(TEXT_DOMAIN); | |
393 | ||
394 | opterr = 0; | |
395 | ||
396 | /* check options */ | |
d93b45ae | 397 | while ((c = getopt_long(argc, argv, "sfnvo:h?", 0, 0)) != -1) { |
d53368f6 BB |
398 | switch (c) { |
399 | case 's': | |
400 | sloppy = 1; | |
401 | break; | |
402 | case 'f': | |
403 | fake = 1; | |
404 | break; | |
405 | case 'n': | |
406 | nomtab = 1; | |
407 | break; | |
408 | case 'v': | |
409 | verbose++; | |
410 | break; | |
411 | case 'o': | |
412 | (void) strlcpy(mntopts, optarg, sizeof (mntopts)); | |
413 | break; | |
414 | case 'h': | |
415 | case '?': | |
416 | (void) fprintf(stderr, gettext("Invalid option '%c'\n"), | |
417 | optopt); | |
418 | (void) fprintf(stderr, gettext("Usage: mount.zfs " | |
419 | "[-sfnv] [-o options] <dataset> <mountpoint>\n")); | |
420 | return (MOUNT_USAGE); | |
421 | } | |
422 | } | |
423 | ||
424 | argc -= optind; | |
425 | argv += optind; | |
426 | ||
427 | /* check that we only have two arguments */ | |
428 | if (argc != 2) { | |
429 | if (argc == 0) | |
430 | (void) fprintf(stderr, gettext("missing dataset " | |
431 | "argument\n")); | |
432 | else if (argc == 1) | |
433 | (void) fprintf(stderr, | |
434 | gettext("missing mountpoint argument\n")); | |
435 | else | |
436 | (void) fprintf(stderr, gettext("too many arguments\n")); | |
437 | (void) fprintf(stderr, "usage: mount <dataset> <mountpoint>\n"); | |
438 | return (MOUNT_USAGE); | |
439 | } | |
440 | ||
441 | dataset = parse_dataset(argv[0]); | |
33364b15 | 442 | |
443 | /* canonicalize the mount point */ | |
444 | if (realpath(argv[1], mntpoint) == NULL) { | |
445 | (void) fprintf(stderr, gettext("filesystem '%s' cannot be " | |
87bdc45c BB |
446 | "mounted at '%s' due to canonicalization error %d.\n"), |
447 | dataset, argv[1], errno); | |
33364b15 | 448 | return (MOUNT_SYSERR); |
449 | } | |
d53368f6 BB |
450 | |
451 | /* validate mount options and set mntflags */ | |
3aff7755 BB |
452 | error = parse_options(mntopts, &mntflags, &zfsflags, sloppy, |
453 | badopt, mtabopt); | |
d53368f6 BB |
454 | if (error) { |
455 | switch (error) { | |
456 | case ENOMEM: | |
457 | (void) fprintf(stderr, gettext("filesystem '%s' " | |
458 | "cannot be mounted due to a memory allocation " | |
3aff7755 | 459 | "failure.\n"), dataset); |
d53368f6 | 460 | return (MOUNT_SYSERR); |
3aff7755 | 461 | case ENOENT: |
d53368f6 | 462 | (void) fprintf(stderr, gettext("filesystem '%s' " |
758d3552 | 463 | "cannot be mounted due to invalid option " |
3aff7755 | 464 | "'%s'.\n"), dataset, badopt); |
d53368f6 BB |
465 | (void) fprintf(stderr, gettext("Use the '-s' option " |
466 | "to ignore the bad mount option.\n")); | |
467 | return (MOUNT_USAGE); | |
468 | default: | |
469 | (void) fprintf(stderr, gettext("filesystem '%s' " | |
3aff7755 | 470 | "cannot be mounted due to internal error %d.\n"), |
d53368f6 BB |
471 | dataset, error); |
472 | return (MOUNT_SOFTWARE); | |
473 | } | |
474 | } | |
475 | ||
d53368f6 BB |
476 | if (verbose) |
477 | (void) fprintf(stdout, gettext("mount.zfs:\n" | |
478 | " dataset: \"%s\"\n mountpoint: \"%s\"\n" | |
479 | " mountflags: 0x%lx\n zfsflags: 0x%lx\n" | |
3aff7755 BB |
480 | " mountopts: \"%s\"\n mtabopts: \"%s\"\n"), |
481 | dataset, mntpoint, mntflags, zfsflags, mntopts, mtabopt); | |
d53368f6 | 482 | |
c171ea71 | 483 | if (mntflags & MS_REMOUNT) { |
d53368f6 | 484 | nomtab = 1; |
c171ea71 BB |
485 | remount = 1; |
486 | } | |
093aa692 BB |
487 | |
488 | if (zfsflags & ZS_ZFSUTIL) | |
d53368f6 BB |
489 | zfsutil = 1; |
490 | ||
65037d9b BB |
491 | if ((g_zfs = libzfs_init()) == NULL) { |
492 | (void) fprintf(stderr, "%s", libzfs_error_init(errno)); | |
d53368f6 | 493 | return (MOUNT_SYSERR); |
65037d9b | 494 | } |
d53368f6 BB |
495 | |
496 | /* try to open the dataset to access the mount point */ | |
3613204c BB |
497 | if ((zhp = zfs_open(g_zfs, dataset, |
498 | ZFS_TYPE_FILESYSTEM | ZFS_TYPE_SNAPSHOT)) == NULL) { | |
d53368f6 BB |
499 | (void) fprintf(stderr, gettext("filesystem '%s' cannot be " |
500 | "mounted, unable to open the dataset\n"), dataset); | |
501 | libzfs_fini(g_zfs); | |
502 | return (MOUNT_USAGE); | |
503 | } | |
504 | ||
11b9ec23 MT |
505 | /* |
506 | * Checks to see if the ZFS_PROP_SELINUX_CONTEXT exists | |
507 | * if it does, create a tmp variable in case it's needed | |
508 | * checks to see if the selinux context is set to the default | |
509 | * if it is, allow the setting of the other context properties | |
510 | * this is needed because the 'context' property overrides others | |
511 | * if it is not the default, set the 'context' property | |
512 | */ | |
513 | if (zfs_prop_get(zhp, ZFS_PROP_SELINUX_CONTEXT, prop, sizeof (prop), | |
514 | NULL, NULL, 0, B_FALSE) == 0) { | |
515 | if (strcmp(prop, "none") == 0) { | |
516 | zfs_selinux_setcontext(zhp, ZFS_PROP_SELINUX_FSCONTEXT, | |
517 | MNTOPT_FSCONTEXT, mntopts, mtabopt); | |
518 | zfs_selinux_setcontext(zhp, ZFS_PROP_SELINUX_DEFCONTEXT, | |
519 | MNTOPT_DEFCONTEXT, mntopts, mtabopt); | |
520 | zfs_selinux_setcontext(zhp, | |
521 | ZFS_PROP_SELINUX_ROOTCONTEXT, MNTOPT_ROOTCONTEXT, | |
522 | mntopts, mtabopt); | |
523 | } else { | |
0282c413 BB |
524 | append_mntopt(MNTOPT_CONTEXT, prop, |
525 | mntopts, mtabopt, B_TRUE); | |
11b9ec23 MT |
526 | } |
527 | } | |
528 | ||
0282c413 BB |
529 | /* A hint used to determine an auto-mounted snapshot mount point */ |
530 | append_mntopt(MNTOPT_MNTPOINT, mntpoint, mntopts, NULL, B_FALSE); | |
531 | ||
3613204c BB |
532 | /* treat all snapshots as legacy mount points */ |
533 | if (zfs_get_type(zhp) == ZFS_TYPE_SNAPSHOT) | |
11b9ec23 | 534 | (void) strlcpy(prop, ZFS_MOUNTPOINT_LEGACY, ZFS_MAXPROPLEN); |
3613204c | 535 | else |
11b9ec23 MT |
536 | (void) zfs_prop_get(zhp, ZFS_PROP_MOUNTPOINT, prop, |
537 | sizeof (prop), NULL, NULL, 0, B_FALSE); | |
d53368f6 | 538 | |
287be44f DS |
539 | /* |
540 | * Fetch the max supported zfs version in case we get ENOTSUP | |
541 | * back from the mount command, since we need the zfs handle | |
542 | * to do so. | |
543 | */ | |
544 | zfs_version = zfs_prop_get_int(zhp, ZFS_PROP_VERSION); | |
545 | if (zfs_version == 0) { | |
546 | fprintf(stderr, gettext("unable to fetch " | |
547 | "ZFS version for filesystem '%s'\n"), dataset); | |
548 | return (MOUNT_SYSERR); | |
549 | } | |
550 | ||
d53368f6 BB |
551 | zfs_close(zhp); |
552 | libzfs_fini(g_zfs); | |
553 | ||
554 | /* | |
555 | * Legacy mount points may only be mounted using 'mount', never using | |
556 | * 'zfs mount'. However, since 'zfs mount' actually invokes 'mount' | |
557 | * we differentiate the two cases using the 'zfsutil' mount option. | |
558 | * This mount option should only be supplied by the 'zfs mount' util. | |
093aa692 | 559 | * |
c171ea71 BB |
560 | * The only exception to the above rule is '-o remount' which is |
561 | * always allowed for non-legacy datasets. This is done because when | |
562 | * using zfs as your root file system both rc.sysinit/umountroot and | |
563 | * systemd depend on 'mount -o remount <mountpoint>' to work. | |
d53368f6 | 564 | */ |
11b9ec23 | 565 | if (zfsutil && (strcmp(prop, ZFS_MOUNTPOINT_LEGACY) == 0)) { |
d53368f6 BB |
566 | (void) fprintf(stderr, gettext( |
567 | "filesystem '%s' cannot be mounted using 'zfs mount'.\n" | |
568 | "Use 'zfs set mountpoint=%s' or 'mount -t zfs %s %s'.\n" | |
569 | "See zfs(8) for more information.\n"), | |
d1d7e268 | 570 | dataset, mntpoint, dataset, mntpoint); |
d53368f6 BB |
571 | return (MOUNT_USAGE); |
572 | } | |
573 | ||
462ee8e3 | 574 | if (!zfsutil && !(remount || fake) && |
11b9ec23 | 575 | strcmp(prop, ZFS_MOUNTPOINT_LEGACY)) { |
d53368f6 BB |
576 | (void) fprintf(stderr, gettext( |
577 | "filesystem '%s' cannot be mounted using 'mount'.\n" | |
578 | "Use 'zfs set mountpoint=%s' or 'zfs mount %s'.\n" | |
579 | "See zfs(8) for more information.\n"), | |
580 | dataset, "legacy", dataset); | |
581 | return (MOUNT_USAGE); | |
582 | } | |
583 | ||
584 | if (!fake) { | |
585 | error = mount(dataset, mntpoint, MNTTYPE_ZFS, | |
586 | mntflags, mntopts); | |
287be44f DS |
587 | } |
588 | ||
589 | if (error) { | |
590 | switch (errno) { | |
591 | case ENOENT: | |
592 | (void) fprintf(stderr, gettext("mount point " | |
593 | "'%s' does not exist\n"), mntpoint); | |
594 | return (MOUNT_SYSERR); | |
595 | case EBUSY: | |
596 | (void) fprintf(stderr, gettext("filesystem " | |
597 | "'%s' is already mounted\n"), dataset); | |
598 | return (MOUNT_BUSY); | |
599 | case ENOTSUP: | |
600 | if (zfs_version > ZPL_VERSION) { | |
601 | (void) fprintf(stderr, | |
602 | gettext("filesystem '%s' (v%d) is not " | |
603 | "supported by this implementation of " | |
604 | "ZFS (max v%d).\n"), dataset, | |
02730c33 | 605 | (int)zfs_version, (int)ZPL_VERSION); |
287be44f DS |
606 | } else { |
607 | (void) fprintf(stderr, | |
608 | gettext("filesystem '%s' mount " | |
609 | "failed for unknown reason.\n"), dataset); | |
d53368f6 | 610 | } |
287be44f | 611 | return (MOUNT_SYSERR); |
4070bfd8 BB |
612 | #ifdef MS_MANDLOCK |
613 | case EPERM: | |
614 | if (mntflags & MS_MANDLOCK) { | |
615 | (void) fprintf(stderr, gettext("filesystem " | |
616 | "'%s' has the 'nbmand=on' property set, " | |
617 | "this mount\noption may be disabled in " | |
618 | "your kernel. Use 'zfs set nbmand=off'\n" | |
619 | "to disable this option and try to " | |
620 | "mount the filesystem again.\n"), dataset); | |
621 | return (MOUNT_SYSERR); | |
622 | } | |
623 | /* fallthru */ | |
624 | #endif | |
287be44f DS |
625 | default: |
626 | (void) fprintf(stderr, gettext("filesystem " | |
4070bfd8 BB |
627 | "'%s' can not be mounted: %s\n"), dataset, |
628 | strerror(errno)); | |
287be44f | 629 | return (MOUNT_USAGE); |
d53368f6 BB |
630 | } |
631 | } | |
632 | ||
633 | if (!nomtab && mtab_is_writeable()) { | |
3aff7755 | 634 | error = mtab_update(dataset, mntpoint, MNTTYPE_ZFS, mtabopt); |
d53368f6 BB |
635 | if (error) |
636 | return (error); | |
637 | } | |
638 | ||
639 | return (MOUNT_SUCCESS); | |
640 | } |