PSARC 2010/059 SNAP BE Management
[illumos-gate.git] / usr / src / lib / libbe / tbeadm / tbeadm.c
blobf0de6a50ef9a92a7e8bfcac1067748ee947b2469
1 /*
2 * CDDL HEADER START
4 * The contents of this file are subject to the terms of the
5 * Common Development and Distribution License (the "License").
6 * You may not use this file except in compliance with the License.
8 * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
9 * or http://www.opensolaris.org/os/licensing.
10 * See the License for the specific language governing permissions
11 * and limitations under the License.
13 * When distributing Covered Code, include this CDDL HEADER in each
14 * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
15 * If applicable, add the following below this CDDL HEADER, with the
16 * fields enclosed by brackets "[]" replaced with your own identifying
17 * information: Portions Copyright [yyyy] [name of copyright owner]
19 * CDDL HEADER END
23 * Copyright (c) 2009, 2010, Oracle and/or its affiliates. All rights reserved.
27 * System includes
30 #include <stdio.h>
31 #include <strings.h>
32 #include <libzfs.h>
34 #include "libbe.h"
36 static int be_do_create(int argc, char **argv);
37 static int be_do_destroy(int argc, char **argv);
38 static int be_do_list(int argc, char **argv);
39 static int be_do_mount(int argc, char **argv);
40 static int be_do_unmount(int argc, char **argv);
41 static int be_do_rename(int argc, char **argv);
42 static int be_do_activate(int argc, char **argv);
43 static int be_do_create_snapshot(int argc, char **argv);
44 static int be_do_destroy_snapshot(int argc, char **argv);
45 static int be_do_rollback(int argc, char **argv);
46 static void usage(void);
48 typedef struct be_command {
49 const char *name;
50 int (*func)(int argc, char **argv);
51 } be_command_t;
53 static be_command_t command_table[] = {
54 { "create", be_do_create },
55 { "destroy", be_do_destroy },
56 { "list", be_do_list },
57 { "mount", be_do_mount },
58 { "unmount", be_do_unmount },
59 { "rename", be_do_rename },
60 { "activate", be_do_activate },
61 { "create_snap", be_do_create_snapshot },
62 { "destroy_snap", be_do_destroy_snapshot },
65 static int fs_num = 2;
66 static int shared_fs_num = 2;
67 static char *fs_names[2] = {"/", "/opt"};
68 static char *shared_fs_names[4] = {"/export", "/export/home"};
70 static void
71 usage(void)
73 (void) printf("usage:\n"
74 "\ttbeadm\n"
75 "\ttbeadm create [-d BE_desc] [-e nonActiveBe | -i] \n"
76 "\t\t[-o property=value] ... [-p zpool] [beName]\n"
77 "\ttbeadm destroy [-fs] beName\n"
78 "\ttbeadm create_snap [-p policy] beName [snapshot]\n"
79 "\ttbeadm destroy_snap beName snapshot\n"
80 "\ttbeadm list [-s] [beName]\n"
81 "\ttbeadm mount [-s ro|rw] beName mountpoint\n"
82 "\ttbeadm unmount [-f] beName\n"
83 "\ttbeadm rename origBeName newBeName\n"
84 "\ttbeadm activate beName\n"
85 "\ttbeadm rollback beName snapshot\n");
88 int
89 main(int argc, char **argv) {
91 if (argc < 2) {
92 usage();
93 return (1);
96 /* Turn error printing on */
97 libbe_print_errors(B_TRUE);
99 if (strcmp(argv[1], "create") == 0) {
100 return (be_do_create(argc - 1, argv + 1));
101 } else if (strcmp(argv[1], "destroy") == 0) {
102 return (be_do_destroy(argc - 1, argv + 1));
103 } else if (strcmp(argv[1], "list") == 0) {
104 return (be_do_list(argc - 1, argv + 1));
105 } else if (strcmp(argv[1], "mount") == 0) {
106 return (be_do_mount(argc - 1, argv + 1));
107 } else if (strcmp(argv[1], "unmount") == 0) {
108 return (be_do_unmount(argc - 1, argv + 1));
109 } else if (strcmp(argv[1], "rename") == 0) {
110 return (be_do_rename(argc - 2, argv + 2));
111 } else if (strcmp(argv[1], "activate") == 0) {
112 return (be_do_activate(argc - 2, argv + 2));
113 } else if (strcmp(argv[1], "create_snap") == 0) {
114 return (be_do_create_snapshot(argc - 1, argv + 1));
115 } else if (strcmp(argv[1], "destroy_snap") == 0) {
116 return (be_do_destroy_snapshot(argc - 2, argv + 2));
117 } else if (strcmp(argv[1], "rollback") == 0) {
118 return (be_do_rollback(argc - 2, argv + 2));
119 } else {
120 usage();
121 return (1);
124 /* NOTREACHED */
127 static int
128 be_do_create(int argc, char **argv)
130 nvlist_t *be_attrs;
131 char *obe_name = NULL;
132 char *snap_name = NULL;
133 char *nbe_zpool = NULL;
134 char *nbe_name = NULL;
135 char *nbe_desc = NULL;
136 nvlist_t *zfs_props = NULL;
137 char *propname = NULL;
138 char *propval = NULL;
139 char *strval = NULL;
140 boolean_t init = B_FALSE;
141 int c;
142 int ret = BE_SUCCESS;
144 if (nvlist_alloc(&zfs_props, NV_UNIQUE_NAME, 0) != 0) {
145 printf("nvlist_alloc failed.\n");
146 return (1);
149 while ((c = getopt(argc, argv, "d:e:io:p:")) != -1) {
150 switch (c) {
151 case 'd':
152 nbe_desc = optarg;
153 break;
154 case 'e':
155 obe_name = optarg;
156 break;
157 case 'i':
158 /* Special option to test be_init() function */
159 init = B_TRUE;
160 break;
161 case 'o':
162 if (zfs_props == NULL) {
163 if (nvlist_alloc(&zfs_props, NV_UNIQUE_NAME,
164 0) != 0) {
165 printf("nvlist_alloc failed.\n");
166 return (1);
170 propname = optarg;
171 if ((propval = strchr(propname, '=')) == NULL) {
172 (void) fprintf(stderr, "missing "
173 "'=' for -o option\n");
174 return (1);
176 *propval = '\0';
177 propval++;
178 if (nvlist_lookup_string(zfs_props, propname,
179 &strval) == 0) {
180 (void) fprintf(stderr, "property '%s' "
181 "specified multiple times\n", propname);
182 return (1);
184 if (nvlist_add_string(zfs_props, propname, propval)
185 != 0) {
186 (void) fprintf(stderr, "internal "
187 "error: out of memory\n");
188 return (1);
190 break;
191 case 'p':
192 nbe_zpool = optarg;
193 break;
194 default:
195 usage();
196 return (1);
200 if (init && obe_name) {
201 printf("ERROR: -e and -i are exclusive options\n");
202 usage();
203 return (1);
206 argc -= optind;
207 argv += optind;
209 if (argc == 1) {
210 nbe_name = argv[0];
211 } else if (argc > 1) {
212 usage();
213 return (1);
216 if (obe_name) {
218 * Check if obe_name is really a snapshot name.
219 * If so, split it out.
221 char *cp = NULL;
223 cp = strrchr(obe_name, '@');
224 if (cp != NULL) {
225 cp[0] = '\0';
226 if (cp[1] != NULL && cp[1] != '\0') {
227 snap_name = cp+1;
232 if (nvlist_alloc(&be_attrs, NV_UNIQUE_NAME, 0) != 0) {
233 printf("nvlist_alloc failed.\n");
234 return (1);
237 if (zfs_props) {
238 if (nvlist_add_nvlist(be_attrs, BE_ATTR_ZFS_PROPERTIES,
239 zfs_props) != 0) {
240 printf("nvlist_add_string failed for "
241 "BE_ATTR_ZFS_PROPERTES (%s).\n", zfs_props);
242 return (1);
246 if (obe_name != NULL) {
247 if (nvlist_add_string(be_attrs, BE_ATTR_ORIG_BE_NAME, obe_name)
248 != 0) {
249 printf("nvlist_add_string failed for "
250 "BE_ATTR_ORIG_BE_NAME (%s).\n", obe_name);
251 return (1);
255 if (snap_name != NULL) {
256 if (nvlist_add_string(be_attrs, BE_ATTR_SNAP_NAME, snap_name)
257 != 0) {
258 printf("nvlist_add_string failed for "
259 "BE_ATTR_SNAP_NANE (%s).\n", snap_name);
260 return (1);
264 if (nbe_zpool != NULL) {
265 if (nvlist_add_string(be_attrs, BE_ATTR_NEW_BE_POOL, nbe_zpool)
266 != 0) {
267 printf("nvlist_add_string failed for "
268 "BE_ATTR_NEW_BE_POOL (%s).\n", nbe_zpool);
269 return (1);
273 if (nbe_name) {
274 if (nvlist_add_string(be_attrs, BE_ATTR_NEW_BE_NAME, nbe_name)
275 != 0) {
276 printf("nvlist_add_string failed for "
277 "BE_ATTR_NEW_BE_NAME (%s).\n", nbe_name);
278 return (1);
282 if (nbe_desc) {
283 if (nvlist_add_string(be_attrs, BE_ATTR_NEW_BE_DESC, nbe_desc)
284 != 0) {
285 printf("nvlist_add_string failed for "
286 "BE_ATTR_NEW_BE_DESC (%s)\n", nbe_desc);
287 return (1);
291 if (init) {
293 * Add the default file system test values to test
294 * creating an initial BE.
296 if (nvlist_add_uint16(be_attrs, BE_ATTR_FS_NUM, fs_num) != 0) {
297 printf("nvlist_add_uint16 failed for BE_ATTR_FS_NUM "
298 "(%d).\n", fs_num);
299 return (1);
302 if (nvlist_add_string_array(be_attrs, BE_ATTR_FS_NAMES,
303 fs_names, fs_num) != 0) {
304 printf("nvlist_add_string_array failed for "
305 "BE_ATTR_FS_NAMES\n");
306 return (1);
309 if (nvlist_add_uint16(be_attrs, BE_ATTR_SHARED_FS_NUM,
310 shared_fs_num) != 0) {
311 printf("nvlist_add_uint16 failed for "
312 "BE_ATTR_SHARED_FS_NUM (%d).\n", shared_fs_num);
313 return (1);
316 if (nvlist_add_string_array(be_attrs, BE_ATTR_SHARED_FS_NAMES,
317 shared_fs_names, shared_fs_num) != 0) {
318 printf("nvlist_add_string_array failed for "
319 "BE_ATTR_SHARED_FS_NAMES\n");
320 return (1);
323 return (be_init(be_attrs));
326 ret = be_copy(be_attrs);
328 if (!nbe_name & ret == BE_SUCCESS) {
330 * We requested an auto named BE; find out the
331 * name of the BE that was created for us and
332 * the auto snapshot created from the original BE.
334 if (nvlist_lookup_string(be_attrs, BE_ATTR_NEW_BE_NAME,
335 &nbe_name) != 0) {
336 printf("failed to get BE_ATTR_NEW_BE_NAME attribute\n");
337 ret = 1;
338 } else {
339 printf("Auto named BE: %s\n", nbe_name);
342 if (nvlist_lookup_string(be_attrs, BE_ATTR_SNAP_NAME,
343 &snap_name) != 0) {
344 printf("failed to get BE_ATTR_SNAP_NAME attribute\n");
345 ret = 1;
346 } else {
347 printf("Auto named snapshot: %s\n", snap_name);
351 return (ret);
354 static int
355 be_do_destroy(int argc, char **argv)
357 nvlist_t *be_attrs;
358 int c;
359 int destroy_flags = 0;
360 char *be_name;
362 while ((c = getopt(argc, argv, "fs")) != -1) {
363 switch (c) {
364 case 'f':
365 destroy_flags |= BE_DESTROY_FLAG_FORCE_UNMOUNT;
366 break;
367 case 's':
368 destroy_flags |= BE_DESTROY_FLAG_SNAPSHOTS;
369 break;
370 default:
371 usage();
372 return (1);
376 argc -= optind;
377 argv += optind;
379 if (argc != 1) {
380 usage();
381 return (1);
384 if (nvlist_alloc(&be_attrs, NV_UNIQUE_NAME, 0) != 0) {
385 printf("nvlist_alloc failed.\n");
386 return (1);
389 if (nvlist_add_string(be_attrs, BE_ATTR_ORIG_BE_NAME, argv[0]) != 0) {
390 printf("nvlist_add_string failed for BE_ATTR_NEW_BE_NAME "
391 "(%s).\n", argv[0]);
392 return (1);
395 if (nvlist_add_uint16(be_attrs, BE_ATTR_DESTROY_FLAGS, destroy_flags)
396 != 0) {
397 printf("nvlist_add_uint16 failed for "
398 "BE_ATTR_DESTROY_FLAGS.\n");
399 return (1);
402 return (be_destroy(be_attrs));
405 static int
406 be_do_list(int argc, char **argv)
408 int err = BE_SUCCESS;
409 be_node_list_t *be_nodes;
410 be_node_list_t *cur_be;
411 boolean_t snaps = B_FALSE;
412 int c = 0;
414 while ((c = getopt(argc, argv, "s")) != -1) {
415 switch (c) {
416 case 's':
417 snaps = B_TRUE;
418 break;
419 default:
420 usage();
421 return (1);
425 argc -= optind;
426 argv += optind;
429 if (argc == 1) {
430 err = be_list(argv[0], &be_nodes);
431 } else {
432 err = be_list(NULL, &be_nodes);
435 if (err == BE_SUCCESS) {
437 printf(
438 "BE name\t\tActive\tActive \tDataset\t\t\tPolicy\tUUID\n");
439 printf(
440 " \t\t \ton boot\t \t\t\t \t \n");
441 printf(
442 "-------\t\t------\t-------\t-------\t\t\t------\t----\n");
444 for (cur_be = be_nodes; cur_be != NULL;
445 cur_be = cur_be->be_next_node) {
447 int name_len = strlen(cur_be->be_node_name);
448 int ds_len = strlen(cur_be->be_root_ds);
450 printf("%s%s%s\t%s\t%s%s%s\t%s\n",
451 cur_be->be_node_name,
452 name_len < 8 ? "\t\t" : "\t",
453 cur_be->be_active ? "yes" : "no",
454 cur_be->be_active_on_boot ? "yes" : "no",
455 cur_be->be_root_ds,
456 ds_len < 8 ? "\t\t\t" :
457 (ds_len < 16 ? "\t\t" : "\t"),
458 cur_be->be_policy_type,
459 cur_be->be_uuid_str ? cur_be->be_uuid_str : "-");
460 if (snaps) {
461 be_snapshot_list_t *snapshots = NULL;
462 printf("Snapshot Name\n");
463 printf("--------------\n");
464 for (snapshots = cur_be->be_node_snapshots;
465 snapshots != NULL; snapshots =
466 snapshots->be_next_snapshot) {
467 printf("%s\n",
468 snapshots->be_snapshot_name);
474 be_free_list(be_nodes);
475 return (err);
478 static int
479 be_do_rename(int argc, char **argv)
481 nvlist_t *be_attrs;
482 char *obe_name;
483 char *nbe_name;
485 if (argc < 1 || argc > 2) {
486 usage();
487 return (1);
490 obe_name = argv[0];
491 nbe_name = argv[1];
493 if (nvlist_alloc(&be_attrs, NV_UNIQUE_NAME, 0) != 0) {
494 printf("nvlist_alloc failed.\n");
495 return (1);
498 if (nvlist_add_string(be_attrs, BE_ATTR_ORIG_BE_NAME, obe_name)
499 != 0) {
500 printf("nvlist_add_string failed for "
501 "BE_ATTR_ORIG_BE_NAME (%s).\n", obe_name);
502 return (1);
505 if (nvlist_add_string(be_attrs, BE_ATTR_NEW_BE_NAME, nbe_name)
506 != 0) {
507 printf("nvlist_add_string failed for "
508 "BE_ATTR_NEW_BE_NAME (%s).\n", nbe_name);
509 return (1);
512 return (be_rename(be_attrs));
516 static int
517 be_do_create_snapshot(int argc, char **argv)
519 nvlist_t *be_attrs;
520 char *obe_name = NULL;
521 char *snap_name = NULL;
522 char *policy = NULL;
523 int c;
524 int ret = BE_SUCCESS;
526 while ((c = getopt(argc, argv, "p:")) != -1) {
527 switch (c) {
528 case 'p':
529 policy = optarg;
530 break;
531 default:
532 usage();
533 return (1);
537 argc -= optind;
538 argv += optind;
540 if (argc < 1 || argc > 2) {
541 usage();
542 return (1);
545 obe_name = argv[0];
547 if (argc > 1) {
548 /* Snapshot name provided */
549 snap_name = argv[1];
552 if (nvlist_alloc(&be_attrs, NV_UNIQUE_NAME, 0) != 0) {
553 printf("nvlist_alloc failed.\n");
554 return (1);
557 if (nvlist_add_string(be_attrs, BE_ATTR_ORIG_BE_NAME, obe_name)
558 != 0) {
559 printf("nvlist_add_string failed for "
560 "BE_ATTR_ORIG_BE_NAME (%s).\n", obe_name);
561 return (1);
564 if (policy) {
565 if (nvlist_add_string(be_attrs, BE_ATTR_POLICY, policy) != 0) {
566 printf("nvlist_add_string failed for "
567 "BE_ATTR_POLICY (%s).\n", policy);
568 return (1);
572 if (snap_name) {
573 if (nvlist_add_string(be_attrs, BE_ATTR_SNAP_NAME, snap_name)
574 != 0) {
575 printf("nvlist_add_string failed for "
576 "BE_ATTR_SNAP_NAME (%s).\n", snap_name);
577 return (1);
581 ret = be_create_snapshot(be_attrs);
583 if (!snap_name && ret == BE_SUCCESS) {
585 * We requested an auto named snapshot; find out
586 * the snapshot name that was created for us.
588 if (nvlist_lookup_string(be_attrs, BE_ATTR_SNAP_NAME,
589 &snap_name) != 0) {
590 printf("failed to get BE_ATTR_SNAP_NAME attribute\n");
591 ret = 1;
592 } else {
593 printf("Auto named snapshot: %s\n", snap_name);
597 return (ret);
600 static int
601 be_do_destroy_snapshot(int argc, char **argv)
603 nvlist_t *be_attrs;
604 char *obe_name;
605 char *snap_name;
607 if (argc != 2) {
608 usage();
609 return (1);
612 obe_name = argv[0];
613 snap_name = argv[1];
615 if (nvlist_alloc(&be_attrs, NV_UNIQUE_NAME, 0) != 0) {
616 printf("nvlist_alloc failed.\n");
617 return (1);
620 if (nvlist_add_string(be_attrs, BE_ATTR_ORIG_BE_NAME, obe_name)
621 != 0) {
622 printf("nvlist_add_string failed for "
623 "BE_ATTR_ORIG_BE_NAME (%s).\n", obe_name);
624 return (1);
627 if (nvlist_add_string(be_attrs, BE_ATTR_SNAP_NAME, snap_name)
628 != 0) {
629 printf("nvlist_add_string failed for "
630 "BE_ATTR_SNAP_NAME (%s).\n", snap_name);
631 return (1);
634 return (be_destroy_snapshot(be_attrs));
637 static int
638 be_do_rollback(int argc, char **argv)
640 nvlist_t *be_attrs;
641 char *obe_name;
642 char *snap_name;
644 if (argc < 1 || argc > 2) {
645 usage();
646 return (1);
649 obe_name = argv[0];
650 snap_name = argv[1];
652 if (nvlist_alloc(&be_attrs, NV_UNIQUE_NAME, 0) != 0) {
653 printf("nvlist_alloc failed.\n");
654 return (1);
657 if (nvlist_add_string(be_attrs, BE_ATTR_ORIG_BE_NAME, obe_name)
658 != 0) {
659 printf("nvlist_add_string failed for "
660 "BE_ATTR_ORIG_BE_NAME (%s).\n", obe_name);
661 return (1);
664 if (nvlist_add_string(be_attrs, BE_ATTR_SNAP_NAME, snap_name)
665 != 0) {
666 printf("nvlist_add_string failed for "
667 "BE_ATTR_SNAP_NAME (%s).\n", snap_name);
668 return (1);
671 return (be_rollback(be_attrs));
674 static int
675 be_do_activate(int argc, char **argv)
677 nvlist_t *be_attrs;
678 char *obe_name;
680 if (argc < 1 || argc > 2) {
681 usage();
682 return (1);
685 obe_name = argv[0];
687 if (nvlist_alloc(&be_attrs, NV_UNIQUE_NAME, 0) != 0) {
688 printf("nvlist_alloc failed.\n");
689 return (1);
692 if (nvlist_add_string(be_attrs, BE_ATTR_ORIG_BE_NAME, obe_name)
693 != 0) {
694 printf("nvlist_add_string failed for "
695 "BE_ATTR_ORIG_BE_NAME (%s).\n", obe_name);
696 return (1);
699 return (be_activate(be_attrs));
702 static int
703 be_do_mount(int argc, char **argv)
705 nvlist_t *be_attrs;
706 int c;
707 boolean_t shared_fs = B_FALSE;
708 int mount_flags = 0;
709 char *obe_name;
710 char *mountpoint;
712 while ((c = getopt(argc, argv, "s:")) != -1) {
713 switch (c) {
714 case 's':
715 shared_fs = B_TRUE;
717 mount_flags |= BE_MOUNT_FLAG_SHARED_FS;
719 if (strcmp(optarg, "rw") == 0) {
720 mount_flags |= BE_MOUNT_FLAG_SHARED_RW;
721 } else if (strcmp(optarg, "ro") != 0) {
722 printf("The -s flag requires an argument "
723 "[ rw | ro ]\n");
724 usage();
725 return (1);
728 break;
729 default:
730 usage();
731 return (1);
735 argc -= optind;
736 argv += optind;
738 if (argc < 1 || argc > 2) {
739 usage();
740 return (1);
743 obe_name = argv[0];
745 if (argc == 2) {
746 mountpoint = argv[1];
747 } else {
749 * XXX - Need to generate a random mountpoint here;
750 * right now we're just exitting if one isn't supplied.
752 usage();
753 return (1);
756 if (nvlist_alloc(&be_attrs, NV_UNIQUE_NAME, 0) != 0) {
757 printf("nvlist_alloc failed.\n");
758 return (1);
761 if (nvlist_add_string(be_attrs, BE_ATTR_ORIG_BE_NAME, obe_name)
762 != 0) {
763 printf("nvlist_add_string failed for "
764 "BE_ATTR_ORIG_BE_NAME (%s).\n", obe_name);
765 return (1);
768 if (nvlist_add_string(be_attrs, BE_ATTR_MOUNTPOINT, mountpoint)
769 != 0) {
770 printf("nvlist_add_string failed for "
771 "BE_ATTR_MOUNTPOINT (%s).\n", mountpoint);
772 return (1);
775 if (shared_fs) {
776 if (nvlist_add_uint16(be_attrs, BE_ATTR_MOUNT_FLAGS,
777 mount_flags) != 0) {
778 printf("nvlist_add_uint16 failed for "
779 "BE_ATTR_MOUNT_FLAGS (%d).\n", mount_flags);
780 return (1);
784 return (be_mount(be_attrs));
788 static int
789 be_do_unmount(int argc, char **argv)
791 nvlist_t *be_attrs;
792 int c;
793 int unmount_flags = 0;
794 char *obe_name;
796 while ((c = getopt(argc, argv, "f")) != -1) {
797 switch (c) {
798 case 'f':
799 unmount_flags |= BE_UNMOUNT_FLAG_FORCE;
800 break;
801 default:
802 usage();
803 return (1);
807 argc -= optind;
808 argv += optind;
810 if (argc != 1) {
811 usage();
812 return (1);
815 obe_name = argv[0];
817 if (nvlist_alloc(&be_attrs, NV_UNIQUE_NAME, 0) != 0) {
818 printf("nvlist_alloc failed.\n");
819 return (1);
822 if (nvlist_add_string(be_attrs, BE_ATTR_ORIG_BE_NAME, obe_name)
823 != 0) {
824 printf("nvlist_add_string failed for "
825 "BE_ATTR_ORIG_BE_NAME (%s).\n", obe_name);
826 return (1);
829 if (nvlist_add_uint16(be_attrs, BE_ATTR_UNMOUNT_FLAGS, unmount_flags)
830 != 0) {
831 printf("nvlist_add_uint16 failed for "
832 "BE_ATTR_UNMOUNT_FLAGS\n");
833 return (1);
836 return (be_unmount(be_attrs));