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