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) 2006, 2010, Oracle and/or its affiliates. All rights reserved.
24 * Copyright (c) 2012, 2015 by Delphix. All rights reserved.
25 * Copyright (c) 2012, Joyent, Inc. All rights reserved.
26 */
27
28 /*
29 * This file contains the functions used to support the ZFS integration
30 * with zones. This includes validation (e.g. zonecfg dataset), cloning,
31 * file system creation and destruction.
32 */
33
34 #include <stdio.h>
35 #include <errno.h>
36 #include <unistd.h>
37 #include <string.h>
38 #include <locale.h>
39 #include <libintl.h>
40 #include <sys/stat.h>
41 #include <sys/statvfs.h>
42 #include <libgen.h>
43 #include <libzonecfg.h>
44 #include <sys/mnttab.h>
45 #include <libzfs.h>
46 #include <sys/mntent.h>
47 #include <values.h>
48 #include <strings.h>
49 #include <assert.h>
50
51 #include "zoneadm.h"
52
53 libzfs_handle_t *g_zfs;
54
55 typedef struct zfs_mount_data {
56 char *match_name;
57 zfs_handle_t *match_handle;
58 } zfs_mount_data_t;
59
60 typedef struct zfs_snapshot_data {
61 char *match_name; /* zonename@SUNWzone */
62 int len; /* strlen of match_name */
63 int max; /* highest digit appended to snap name */
64 int num; /* number of snapshots to rename */
65 int cntr; /* counter for renaming snapshots */
66 } zfs_snapshot_data_t;
67
68 typedef struct clone_data {
69 zfs_handle_t *clone_zhp; /* clone dataset to promote */
70 time_t origin_creation; /* snapshot creation time of clone */
71 const char *snapshot; /* snapshot of dataset being demoted */
72 } clone_data_t;
73
74 /*
75 * A ZFS file system iterator call-back function which returns the
76 * zfs_handle_t for a ZFS file system on the specified mount point.
77 */
78 static int
match_mountpoint(zfs_handle_t * zhp,void * data)79 match_mountpoint(zfs_handle_t *zhp, void *data)
80 {
81 int res;
82 zfs_mount_data_t *cbp;
83 char mp[ZFS_MAXPROPLEN];
84
85 if (zfs_get_type(zhp) != ZFS_TYPE_FILESYSTEM) {
86 zfs_close(zhp);
87 return (0);
88 }
89
90 /* First check if the dataset is mounted. */
91 if (zfs_prop_get(zhp, ZFS_PROP_MOUNTED, mp, sizeof (mp), NULL, NULL,
92 0, B_FALSE) != 0 || strcmp(mp, "no") == 0) {
93 zfs_close(zhp);
94 return (0);
95 }
96
97 /* Now check mount point. */
98 if (zfs_prop_get(zhp, ZFS_PROP_MOUNTPOINT, mp, sizeof (mp), NULL, NULL,
99 0, B_FALSE) != 0) {
100 zfs_close(zhp);
101 return (0);
102 }
103
104 cbp = (zfs_mount_data_t *)data;
105
106 if (strcmp(mp, "legacy") == 0) {
107 /* If legacy, must look in mnttab for mountpoint. */
108 FILE *fp;
109 struct mnttab entry;
110 const char *nm;
111
112 nm = zfs_get_name(zhp);
113 if ((fp = fopen(MNTTAB, "r")) == NULL) {
114 zfs_close(zhp);
115 return (0);
116 }
117
118 while (getmntent(fp, &entry) == 0) {
119 if (strcmp(nm, entry.mnt_special) == 0) {
120 if (strcmp(entry.mnt_mountp, cbp->match_name)
121 == 0) {
122 (void) fclose(fp);
123 cbp->match_handle = zhp;
124 return (1);
125 }
126 break;
127 }
128 }
129 (void) fclose(fp);
130
131 } else if (strcmp(mp, cbp->match_name) == 0) {
132 cbp->match_handle = zhp;
133 return (1);
134 }
135
136 /* Iterate over any nested datasets. */
137 res = zfs_iter_filesystems(zhp, match_mountpoint, data);
138 zfs_close(zhp);
139 return (res);
140 }
141
142 /*
143 * Get ZFS handle for the specified mount point.
144 */
145 static zfs_handle_t *
mount2zhandle(char * mountpoint)146 mount2zhandle(char *mountpoint)
147 {
148 zfs_mount_data_t cb;
149
150 cb.match_name = mountpoint;
151 cb.match_handle = NULL;
152 (void) zfs_iter_root(g_zfs, match_mountpoint, &cb);
153 return (cb.match_handle);
154 }
155
156 /*
157 * Check if there is already a file system (zfs or any other type) mounted on
158 * path.
159 */
160 static boolean_t
is_mountpnt(char * path)161 is_mountpnt(char *path)
162 {
163 FILE *fp;
164 struct mnttab entry;
165
166 if ((fp = fopen(MNTTAB, "r")) == NULL)
167 return (B_FALSE);
168
169 while (getmntent(fp, &entry) == 0) {
170 if (strcmp(path, entry.mnt_mountp) == 0) {
171 (void) fclose(fp);
172 return (B_TRUE);
173 }
174 }
175
176 (void) fclose(fp);
177 return (B_FALSE);
178 }
179
180 /*
181 * Run the brand's pre-snapshot hook before we take a ZFS snapshot of the zone.
182 */
183 static int
pre_snapshot(char * presnapbuf)184 pre_snapshot(char *presnapbuf)
185 {
186 int status;
187
188 /* No brand-specific handler */
189 if (presnapbuf[0] == '\0')
190 return (Z_OK);
191
192 /* Run the hook */
193 status = do_subproc(presnapbuf);
194 if ((status = subproc_status(gettext("brand-specific presnapshot"),
195 status, B_FALSE)) != ZONE_SUBPROC_OK)
196 return (Z_ERR);
197
198 return (Z_OK);
199 }
200
201 /*
202 * Run the brand's post-snapshot hook after we take a ZFS snapshot of the zone.
203 */
204 static int
post_snapshot(char * postsnapbuf)205 post_snapshot(char *postsnapbuf)
206 {
207 int status;
208
209 /* No brand-specific handler */
210 if (postsnapbuf[0] == '\0')
211 return (Z_OK);
212
213 /* Run the hook */
214 status = do_subproc(postsnapbuf);
215 if ((status = subproc_status(gettext("brand-specific postsnapshot"),
216 status, B_FALSE)) != ZONE_SUBPROC_OK)
217 return (Z_ERR);
218
219 return (Z_OK);
220 }
221
222 /*
223 * This is a ZFS snapshot iterator call-back function which returns the
224 * highest number of SUNWzone snapshots that have been taken.
225 */
226 static int
get_snap_max(zfs_handle_t * zhp,void * data)227 get_snap_max(zfs_handle_t *zhp, void *data)
228 {
229 int res;
230 zfs_snapshot_data_t *cbp;
231
232 if (zfs_get_type(zhp) != ZFS_TYPE_SNAPSHOT) {
233 zfs_close(zhp);
234 return (0);
235 }
236
237 cbp = (zfs_snapshot_data_t *)data;
238
239 if (strncmp(zfs_get_name(zhp), cbp->match_name, cbp->len) == 0) {
240 char *nump;
241 int num;
242
243 cbp->num++;
244 nump = (char *)(zfs_get_name(zhp) + cbp->len);
245 num = atoi(nump);
246 if (num > cbp->max)
247 cbp->max = num;
248 }
249
250 res = zfs_iter_snapshots(zhp, get_snap_max, data);
251 zfs_close(zhp);
252 return (res);
253 }
254
255 /*
256 * Take a ZFS snapshot to be used for cloning the zone.
257 */
258 static int
take_snapshot(zfs_handle_t * zhp,char * snapshot_name,int snap_size,char * presnapbuf,char * postsnapbuf)259 take_snapshot(zfs_handle_t *zhp, char *snapshot_name, int snap_size,
260 char *presnapbuf, char *postsnapbuf)
261 {
262 int res;
263 char template[ZFS_MAX_DATASET_NAME_LEN];
264 zfs_snapshot_data_t cb;
265
266 /*
267 * First we need to figure out the next available name for the
268 * zone snapshot. Look through the list of zones snapshots for
269 * this file system to determine the maximum snapshot name.
270 */
271 if (snprintf(template, sizeof (template), "%s@SUNWzone",
272 zfs_get_name(zhp)) >= sizeof (template))
273 return (Z_ERR);
274
275 cb.match_name = template;
276 cb.len = strlen(template);
277 cb.max = 0;
278
279 if (zfs_iter_snapshots(zhp, get_snap_max, &cb) != 0)
280 return (Z_ERR);
281
282 cb.max++;
283
284 if (snprintf(snapshot_name, snap_size, "%s@SUNWzone%d",
285 zfs_get_name(zhp), cb.max) >= snap_size)
286 return (Z_ERR);
287
288 if (pre_snapshot(presnapbuf) != Z_OK)
289 return (Z_ERR);
290 res = zfs_snapshot(g_zfs, snapshot_name, B_FALSE, NULL);
291 if (post_snapshot(postsnapbuf) != Z_OK)
292 return (Z_ERR);
293
294 if (res != 0)
295 return (Z_ERR);
296 return (Z_OK);
297 }
298
299 /*
300 * We are using an explicit snapshot from some earlier point in time so
301 * we need to validate it. Run the brand specific hook.
302 */
303 static int
validate_snapshot(char * snapshot_name,char * snap_path,char * validsnapbuf)304 validate_snapshot(char *snapshot_name, char *snap_path, char *validsnapbuf)
305 {
306 int status;
307 char cmdbuf[MAXPATHLEN];
308
309 /* No brand-specific handler */
310 if (validsnapbuf[0] == '\0')
311 return (Z_OK);
312
313 /* pass args - snapshot_name & snap_path */
314 if (snprintf(cmdbuf, sizeof (cmdbuf), "%s %s %s", validsnapbuf,
315 snapshot_name, snap_path) >= sizeof (cmdbuf)) {
316 zerror("Command line too long");
317 return (Z_ERR);
318 }
319
320 /* Run the hook */
321 status = do_subproc(cmdbuf);
322 if ((status = subproc_status(gettext("brand-specific validatesnapshot"),
323 status, B_FALSE)) != ZONE_SUBPROC_OK)
324 return (Z_ERR);
325
326 return (Z_OK);
327 }
328
329 /*
330 * Remove the sw inventory file from inside this zonepath that we picked up out
331 * of the snapshot.
332 */
333 static int
clean_out_clone()334 clean_out_clone()
335 {
336 int err;
337 zone_dochandle_t handle;
338
339 if ((handle = zonecfg_init_handle()) == NULL) {
340 zperror(cmd_to_str(CMD_CLONE), B_TRUE);
341 return (Z_ERR);
342 }
343
344 if ((err = zonecfg_get_handle(target_zone, handle)) != Z_OK) {
345 errno = err;
346 zperror(cmd_to_str(CMD_CLONE), B_TRUE);
347 zonecfg_fini_handle(handle);
348 return (Z_ERR);
349 }
350
351 zonecfg_rm_detached(handle, B_FALSE);
352 zonecfg_fini_handle(handle);
353
354 return (Z_OK);
355 }
356
357 /*
358 * Make a ZFS clone on zonepath from snapshot_name.
359 */
360 static int
clone_snap(char * snapshot_name,char * zonepath)361 clone_snap(char *snapshot_name, char *zonepath)
362 {
363 int res = Z_OK;
364 int err;
365 zfs_handle_t *zhp;
366 zfs_handle_t *clone;
367 nvlist_t *props = NULL;
368
369 if ((zhp = zfs_open(g_zfs, snapshot_name, ZFS_TYPE_SNAPSHOT)) == NULL)
370 return (Z_NO_ENTRY);
371
372 (void) printf(gettext("Cloning snapshot %s\n"), snapshot_name);
373
374 /*
375 * We turn off zfs SHARENFS and SHARESMB properties on the
376 * zoneroot dataset in order to prevent the GZ from sharing
377 * NGZ data by accident.
378 */
379 if ((nvlist_alloc(&props, NV_UNIQUE_NAME, 0) != 0) ||
380 (nvlist_add_string(props, zfs_prop_to_name(ZFS_PROP_SHARENFS),
381 "off") != 0) ||
382 (nvlist_add_string(props, zfs_prop_to_name(ZFS_PROP_SHARESMB),
383 "off") != 0)) {
384 nvlist_free(props);
385 (void) fprintf(stderr, gettext("could not create ZFS clone "
386 "%s: out of memory\n"), zonepath);
387 return (Z_ERR);
388 }
389
390 err = zfs_clone(zhp, zonepath, props);
391 zfs_close(zhp);
392
393 nvlist_free(props);
394
395 if (err != 0)
396 return (Z_ERR);
397
398 /* create the mountpoint if necessary */
399 if ((clone = zfs_open(g_zfs, zonepath, ZFS_TYPE_DATASET)) == NULL)
400 return (Z_ERR);
401
402 /*
403 * The clone has been created so we need to print a diagnostic
404 * message if one of the following steps fails for some reason.
405 */
406 if (zfs_mount(clone, NULL, 0) != 0) {
407 (void) fprintf(stderr, gettext("could not mount ZFS clone "
408 "%s\n"), zfs_get_name(clone));
409 res = Z_ERR;
410
411 } else if (clean_out_clone() != Z_OK) {
412 (void) fprintf(stderr, gettext("could not remove the "
413 "software inventory from ZFS clone %s\n"),
414 zfs_get_name(clone));
415 res = Z_ERR;
416 }
417
418 zfs_close(clone);
419 return (res);
420 }
421
422 /*
423 * This function takes a zonepath and attempts to determine what the ZFS
424 * file system name (not mountpoint) should be for that path. We do not
425 * assume that zonepath is an existing directory or ZFS fs since we use
426 * this function as part of the process of creating a new ZFS fs or clone.
427 *
428 * The way this works is that we look at the parent directory of the zonepath
429 * to see if it is a ZFS fs. If it is, we get the name of that ZFS fs and
430 * append the last component of the zonepath to generate the ZFS name for the
431 * zonepath. This matches the algorithm that ZFS uses for automatically
432 * mounting a new fs after it is created.
433 *
434 * Although a ZFS fs can be mounted anywhere, we don't worry about handling
435 * all of the complexity that a user could possibly configure with arbitrary
436 * mounts since there is no way to generate a ZFS name from a random path in
437 * the file system. We only try to handle the automatic mounts that ZFS does
438 * for each file system. ZFS restricts this so that a new fs must be created
439 * in an existing parent ZFS fs. It then automatically mounts the new fs
440 * directly under the mountpoint for the parent fs using the last component
441 * of the name as the mountpoint directory.
442 *
443 * For example:
444 * Name Mountpoint
445 * space/eng/dev/test/zone1 /project1/eng/dev/test/zone1
446 *
447 * Return Z_OK if the path mapped to a ZFS file system name, otherwise return
448 * Z_ERR.
449 */
450 static int
path2name(char * zonepath,char * zfs_name,int len)451 path2name(char *zonepath, char *zfs_name, int len)
452 {
453 int res;
454 char *bnm, *dnm, *dname, *bname;
455 zfs_handle_t *zhp;
456 struct stat stbuf;
457
458 /*
459 * We need two tmp strings to handle paths directly in / (e.g. /foo)
460 * since dirname will overwrite the first char after "/" in this case.
461 */
462 if ((bnm = strdup(zonepath)) == NULL)
463 return (Z_ERR);
464
465 if ((dnm = strdup(zonepath)) == NULL) {
466 free(bnm);
467 return (Z_ERR);
468 }
469
470 bname = basename(bnm);
471 dname = dirname(dnm);
472
473 /*
474 * This is a quick test to save iterating over all of the zfs datasets
475 * on the system (which can be a lot). If the parent dir is not in a
476 * ZFS fs, then we're done.
477 */
478 if (stat(dname, &stbuf) != 0 || !S_ISDIR(stbuf.st_mode) ||
479 strcmp(stbuf.st_fstype, MNTTYPE_ZFS) != 0) {
480 free(bnm);
481 free(dnm);
482 return (Z_ERR);
483 }
484
485 /* See if the parent directory is its own ZFS dataset. */
486 if ((zhp = mount2zhandle(dname)) == NULL) {
487 /*
488 * The parent is not a ZFS dataset so we can't automatically
489 * create a dataset on the given path.
490 */
491 free(bnm);
492 free(dnm);
493 return (Z_ERR);
494 }
495
496 res = snprintf(zfs_name, len, "%s/%s", zfs_get_name(zhp), bname);
497
498 free(bnm);
499 free(dnm);
500 zfs_close(zhp);
501 if (res >= len)
502 return (Z_ERR);
503
504 return (Z_OK);
505 }
506
507 /*
508 * A ZFS file system iterator call-back function used to determine if the
509 * file system has dependents (snapshots & clones).
510 */
511 /* ARGSUSED */
512 static int
has_dependent(zfs_handle_t * zhp,void * data)513 has_dependent(zfs_handle_t *zhp, void *data)
514 {
515 zfs_close(zhp);
516 return (1);
517 }
518
519 /*
520 * Given a snapshot name, get the file system path where the snapshot lives.
521 * A snapshot name is of the form fs_name@snap_name. For example, snapshot
522 * pl/zones/z1@SUNWzone1 would have a path of
523 * /pl/zones/z1/.zfs/snapshot/SUNWzone1.
524 */
525 static int
snap2path(char * snap_name,char * path,int len)526 snap2path(char *snap_name, char *path, int len)
527 {
528 char *p;
529 zfs_handle_t *zhp;
530 char mp[ZFS_MAXPROPLEN];
531
532 if ((p = strrchr(snap_name, '@')) == NULL)
533 return (Z_ERR);
534
535 /* Get the file system name from the snap_name. */
536 *p = '\0';
537 zhp = zfs_open(g_zfs, snap_name, ZFS_TYPE_DATASET);
538 *p = '@';
539 if (zhp == NULL)
540 return (Z_ERR);
541
542 /* Get the file system mount point. */
543 if (zfs_prop_get(zhp, ZFS_PROP_MOUNTPOINT, mp, sizeof (mp), NULL, NULL,
544 0, B_FALSE) != 0) {
545 zfs_close(zhp);
546 return (Z_ERR);
547 }
548 zfs_close(zhp);
549
550 p++;
551 if (snprintf(path, len, "%s/.zfs/snapshot/%s", mp, p) >= len)
552 return (Z_ERR);
553
554 return (Z_OK);
555 }
556
557 /*
558 * This callback function is used to iterate through a snapshot's dependencies
559 * to find a filesystem that is a direct clone of the snapshot being iterated.
560 */
561 static int
get_direct_clone(zfs_handle_t * zhp,void * data)562 get_direct_clone(zfs_handle_t *zhp, void *data)
563 {
564 clone_data_t *cd = data;
565 char origin[ZFS_MAX_DATASET_NAME_LEN];
566 char ds_path[ZFS_MAX_DATASET_NAME_LEN];
567
568 if (zfs_get_type(zhp) != ZFS_TYPE_FILESYSTEM) {
569 zfs_close(zhp);
570 return (0);
571 }
572
573 (void) strlcpy(ds_path, zfs_get_name(zhp), sizeof (ds_path));
574
575 /* Make sure this is a direct clone of the snapshot we're iterating. */
576 if (zfs_prop_get(zhp, ZFS_PROP_ORIGIN, origin, sizeof (origin), NULL,
577 NULL, 0, B_FALSE) != 0 || strcmp(origin, cd->snapshot) != 0) {
578 zfs_close(zhp);
579 return (0);
580 }
581
582 if (cd->clone_zhp != NULL)
583 zfs_close(cd->clone_zhp);
584
585 cd->clone_zhp = zhp;
586 return (1);
587 }
588
589 /*
590 * A ZFS file system iterator call-back function used to determine the clone
591 * to promote. This function finds the youngest (i.e. last one taken) snapshot
592 * that has a clone. If found, it returns a reference to that clone in the
593 * callback data.
594 */
595 static int
find_clone(zfs_handle_t * zhp,void * data)596 find_clone(zfs_handle_t *zhp, void *data)
597 {
598 clone_data_t *cd = data;
599 time_t snap_creation;
600 int zret = 0;
601
602 /* If snapshot has no clones, skip it */
603 if (zfs_prop_get_int(zhp, ZFS_PROP_NUMCLONES) == 0) {
604 zfs_close(zhp);
605 return (0);
606 }
607
608 cd->snapshot = zfs_get_name(zhp);
609
610 /* Get the creation time of this snapshot */
611 snap_creation = (time_t)zfs_prop_get_int(zhp, ZFS_PROP_CREATION);
612
613 /*
614 * If this snapshot's creation time is greater than (i.e. younger than)
615 * the current youngest snapshot found, iterate this snapshot to
616 * get the right clone.
617 */
618 if (snap_creation >= cd->origin_creation) {
619 /*
620 * Iterate the dependents of this snapshot to find a clone
621 * that's a direct dependent.
622 */
623 if ((zret = zfs_iter_dependents(zhp, B_FALSE, get_direct_clone,
624 cd)) == -1) {
625 zfs_close(zhp);
626 return (1);
627 } else if (zret == 1) {
628 /*
629 * Found a clone, update the origin_creation time
630 * in the callback data.
631 */
632 cd->origin_creation = snap_creation;
633 }
634 }
635
636 zfs_close(zhp);
637 return (0);
638 }
639
640 /*
641 * A ZFS file system iterator call-back function used to remove standalone
642 * snapshots.
643 */
644 /* ARGSUSED */
645 static int
rm_snap(zfs_handle_t * zhp,void * data)646 rm_snap(zfs_handle_t *zhp, void *data)
647 {
648 /* If snapshot has clones, something is wrong */
649 if (zfs_prop_get_int(zhp, ZFS_PROP_NUMCLONES) != 0) {
650 zfs_close(zhp);
651 return (1);
652 }
653
654 if (zfs_unmount(zhp, NULL, 0) == 0) {
655 (void) zfs_destroy(zhp, B_FALSE);
656 }
657
658 zfs_close(zhp);
659 return (0);
660 }
661
662 /*
663 * A ZFS snapshot iterator call-back function which renames snapshots.
664 */
665 static int
rename_snap(zfs_handle_t * zhp,void * data)666 rename_snap(zfs_handle_t *zhp, void *data)
667 {
668 int res;
669 zfs_snapshot_data_t *cbp;
670 char template[ZFS_MAX_DATASET_NAME_LEN];
671
672 cbp = (zfs_snapshot_data_t *)data;
673
674 /*
675 * When renaming snapshots with the iterator, the iterator can see
676 * the same snapshot after we've renamed up in the namespace. To
677 * prevent this we check the count for the number of snapshots we have
678 * to rename and stop at that point.
679 */
680 if (cbp->cntr >= cbp->num) {
681 zfs_close(zhp);
682 return (0);
683 }
684
685 if (zfs_get_type(zhp) != ZFS_TYPE_SNAPSHOT) {
686 zfs_close(zhp);
687 return (0);
688 }
689
690 /* Only rename the snapshots we automatically generate when we clone. */
691 if (strncmp(zfs_get_name(zhp), cbp->match_name, cbp->len) != 0) {
692 zfs_close(zhp);
693 return (0);
694 }
695
696 (void) snprintf(template, sizeof (template), "%s%d", cbp->match_name,
697 cbp->max++);
698
699 res = (zfs_rename(zhp, template, B_FALSE, B_FALSE) != 0);
700 if (res != 0)
701 (void) fprintf(stderr, gettext("failed to rename snapshot %s "
702 "to %s: %s\n"), zfs_get_name(zhp), template,
703 libzfs_error_description(g_zfs));
704
705 cbp->cntr++;
706
707 zfs_close(zhp);
708 return (res);
709 }
710
711 /*
712 * Rename the source dataset's snapshots that are automatically generated when
713 * we clone a zone so that there won't be a name collision when we promote the
714 * cloned dataset. Once the snapshots have been renamed, then promote the
715 * clone.
716 *
717 * The snapshot rename process gets the highest number on the snapshot names
718 * (the format is zonename@SUNWzoneXX where XX are digits) on both the source
719 * and clone datasets, then renames the source dataset snapshots starting at
720 * the next number.
721 */
722 static int
promote_clone(zfs_handle_t * src_zhp,zfs_handle_t * cln_zhp)723 promote_clone(zfs_handle_t *src_zhp, zfs_handle_t *cln_zhp)
724 {
725 zfs_snapshot_data_t sd;
726 char nm[ZFS_MAX_DATASET_NAME_LEN];
727 char template[ZFS_MAX_DATASET_NAME_LEN];
728
729 (void) strlcpy(nm, zfs_get_name(cln_zhp), sizeof (nm));
730 /*
731 * Start by getting the clone's snapshot max which we use
732 * during the rename of the original dataset's snapshots.
733 */
734 (void) snprintf(template, sizeof (template), "%s@SUNWzone", nm);
735 sd.match_name = template;
736 sd.len = strlen(template);
737 sd.max = 0;
738
739 if (zfs_iter_snapshots(cln_zhp, get_snap_max, &sd) != 0)
740 return (Z_ERR);
741
742 /*
743 * Now make sure the source's snapshot max is at least as high as
744 * the clone's snapshot max.
745 */
746 (void) snprintf(template, sizeof (template), "%s@SUNWzone",
747 zfs_get_name(src_zhp));
748 sd.match_name = template;
749 sd.len = strlen(template);
750 sd.num = 0;
751
752 if (zfs_iter_snapshots(src_zhp, get_snap_max, &sd) != 0)
753 return (Z_ERR);
754
755 /*
756 * Now rename the source dataset's snapshots so there's no
757 * conflict when we promote the clone.
758 */
759 sd.max++;
760 sd.cntr = 0;
761 if (zfs_iter_snapshots(src_zhp, rename_snap, &sd) != 0)
762 return (Z_ERR);
763
764 /* close and reopen the clone dataset to get the latest info */
765 zfs_close(cln_zhp);
766 if ((cln_zhp = zfs_open(g_zfs, nm, ZFS_TYPE_FILESYSTEM)) == NULL)
767 return (Z_ERR);
768
769 if (zfs_promote(cln_zhp) != 0) {
770 (void) fprintf(stderr, gettext("failed to promote %s: %s\n"),
771 nm, libzfs_error_description(g_zfs));
772 return (Z_ERR);
773 }
774
775 zfs_close(cln_zhp);
776 return (Z_OK);
777 }
778
779 /*
780 * Promote the youngest clone. That clone will then become the origin of all
781 * of the other clones that were hanging off of the source dataset.
782 */
783 int
promote_all_clones(zfs_handle_t * zhp)784 promote_all_clones(zfs_handle_t *zhp)
785 {
786 clone_data_t cd;
787 char nm[ZFS_MAX_DATASET_NAME_LEN];
788
789 cd.clone_zhp = NULL;
790 cd.origin_creation = 0;
791 cd.snapshot = NULL;
792
793 if (zfs_iter_snapshots(zhp, find_clone, &cd) != 0) {
794 zfs_close(zhp);
795 return (Z_ERR);
796 }
797
798 /* Nothing to promote. */
799 if (cd.clone_zhp == NULL)
800 return (Z_OK);
801
802 /* Found the youngest clone to promote. Promote it. */
803 if (promote_clone(zhp, cd.clone_zhp) != 0) {
804 zfs_close(cd.clone_zhp);
805 zfs_close(zhp);
806 return (Z_ERR);
807 }
808
809 /* close and reopen the main dataset to get the latest info */
810 (void) strlcpy(nm, zfs_get_name(zhp), sizeof (nm));
811 zfs_close(zhp);
812 if ((zhp = zfs_open(g_zfs, nm, ZFS_TYPE_FILESYSTEM)) == NULL)
813 return (Z_ERR);
814
815 return (Z_OK);
816 }
817
818 /*
819 * Clone a pre-existing ZFS snapshot, either by making a direct ZFS clone, if
820 * possible, or by copying the data from the snapshot to the zonepath.
821 */
822 int
clone_snapshot_zfs(char * snap_name,char * zonepath,char * validatesnap)823 clone_snapshot_zfs(char *snap_name, char *zonepath, char *validatesnap)
824 {
825 int err = Z_OK;
826 char clone_name[MAXPATHLEN];
827 char snap_path[MAXPATHLEN];
828
829 if (snap2path(snap_name, snap_path, sizeof (snap_path)) != Z_OK) {
830 (void) fprintf(stderr, gettext("unable to find path for %s.\n"),
831 snap_name);
832 return (Z_ERR);
833 }
834
835 if (validate_snapshot(snap_name, snap_path, validatesnap) != Z_OK)
836 return (Z_NO_ENTRY);
837
838 /*
839 * The zonepath cannot be ZFS cloned, try to copy the data from
840 * within the snapshot to the zonepath.
841 */
842 if (path2name(zonepath, clone_name, sizeof (clone_name)) != Z_OK) {
843 if ((err = clone_copy(snap_path, zonepath)) == Z_OK)
844 if (clean_out_clone() != Z_OK)
845 (void) fprintf(stderr,
846 gettext("could not remove the "
847 "software inventory from %s\n"), zonepath);
848
849 return (err);
850 }
851
852 if ((err = clone_snap(snap_name, clone_name)) != Z_OK) {
853 if (err != Z_NO_ENTRY) {
854 /*
855 * Cloning the snapshot failed. Fall back to trying
856 * to install the zone by copying from the snapshot.
857 */
858 if ((err = clone_copy(snap_path, zonepath)) == Z_OK)
859 if (clean_out_clone() != Z_OK)
860 (void) fprintf(stderr,
861 gettext("could not remove the "
862 "software inventory from %s\n"),
863 zonepath);
864 } else {
865 /*
866 * The snapshot is unusable for some reason so restore
867 * the zone state to configured since we were unable to
868 * actually do anything about getting the zone
869 * installed.
870 */
871 int tmp;
872
873 if ((tmp = zone_set_state(target_zone,
874 ZONE_STATE_CONFIGURED)) != Z_OK) {
875 errno = tmp;
876 zperror2(target_zone,
877 gettext("could not set state"));
878 }
879 }
880 }
881
882 return (err);
883 }
884
885 /*
886 * Attempt to clone a source_zone to a target zonepath by using a ZFS clone.
887 */
888 int
clone_zfs(char * source_zonepath,char * zonepath,char * presnapbuf,char * postsnapbuf)889 clone_zfs(char *source_zonepath, char *zonepath, char *presnapbuf,
890 char *postsnapbuf)
891 {
892 zfs_handle_t *zhp;
893 char clone_name[MAXPATHLEN];
894 char snap_name[MAXPATHLEN];
895
896 /*
897 * Try to get a zfs handle for the source_zonepath. If this fails
898 * the source_zonepath is not ZFS so return an error.
899 */
900 if ((zhp = mount2zhandle(source_zonepath)) == NULL)
901 return (Z_ERR);
902
903 /*
904 * Check if there is a file system already mounted on zonepath. If so,
905 * we can't clone to the path so we should fall back to copying.
906 */
907 if (is_mountpnt(zonepath)) {
908 zfs_close(zhp);
909 (void) fprintf(stderr,
910 gettext("A file system is already mounted on %s,\n"
911 "preventing use of a ZFS clone.\n"), zonepath);
912 return (Z_ERR);
913 }
914
915 /*
916 * Instead of using path2name to get the clone name from the zonepath,
917 * we could generate a name from the source zone ZFS name. However,
918 * this would mean we would create the clone under the ZFS fs of the
919 * source instead of what the zonepath says. For example,
920 *
921 * source_zonepath zonepath
922 * /pl/zones/dev/z1 /pl/zones/deploy/z2
923 *
924 * We don't want the clone to be under "dev", we want it under
925 * "deploy", so that we can leverage the normal attribute inheritance
926 * that ZFS provides in the fs hierarchy.
927 */
928 if (path2name(zonepath, clone_name, sizeof (clone_name)) != Z_OK) {
929 zfs_close(zhp);
930 return (Z_ERR);
931 }
932
933 if (take_snapshot(zhp, snap_name, sizeof (snap_name), presnapbuf,
934 postsnapbuf) != Z_OK) {
935 zfs_close(zhp);
936 return (Z_ERR);
937 }
938 zfs_close(zhp);
939
940 if (clone_snap(snap_name, clone_name) != Z_OK) {
941 /* Clean up the snapshot we just took. */
942 if ((zhp = zfs_open(g_zfs, snap_name, ZFS_TYPE_SNAPSHOT))
943 != NULL) {
944 if (zfs_unmount(zhp, NULL, 0) == 0)
945 (void) zfs_destroy(zhp, B_FALSE);
946 zfs_close(zhp);
947 }
948
949 return (Z_ERR);
950 }
951
952 (void) printf(gettext("Instead of copying, a ZFS clone has been "
953 "created for this zone.\n"));
954
955 return (Z_OK);
956 }
957
958 /*
959 * Attempt to create a ZFS file system for the specified zonepath.
960 * We either will successfully create a ZFS file system and get it mounted
961 * on the zonepath or we don't. The caller doesn't care since a regular
962 * directory is used for the zonepath if no ZFS file system is mounted there.
963 */
964 void
create_zfs_zonepath(char * zonepath)965 create_zfs_zonepath(char *zonepath)
966 {
967 zfs_handle_t *zhp;
968 char zfs_name[MAXPATHLEN];
969 nvlist_t *props = NULL;
970
971 if (path2name(zonepath, zfs_name, sizeof (zfs_name)) != Z_OK)
972 return;
973
974 /* Check if the dataset already exists. */
975 if ((zhp = zfs_open(g_zfs, zfs_name, ZFS_TYPE_DATASET)) != NULL) {
976 zfs_close(zhp);
977 return;
978 }
979
980 /*
981 * We turn off zfs SHARENFS and SHARESMB properties on the
982 * zoneroot dataset in order to prevent the GZ from sharing
983 * NGZ data by accident.
984 */
985 if ((nvlist_alloc(&props, NV_UNIQUE_NAME, 0) != 0) ||
986 (nvlist_add_string(props, zfs_prop_to_name(ZFS_PROP_SHARENFS),
987 "off") != 0) ||
988 (nvlist_add_string(props, zfs_prop_to_name(ZFS_PROP_SHARESMB),
989 "off") != 0)) {
990 nvlist_free(props);
991 (void) fprintf(stderr, gettext("cannot create ZFS dataset %s: "
992 "out of memory\n"), zfs_name);
993 }
994
995 if (zfs_create(g_zfs, zfs_name, ZFS_TYPE_FILESYSTEM, props) != 0 ||
996 (zhp = zfs_open(g_zfs, zfs_name, ZFS_TYPE_DATASET)) == NULL) {
997 (void) fprintf(stderr, gettext("cannot create ZFS dataset %s: "
998 "%s\n"), zfs_name, libzfs_error_description(g_zfs));
999 nvlist_free(props);
1000 return;
1001 }
1002
1003 nvlist_free(props);
1004
1005 if (zfs_mount(zhp, NULL, 0) != 0) {
1006 (void) fprintf(stderr, gettext("cannot mount ZFS dataset %s: "
1007 "%s\n"), zfs_name, libzfs_error_description(g_zfs));
1008 (void) zfs_destroy(zhp, B_FALSE);
1009 } else {
1010 if (chmod(zonepath, S_IRWXU) != 0) {
1011 (void) fprintf(stderr, gettext("file system %s "
1012 "successfully created, but chmod %o failed: %s\n"),
1013 zfs_name, S_IRWXU, strerror(errno));
1014 (void) destroy_zfs(zonepath);
1015 } else {
1016 (void) printf(gettext("A ZFS file system has been "
1017 "created for this zone.\n"));
1018 }
1019 }
1020
1021 zfs_close(zhp);
1022 }
1023
1024 /*
1025 * If the zonepath is a ZFS file system, attempt to destroy it. We return Z_OK
1026 * if we were able to zfs_destroy the zonepath, otherwise we return Z_ERR
1027 * which means the caller should clean up the zonepath in the traditional
1028 * way.
1029 */
1030 int
destroy_zfs(char * zonepath)1031 destroy_zfs(char *zonepath)
1032 {
1033 zfs_handle_t *zhp;
1034 boolean_t is_clone = B_FALSE;
1035 char origin[ZFS_MAXPROPLEN];
1036
1037 if ((zhp = mount2zhandle(zonepath)) == NULL)
1038 return (Z_ERR);
1039
1040 if (promote_all_clones(zhp) != 0)
1041 return (Z_ERR);
1042
1043 /* Now cleanup any snapshots remaining. */
1044 if (zfs_iter_snapshots(zhp, rm_snap, NULL) != 0) {
1045 zfs_close(zhp);
1046 return (Z_ERR);
1047 }
1048
1049 /*
1050 * We can't destroy the file system if it has still has dependents.
1051 * There shouldn't be any at this point, but we'll double check.
1052 */
1053 if (zfs_iter_dependents(zhp, B_TRUE, has_dependent, NULL) != 0) {
1054 (void) fprintf(stderr, gettext("zfs destroy %s failed: the "
1055 "dataset still has dependents\n"), zfs_get_name(zhp));
1056 zfs_close(zhp);
1057 return (Z_ERR);
1058 }
1059
1060 /*
1061 * This might be a clone. Try to get the snapshot so we can attempt
1062 * to destroy that as well.
1063 */
1064 if (zfs_prop_get(zhp, ZFS_PROP_ORIGIN, origin, sizeof (origin), NULL,
1065 NULL, 0, B_FALSE) == 0)
1066 is_clone = B_TRUE;
1067
1068 if (zfs_unmount(zhp, NULL, 0) != 0) {
1069 (void) fprintf(stderr, gettext("zfs unmount %s failed: %s\n"),
1070 zfs_get_name(zhp), libzfs_error_description(g_zfs));
1071 zfs_close(zhp);
1072 return (Z_ERR);
1073 }
1074
1075 if (zfs_destroy(zhp, B_FALSE) != 0) {
1076 /*
1077 * If the destroy fails for some reason, try to remount
1078 * the file system so that we can use "rm -rf" to clean up
1079 * instead.
1080 */
1081 (void) fprintf(stderr, gettext("zfs destroy %s failed: %s\n"),
1082 zfs_get_name(zhp), libzfs_error_description(g_zfs));
1083 (void) zfs_mount(zhp, NULL, 0);
1084 zfs_close(zhp);
1085 return (Z_ERR);
1086 }
1087
1088 /*
1089 * If the zone has ever been moved then the mountpoint dir will not be
1090 * cleaned up by the zfs_destroy(). To handle this case try to clean
1091 * it up now but don't worry if it fails, that will be normal.
1092 */
1093 (void) rmdir(zonepath);
1094
1095 (void) printf(gettext("The ZFS file system for this zone has been "
1096 "destroyed.\n"));
1097
1098 if (is_clone) {
1099 zfs_handle_t *ohp;
1100
1101 /*
1102 * Try to clean up the snapshot that the clone was taken from.
1103 */
1104 if ((ohp = zfs_open(g_zfs, origin,
1105 ZFS_TYPE_SNAPSHOT)) != NULL) {
1106 if (zfs_iter_dependents(ohp, B_TRUE, has_dependent,
1107 NULL) == 0 && zfs_unmount(ohp, NULL, 0) == 0)
1108 (void) zfs_destroy(ohp, B_FALSE);
1109 zfs_close(ohp);
1110 }
1111 }
1112
1113 zfs_close(zhp);
1114 return (Z_OK);
1115 }
1116
1117 /*
1118 * Return true if the path is its own zfs file system. We determine this
1119 * by stat-ing the path to see if it is zfs and stat-ing the parent to see
1120 * if it is a different fs.
1121 */
1122 boolean_t
is_zonepath_zfs(char * zonepath)1123 is_zonepath_zfs(char *zonepath)
1124 {
1125 int res;
1126 char *path;
1127 char *parent;
1128 struct statvfs64 buf1, buf2;
1129
1130 if (statvfs64(zonepath, &buf1) != 0)
1131 return (B_FALSE);
1132
1133 if (strcmp(buf1.f_basetype, "zfs") != 0)
1134 return (B_FALSE);
1135
1136 if ((path = strdup(zonepath)) == NULL)
1137 return (B_FALSE);
1138
1139 parent = dirname(path);
1140 res = statvfs64(parent, &buf2);
1141 free(path);
1142
1143 if (res != 0)
1144 return (B_FALSE);
1145
1146 if (buf1.f_fsid == buf2.f_fsid)
1147 return (B_FALSE);
1148
1149 return (B_TRUE);
1150 }
1151
1152 /*
1153 * Implement the fast move of a ZFS file system by simply updating the
1154 * mountpoint. Since it is file system already, we don't have the
1155 * issue of cross-file system copying.
1156 */
1157 int
move_zfs(char * zonepath,char * new_zonepath)1158 move_zfs(char *zonepath, char *new_zonepath)
1159 {
1160 int ret = Z_ERR;
1161 zfs_handle_t *zhp;
1162
1163 if ((zhp = mount2zhandle(zonepath)) == NULL)
1164 return (Z_ERR);
1165
1166 if (zfs_prop_set(zhp, zfs_prop_to_name(ZFS_PROP_MOUNTPOINT),
1167 new_zonepath) == 0) {
1168 /*
1169 * Clean up the old mount point. We ignore any failure since
1170 * the zone is already successfully mounted on the new path.
1171 */
1172 (void) rmdir(zonepath);
1173 ret = Z_OK;
1174 }
1175
1176 zfs_close(zhp);
1177
1178 return (ret);
1179 }
1180
1181 /*
1182 * Validate that the given dataset exists on the system, and that neither it nor
1183 * its children are zvols.
1184 *
1185 * Note that we don't do anything with the 'zoned' property here. All
1186 * management is done in zoneadmd when the zone is actually rebooted. This
1187 * allows us to automatically set the zoned property even when a zone is
1188 * rebooted by the administrator.
1189 */
1190 int
verify_datasets(zone_dochandle_t handle)1191 verify_datasets(zone_dochandle_t handle)
1192 {
1193 int return_code = Z_OK;
1194 struct zone_dstab dstab;
1195 zfs_handle_t *zhp;
1196 char propbuf[ZFS_MAXPROPLEN];
1197 char source[ZFS_MAX_DATASET_NAME_LEN];
1198 zprop_source_t srctype;
1199
1200 if (zonecfg_setdsent(handle) != Z_OK) {
1201 /*
1202 * TRANSLATION_NOTE
1203 * zfs and dataset are literals that should not be translated.
1204 */
1205 (void) fprintf(stderr, gettext("could not verify zfs datasets: "
1206 "unable to enumerate datasets\n"));
1207 return (Z_ERR);
1208 }
1209
1210 while (zonecfg_getdsent(handle, &dstab) == Z_OK) {
1211
1212 if ((zhp = zfs_open(g_zfs, dstab.zone_dataset_name,
1213 ZFS_TYPE_FILESYSTEM | ZFS_TYPE_VOLUME)) == NULL) {
1214 (void) fprintf(stderr, gettext("could not verify zfs "
1215 "dataset %s: %s\n"), dstab.zone_dataset_name,
1216 libzfs_error_description(g_zfs));
1217 return_code = Z_ERR;
1218 continue;
1219 }
1220
1221 if (zfs_prop_get(zhp, ZFS_PROP_MOUNTPOINT, propbuf,
1222 sizeof (propbuf), &srctype, source,
1223 sizeof (source), 0) == 0 &&
1224 (srctype == ZPROP_SRC_INHERITED)) {
1225 (void) fprintf(stderr, gettext("could not verify zfs "
1226 "dataset %s: mountpoint cannot be inherited\n"),
1227 dstab.zone_dataset_name);
1228 return_code = Z_ERR;
1229 zfs_close(zhp);
1230 continue;
1231 }
1232
1233 zfs_close(zhp);
1234 }
1235 (void) zonecfg_enddsent(handle);
1236
1237 return (return_code);
1238 }
1239
1240 /*
1241 * Verify that the ZFS dataset exists, and its mountpoint
1242 * property is set to "legacy".
1243 */
1244 int
verify_fs_zfs(struct zone_fstab * fstab)1245 verify_fs_zfs(struct zone_fstab *fstab)
1246 {
1247 zfs_handle_t *zhp;
1248 char propbuf[ZFS_MAXPROPLEN];
1249
1250 if ((zhp = zfs_open(g_zfs, fstab->zone_fs_special,
1251 ZFS_TYPE_DATASET)) == NULL) {
1252 (void) fprintf(stderr, gettext("could not verify fs %s: "
1253 "could not access zfs dataset '%s'\n"),
1254 fstab->zone_fs_dir, fstab->zone_fs_special);
1255 return (Z_ERR);
1256 }
1257
1258 if (zfs_get_type(zhp) != ZFS_TYPE_FILESYSTEM) {
1259 (void) fprintf(stderr, gettext("cannot verify fs %s: "
1260 "'%s' is not a file system\n"),
1261 fstab->zone_fs_dir, fstab->zone_fs_special);
1262 zfs_close(zhp);
1263 return (Z_ERR);
1264 }
1265
1266 if (zfs_prop_get(zhp, ZFS_PROP_MOUNTPOINT, propbuf, sizeof (propbuf),
1267 NULL, NULL, 0, 0) != 0 || strcmp(propbuf, "legacy") != 0) {
1268 (void) fprintf(stderr, gettext("could not verify fs %s: "
1269 "zfs '%s' mountpoint is not \"legacy\"\n"),
1270 fstab->zone_fs_dir, fstab->zone_fs_special);
1271 zfs_close(zhp);
1272 return (Z_ERR);
1273 }
1274
1275 zfs_close(zhp);
1276 return (Z_OK);
1277 }
1278
1279 /*
1280 * Destroy the specified mnttab structure that was created by mnttab_dup().
1281 * NOTE: The structure's mnt_time field isn't freed.
1282 */
1283 static void
mnttab_destroy(struct mnttab * tabp)1284 mnttab_destroy(struct mnttab *tabp)
1285 {
1286 assert(tabp != NULL);
1287
1288 free(tabp->mnt_mountp);
1289 free(tabp->mnt_special);
1290 free(tabp->mnt_fstype);
1291 free(tabp->mnt_mntopts);
1292 free(tabp);
1293 }
1294
1295 /*
1296 * Duplicate the specified mnttab structure. The mnt_mountp and mnt_time
1297 * fields aren't duplicated. This function returns a pointer to the new mnttab
1298 * structure or NULL if an error occurred. If an error occurs, then this
1299 * function sets errno to reflect the error. mnttab structures created by
1300 * this function should be destroyed via mnttab_destroy().
1301 */
1302 static struct mnttab *
mnttab_dup(const struct mnttab * srcp)1303 mnttab_dup(const struct mnttab *srcp)
1304 {
1305 struct mnttab *retval;
1306
1307 assert(srcp != NULL);
1308
1309 retval = (struct mnttab *)calloc(1, sizeof (*retval));
1310 if (retval == NULL) {
1311 errno = ENOMEM;
1312 return (NULL);
1313 }
1314 if (srcp->mnt_special != NULL) {
1315 retval->mnt_special = strdup(srcp->mnt_special);
1316 if (retval->mnt_special == NULL)
1317 goto err;
1318 }
1319 if (srcp->mnt_fstype != NULL) {
1320 retval->mnt_fstype = strdup(srcp->mnt_fstype);
1321 if (retval->mnt_fstype == NULL)
1322 goto err;
1323 }
1324 retval->mnt_mntopts = (char *)malloc(MAX_MNTOPT_STR * sizeof (char));
1325 if (retval->mnt_mntopts == NULL)
1326 goto err;
1327 if (srcp->mnt_mntopts != NULL) {
1328 if (strlcpy(retval->mnt_mntopts, srcp->mnt_mntopts,
1329 MAX_MNTOPT_STR * sizeof (char)) >= MAX_MNTOPT_STR *
1330 sizeof (char)) {
1331 mnttab_destroy(retval);
1332 errno = EOVERFLOW; /* similar to mount(2) behavior */
1333 return (NULL);
1334 }
1335 } else {
1336 retval->mnt_mntopts[0] = '\0';
1337 }
1338 return (retval);
1339
1340 err:
1341 mnttab_destroy(retval);
1342 errno = ENOMEM;
1343 return (NULL);
1344 }
1345
1346 /*
1347 * Determine whether the specified ZFS dataset's mountpoint property is set
1348 * to "legacy". If the specified dataset does not have a legacy mountpoint,
1349 * then the string pointer to which the mountpoint argument points is assigned
1350 * a dynamically-allocated string containing the dataset's mountpoint
1351 * property. If the dataset's mountpoint property is "legacy" or a libzfs
1352 * error occurs, then the string pointer to which the mountpoint argument
1353 * points isn't modified.
1354 *
1355 * This function returns B_TRUE if it doesn't encounter any fatal errors.
1356 * It returns B_FALSE if it encounters a fatal error and sets errno to the
1357 * appropriate error code.
1358 */
1359 static boolean_t
get_zfs_non_legacy_mountpoint(const char * dataset_name,char ** mountpoint)1360 get_zfs_non_legacy_mountpoint(const char *dataset_name, char **mountpoint)
1361 {
1362 zfs_handle_t *zhp;
1363 char propbuf[ZFS_MAXPROPLEN];
1364
1365 assert(dataset_name != NULL);
1366 assert(mountpoint != NULL);
1367
1368 if ((zhp = zfs_open(g_zfs, dataset_name, ZFS_TYPE_DATASET)) == NULL) {
1369 errno = EINVAL;
1370 return (B_FALSE);
1371 }
1372 if (zfs_prop_get(zhp, ZFS_PROP_MOUNTPOINT, propbuf, sizeof (propbuf),
1373 NULL, NULL, 0, 0) != 0) {
1374 zfs_close(zhp);
1375 errno = EINVAL;
1376 return (B_FALSE);
1377 }
1378 zfs_close(zhp);
1379 if (strcmp(propbuf, "legacy") != 0) {
1380 if ((*mountpoint = strdup(propbuf)) == NULL) {
1381 errno = ENOMEM;
1382 return (B_FALSE);
1383 }
1384 }
1385 return (B_TRUE);
1386 }
1387
1388
1389 /*
1390 * This zonecfg_find_mounts() callback records information about mounts of
1391 * interest in a zonepath. It also tallies the number of zone
1392 * root overlay mounts and the number of unexpected mounts found.
1393 * This function outputs errors using zerror() if it finds unexpected
1394 * mounts. cookiep should point to an initialized zone_mounts_t structure.
1395 *
1396 * This function returns zero on success and a nonzero value on failure.
1397 */
1398 static int
zone_mounts_cb(const struct mnttab * mountp,void * cookiep)1399 zone_mounts_cb(const struct mnttab *mountp, void *cookiep)
1400 {
1401 zone_mounts_t *mounts;
1402 const char *zone_mount_dir;
1403
1404 assert(mountp != NULL);
1405 assert(cookiep != NULL);
1406
1407 mounts = (zone_mounts_t *)cookiep;
1408 zone_mount_dir = mountp->mnt_mountp + mounts->zonepath_len;
1409 if (strcmp(zone_mount_dir, "/root") == 0) {
1410 /*
1411 * Check for an overlay mount. If we already detected a /root
1412 * mount, then the current mount must be an overlay mount.
1413 */
1414 if (mounts->root_mnttab != NULL) {
1415 mounts->num_root_overlay_mounts++;
1416 return (0);
1417 }
1418
1419 /*
1420 * Store the root mount's mnttab information in the
1421 * zone_mounts_t structure for future use.
1422 */
1423 if ((mounts->root_mnttab = mnttab_dup(mountp)) == NULL) {
1424 zperror(cmd_to_str(CMD_MOVE), B_FALSE);
1425 return (-1);
1426 }
1427
1428 /*
1429 * Determine if the filesystem is a ZFS filesystem with a
1430 * non-legacy mountpoint. If it is, then set the root
1431 * filesystem's mnttab's mnt_mountp field to a non-NULL
1432 * value, which will serve as a flag to indicate this special
1433 * condition.
1434 */
1435 if (strcmp(mountp->mnt_fstype, MNTTYPE_ZFS) == 0 &&
1436 get_zfs_non_legacy_mountpoint(mountp->mnt_special,
1437 &mounts->root_mnttab->mnt_mountp) != B_TRUE) {
1438 zperror(cmd_to_str(CMD_MOVE), B_FALSE);
1439 return (-1);
1440 }
1441 } else {
1442 /*
1443 * An unexpected mount was found. Notify the user.
1444 */
1445 if (mounts->num_unexpected_mounts == 0)
1446 zerror(gettext("These file systems are mounted on "
1447 "subdirectories of %s.\n"), mounts->zonepath);
1448 mounts->num_unexpected_mounts++;
1449 (void) zfm_print(mountp, NULL);
1450 }
1451 return (0);
1452 }
1453
1454 /*
1455 * Initialize the specified zone_mounts_t structure for the given zonepath.
1456 * If this function succeeds, it returns zero and the specified zone_mounts_t
1457 * structure contains information about mounts in the specified zonepath.
1458 * The function returns a nonzero value if it fails. The zone_mounts_t
1459 * structure doesn't need be destroyed via zone_mounts_destroy() if this
1460 * function fails.
1461 */
1462 int
zone_mounts_init(zone_mounts_t * mounts,const char * zonepath)1463 zone_mounts_init(zone_mounts_t *mounts, const char *zonepath)
1464 {
1465 assert(mounts != NULL);
1466 assert(zonepath != NULL);
1467
1468 bzero(mounts, sizeof (*mounts));
1469 if ((mounts->zonepath = strdup(zonepath)) == NULL) {
1470 zerror(gettext("the process ran out of memory while checking "
1471 "for mounts in zonepath %s."), zonepath);
1472 return (-1);
1473 }
1474 mounts->zonepath_len = strlen(zonepath);
1475 if (zonecfg_find_mounts((char *)zonepath, zone_mounts_cb, mounts) ==
1476 -1) {
1477 zerror(gettext("an error occurred while checking for mounts "
1478 "in zonepath %s."), zonepath);
1479 zone_mounts_destroy(mounts);
1480 return (-1);
1481 }
1482 return (0);
1483 }
1484
1485 /*
1486 * Destroy the memory used by the specified zone_mounts_t structure's fields.
1487 * This function doesn't free the memory occupied by the structure itself
1488 * (i.e., it doesn't free the parameter).
1489 */
1490 void
zone_mounts_destroy(zone_mounts_t * mounts)1491 zone_mounts_destroy(zone_mounts_t *mounts)
1492 {
1493 assert(mounts != NULL);
1494
1495 free(mounts->zonepath);
1496 if (mounts->root_mnttab != NULL)
1497 mnttab_destroy(mounts->root_mnttab);
1498 }
1499
1500 /*
1501 * Mount a moving zone's root filesystem (if it had a root filesystem mount
1502 * prior to the move) using the specified zonepath. mounts should refer to
1503 * the zone_mounts_t structure describing the zone's mount information.
1504 *
1505 * This function returns zero if the mount succeeds and a nonzero value
1506 * if it doesn't.
1507 */
1508 int
zone_mount_rootfs(zone_mounts_t * mounts,const char * zonepath)1509 zone_mount_rootfs(zone_mounts_t *mounts, const char *zonepath)
1510 {
1511 char zoneroot[MAXPATHLEN];
1512 struct mnttab *mtab;
1513 int flags;
1514
1515 assert(mounts != NULL);
1516 assert(zonepath != NULL);
1517
1518 /*
1519 * If there isn't a root filesystem, then don't do anything.
1520 */
1521 mtab = mounts->root_mnttab;
1522 if (mtab == NULL)
1523 return (0);
1524
1525 /*
1526 * Determine the root filesystem's new mountpoint.
1527 */
1528 if (snprintf(zoneroot, sizeof (zoneroot), "%s/root", zonepath) >=
1529 sizeof (zoneroot)) {
1530 zerror(gettext("Zonepath %s is too long.\n"), zonepath);
1531 return (-1);
1532 }
1533
1534 /*
1535 * If the root filesystem is a non-legacy ZFS filesystem (i.e., if it's
1536 * mnt_mountp field is non-NULL), then make the filesystem's new
1537 * mount point its mountpoint property and mount the filesystem.
1538 */
1539 if (mtab->mnt_mountp != NULL) {
1540 zfs_handle_t *zhp;
1541
1542 if ((zhp = zfs_open(g_zfs, mtab->mnt_special,
1543 ZFS_TYPE_DATASET)) == NULL) {
1544 zerror(gettext("could not get ZFS handle for the zone's"
1545 " root filesystem"));
1546 return (-1);
1547 }
1548 if (zfs_prop_set(zhp, zfs_prop_to_name(ZFS_PROP_MOUNTPOINT),
1549 zoneroot) != 0) {
1550 zerror(gettext("could not modify zone's root "
1551 "filesystem's mountpoint property"));
1552 zfs_close(zhp);
1553 return (-1);
1554 }
1555 if (zfs_mount(zhp, mtab->mnt_mntopts, 0) != 0) {
1556 zerror(gettext("unable to mount zone root %s: %s"),
1557 zoneroot, libzfs_error_description(g_zfs));
1558 if (zfs_prop_set(zhp,
1559 zfs_prop_to_name(ZFS_PROP_MOUNTPOINT),
1560 mtab->mnt_mountp) != 0)
1561 zerror(gettext("unable to restore zone's root "
1562 "filesystem's mountpoint property"));
1563 zfs_close(zhp);
1564 return (-1);
1565 }
1566 zfs_close(zhp);
1567 return (0);
1568 }
1569
1570 /*
1571 * The root filesystem is either a legacy-mounted ZFS filesystem or
1572 * a non-ZFS filesystem. Use mount(2) to mount the root filesystem.
1573 */
1574 if (mtab->mnt_mntopts != NULL)
1575 flags = MS_OPTIONSTR;
1576 else
1577 flags = 0;
1578 if (mount(mtab->mnt_special, zoneroot, flags, mtab->mnt_fstype, NULL, 0,
1579 mtab->mnt_mntopts, MAX_MNTOPT_STR * sizeof (char)) != 0) {
1580 flags = errno;
1581 zerror(gettext("unable to mount zone root %s: %s"), zoneroot,
1582 strerror(flags));
1583 return (-1);
1584 }
1585 return (0);
1586 }
1587
1588 /*
1589 * Unmount a moving zone's root filesystem (if such a mount exists) using the
1590 * specified zonepath. mounts should refer to the zone_mounts_t structure
1591 * describing the zone's mount information. If force is B_TRUE, then if the
1592 * unmount fails, then the function will try to forcibly unmount the zone's root
1593 * filesystem.
1594 *
1595 * This function returns zero if the unmount (forced or otherwise) succeeds;
1596 * otherwise, it returns a nonzero value.
1597 */
1598 int
zone_unmount_rootfs(zone_mounts_t * mounts,const char * zonepath,boolean_t force)1599 zone_unmount_rootfs(zone_mounts_t *mounts, const char *zonepath,
1600 boolean_t force)
1601 {
1602 char zoneroot[MAXPATHLEN];
1603 struct mnttab *mtab;
1604 int err;
1605
1606 assert(mounts != NULL);
1607 assert(zonepath != NULL);
1608
1609 /*
1610 * If there isn't a root filesystem, then don't do anything.
1611 */
1612 mtab = mounts->root_mnttab;
1613 if (mtab == NULL)
1614 return (0);
1615
1616 /*
1617 * Determine the root filesystem's mountpoint.
1618 */
1619 if (snprintf(zoneroot, sizeof (zoneroot), "%s/root", zonepath) >=
1620 sizeof (zoneroot)) {
1621 zerror(gettext("Zonepath %s is too long.\n"), zonepath);
1622 return (-1);
1623 }
1624
1625 /*
1626 * If the root filesystem is a non-legacy ZFS fileystem, then unmount
1627 * the filesystem via libzfs.
1628 */
1629 if (mtab->mnt_mountp != NULL) {
1630 zfs_handle_t *zhp;
1631
1632 if ((zhp = zfs_open(g_zfs, mtab->mnt_special,
1633 ZFS_TYPE_DATASET)) == NULL) {
1634 zerror(gettext("could not get ZFS handle for the zone's"
1635 " root filesystem"));
1636 return (-1);
1637 }
1638 if (zfs_unmount(zhp, zoneroot, 0) != 0) {
1639 if (force && zfs_unmount(zhp, zoneroot, MS_FORCE) ==
1640 0) {
1641 zfs_close(zhp);
1642 return (0);
1643 }
1644 zerror(gettext("unable to unmount zone root %s: %s"),
1645 zoneroot, libzfs_error_description(g_zfs));
1646 zfs_close(zhp);
1647 return (-1);
1648 }
1649 zfs_close(zhp);
1650 return (0);
1651 }
1652
1653 /*
1654 * Use umount(2) to unmount the root filesystem. If this fails, then
1655 * forcibly unmount it if the force flag is set.
1656 */
1657 if (umount(zoneroot) != 0) {
1658 if (force && umount2(zoneroot, MS_FORCE) == 0)
1659 return (0);
1660 err = errno;
1661 zerror(gettext("unable to unmount zone root %s: %s"), zoneroot,
1662 strerror(err));
1663 return (-1);
1664 }
1665 return (0);
1666 }
1667
1668 int
init_zfs(void)1669 init_zfs(void)
1670 {
1671 if ((g_zfs = libzfs_init()) == NULL) {
1672 (void) fprintf(stderr, gettext("failed to initialize ZFS "
1673 "library\n"));
1674 return (Z_ERR);
1675 }
1676
1677 return (Z_OK);
1678 }
1679