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) 2009, 2010, Oracle and/or its affiliates. All rights reserved.
24 * Copyright 2013 Nexenta Systems, Inc. All rights reserved.
25 * Copyright 2015 Toomas Soome <tsoome@me.com>
26 * Copyright 2015 Gary Mills
27 * Copyright (c) 2015 by Delphix. All rights reserved.
28 * Copyright 2017 Jason King
29 * Copyright 2018 OmniOS Community Edition (OmniOSce) Association.
30 */
31
32 /*
33 * System includes
34 */
35
36 #include <assert.h>
37 #include <stdio.h>
38 #include <strings.h>
39 #include <libzfs.h>
40 #include <locale.h>
41 #include <langinfo.h>
42 #include <stdlib.h>
43 #include <wchar.h>
44 #include <sys/types.h>
45 #include <sys/debug.h>
46 #include <libcmdutils.h>
47
48 #include "libbe.h"
49
50 #ifndef lint
51 #define _(x) gettext(x)
52 #else
53 #define _(x) (x)
54 #endif
55
56 #ifndef TEXT_DOMAIN
57 #define TEXT_DOMAIN "SYS_TEST"
58 #endif
59
60 #define DT_BUF_LEN (128)
61 #define NUM_COLS (6)
62 CTASSERT(DT_BUF_LEN >= NN_NUMBUF_SZ);
63
64 static int be_do_activate(int argc, char **argv);
65 static int be_do_create(int argc, char **argv);
66 static int be_do_destroy(int argc, char **argv);
67 static int be_do_list(int argc, char **argv);
68 static int be_do_mount(int argc, char **argv);
69 static int be_do_unmount(int argc, char **argv);
70 static int be_do_rename(int argc, char **argv);
71 static int be_do_rollback(int argc, char **argv);
72 static void usage(void);
73
74 /*
75 * single column name/width output format description
76 */
77 struct col_info {
78 const char *col_name;
79 size_t width;
80 };
81
82 /*
83 * all columns output format
84 */
85 struct hdr_info {
86 struct col_info cols[NUM_COLS];
87 };
88
89 /*
90 * type of possible output formats
91 */
92 enum be_fmt {
93 BE_FMT_DEFAULT,
94 BE_FMT_DATASET,
95 BE_FMT_SNAPSHOT,
96 BE_FMT_ALL
97 };
98
99 /*
100 * command handler description
101 */
102 typedef struct be_command {
103 const char *name;
104 int (*func)(int argc, char **argv);
105 } be_command_t;
106
107 /*
108 * sorted list of be commands
109 */
110 static const be_command_t be_command_tbl[] = {
111 { "activate", be_do_activate },
112 { "create", be_do_create },
113 { "destroy", be_do_destroy },
114 { "list", be_do_list },
115 { "mount", be_do_mount },
116 { "unmount", be_do_unmount },
117 { "umount", be_do_unmount }, /* unmount alias */
118 { "rename", be_do_rename },
119 { "rollback", be_do_rollback },
120 { NULL, NULL },
121 };
122
123 static void
usage(void)124 usage(void)
125 {
126 (void) fprintf(stderr, _("usage:\n"
127 "\tbeadm subcommand cmd_options\n"
128 "\n"
129 "\tsubcommands:\n"
130 "\n"
131 "\tbeadm activate [-v] beName\n"
132 "\tbeadm create [-a] [-d BE_desc]\n"
133 "\t\t[-o property=value] ... [-p zpool] \n"
134 "\t\t[-e nonActiveBe | beName@snapshot] [-v] beName\n"
135 "\tbeadm create [-d BE_desc]\n"
136 "\t\t[-o property=value] ... [-p zpool] [-v] beName@snapshot\n"
137 "\tbeadm destroy [-Ffsv] beName \n"
138 "\tbeadm destroy [-Fv] beName@snapshot \n"
139 "\tbeadm list [[-a] | [-d] [-s]] [-H]\n"
140 "\t\t[-k|-K date | name | space] [-v] [beName]\n"
141 "\tbeadm mount [-s ro|rw] [-v] beName [mountpoint]\n"
142 "\tbeadm unmount [-fv] beName | mountpoint\n"
143 "\tbeadm umount [-fv] beName | mountpoint\n"
144 "\tbeadm rename [-v] origBeName newBeName\n"
145 "\tbeadm rollback [-v] beName snapshot\n"
146 "\tbeadm rollback [-v] beName@snapshot\n"));
147 }
148
149 static int
run_be_cmd(const char * cmdname,int argc,char ** argv)150 run_be_cmd(const char *cmdname, int argc, char **argv)
151 {
152 const be_command_t *command;
153
154 for (command = &be_command_tbl[0]; command->name != NULL; command++)
155 if (strcmp(command->name, cmdname) == 0)
156 return (command->func(argc, argv));
157
158 (void) fprintf(stderr, _("Invalid command: %s\n"), cmdname);
159 usage();
160 return (1);
161 }
162
163 int
main(int argc,char ** argv)164 main(int argc, char **argv)
165 {
166 const char *cmdname;
167
168 (void) setlocale(LC_ALL, "");
169 (void) textdomain(TEXT_DOMAIN);
170
171 if (argc < 2) {
172 usage();
173 return (1);
174 }
175
176 cmdname = argv[1];
177
178 /* Turn error printing off */
179 libbe_print_errors(B_FALSE);
180
181 return (run_be_cmd(cmdname, --argc, ++argv));
182 }
183
184 static void
print_hdr(struct hdr_info * hdr_info)185 print_hdr(struct hdr_info *hdr_info)
186 {
187 boolean_t first = B_TRUE;
188 size_t i;
189 for (i = 0; i < NUM_COLS; i++) {
190 struct col_info *col_info = &hdr_info->cols[i];
191 const char *name = col_info->col_name;
192 size_t width = col_info->width;
193 if (name == NULL)
194 continue;
195
196 if (first) {
197 (void) printf("%-*s", width, name);
198 first = B_FALSE;
199 } else
200 (void) printf(" %-*s", width, name);
201 }
202 (void) putchar('\n');
203 }
204
205 static void
init_hdr_cols(enum be_fmt be_fmt,struct hdr_info * hdr)206 init_hdr_cols(enum be_fmt be_fmt, struct hdr_info *hdr)
207 {
208 struct col_info *col = hdr->cols;
209 size_t i;
210
211 col[1].col_name = _("Active");
212 col[2].col_name = _("Mountpoint");
213 col[3].col_name = _("Space");
214 col[4].col_name = _("Policy");
215 col[5].col_name = _("Created");
216 col[6].col_name = NULL;
217
218 switch (be_fmt) {
219 case BE_FMT_ALL:
220 col[0].col_name = _("BE/Dataset/Snapshot");
221 break;
222 case BE_FMT_DATASET:
223 col[0].col_name = _("BE/Dataset");
224 break;
225 case BE_FMT_SNAPSHOT:
226 col[0].col_name = _("BE/Snapshot");
227 col[1].col_name = NULL;
228 col[2].col_name = NULL;
229 break;
230 case BE_FMT_DEFAULT:
231 default:
232 col[0].col_name = _("BE");
233 }
234
235 for (i = 0; i < NUM_COLS; i++) {
236 const char *name = col[i].col_name;
237 col[i].width = 0;
238
239 if (name != NULL) {
240 wchar_t wname[128];
241 size_t sz = mbstowcs(wname, name, sizeof (wname) /
242 sizeof (wchar_t));
243 if (sz > 0) {
244 int wcsw = wcswidth(wname, sz);
245 if (wcsw > 0)
246 col[i].width = wcsw;
247 else
248 col[i].width = sz;
249 } else {
250 col[i].width = strlen(name);
251 }
252 }
253 }
254 }
255
256 static void
count_widths(enum be_fmt be_fmt,struct hdr_info * hdr,be_node_list_t * be_nodes)257 count_widths(enum be_fmt be_fmt, struct hdr_info *hdr, be_node_list_t *be_nodes)
258 {
259 size_t len[NUM_COLS];
260 char buf[DT_BUF_LEN];
261 int i;
262 be_node_list_t *cur_be;
263
264 for (i = 0; i < NUM_COLS; i++)
265 len[i] = hdr->cols[i].width;
266
267 for (cur_be = be_nodes; cur_be != NULL; cur_be = cur_be->be_next_node) {
268 char name[ZFS_MAX_DATASET_NAME_LEN + 1];
269 const char *be_name = cur_be->be_node_name;
270 const char *root_ds = cur_be->be_root_ds;
271 char *pos;
272 size_t node_name_len = strlen(cur_be->be_node_name);
273 size_t root_ds_len = strlen(cur_be->be_root_ds);
274 size_t mntpt_len = 0;
275 size_t policy_len = 0;
276 size_t used_len;
277 uint64_t used = cur_be->be_space_used;
278 be_snapshot_list_t *snap = NULL;
279
280 if (cur_be->be_mntpt != NULL)
281 mntpt_len = strlen(cur_be->be_mntpt);
282 if (cur_be->be_policy_type != NULL)
283 policy_len = strlen(cur_be->be_policy_type);
284
285 (void) strlcpy(name, root_ds, sizeof (name));
286 pos = strstr(name, be_name);
287
288 if (be_fmt == BE_FMT_DEFAULT) {
289 if (node_name_len > len[0])
290 len[0] = node_name_len;
291 } else {
292 if (root_ds_len + 3 > len[0])
293 len[0] = root_ds_len + 3;
294 }
295
296 if (mntpt_len > len[2])
297 len[2] = mntpt_len;
298 if (policy_len > len[4])
299 len[4] = policy_len;
300
301 for (snap = cur_be->be_node_snapshots; snap != NULL;
302 snap = snap->be_next_snapshot) {
303 uint64_t snap_used = snap->be_snapshot_space_used;
304 const char *snap_name = snap->be_snapshot_name;
305 (void) strcpy(pos, snap_name);
306
307 if (be_fmt == BE_FMT_DEFAULT)
308 used += snap_used;
309 else if (be_fmt & BE_FMT_SNAPSHOT) {
310 int snap_len = strlen(name) + 3;
311 if (be_fmt == BE_FMT_SNAPSHOT)
312 snap_len -= pos - name;
313 if (snap_len > len[0])
314 len[0] = snap_len;
315 nicenum(snap_used, buf, sizeof (buf));
316 used_len = strlen(buf);
317 if (used_len > len[3])
318 len[3] = used_len;
319 }
320 }
321
322 if (be_fmt == BE_FMT_DEFAULT) {
323 int used_len;
324 nicenum(used, buf, sizeof (buf));
325 used_len = strlen(buf);
326 if (used_len > len[3])
327 len[3] = used_len;
328 }
329
330 nicenum(used, buf, sizeof (buf));
331 }
332
333 for (i = 0; i < NUM_COLS; i++)
334 hdr->cols[i].width = len[i];
335 }
336
337 static void
print_be_nodes(const char * be_name,boolean_t parsable,struct hdr_info * hdr,be_node_list_t * nodes)338 print_be_nodes(const char *be_name, boolean_t parsable, struct hdr_info *hdr,
339 be_node_list_t *nodes)
340 {
341 char buf[64];
342 char datetime[DT_BUF_LEN];
343 be_node_list_t *cur_be;
344
345 for (cur_be = nodes; cur_be != NULL; cur_be = cur_be->be_next_node) {
346 char active[3] = "-\0";
347 int ai = 0;
348 const char *datetime_fmt = "%F %R";
349 const char *name = cur_be->be_node_name;
350 const char *mntpt = cur_be->be_mntpt;
351 be_snapshot_list_t *snap = NULL;
352 uint64_t used = cur_be->be_space_used;
353 time_t creation = cur_be->be_node_creation;
354 struct tm *tm;
355
356 if (be_name != NULL && strcmp(be_name, name) != 0)
357 continue;
358
359 if (parsable)
360 active[0] = '\0';
361
362 tm = localtime(&creation);
363 (void) strftime(datetime, DT_BUF_LEN, datetime_fmt, tm);
364
365 for (snap = cur_be->be_node_snapshots; snap != NULL;
366 snap = snap->be_next_snapshot)
367 used += snap->be_snapshot_space_used;
368
369 if (!cur_be->be_global_active)
370 active[ai++] = 'x';
371
372 if (cur_be->be_active)
373 active[ai++] = 'N';
374 if (cur_be->be_active_on_boot) {
375 if (!cur_be->be_global_active)
376 active[ai] = 'b';
377 else
378 active[ai] = 'R';
379 }
380
381 nicenum(used, buf, sizeof (buf));
382 if (parsable)
383 (void) printf("%s;%s;%s;%s;%llu;%s;%ld\n",
384 name,
385 cur_be->be_uuid_str,
386 active,
387 (cur_be->be_mounted ? mntpt: ""),
388 used,
389 cur_be->be_policy_type,
390 creation);
391 else
392 (void) printf("%-*s %-*s %-*s %-*s %-*s %-*s\n",
393 hdr->cols[0].width, name,
394 hdr->cols[1].width, active,
395 hdr->cols[2].width, (cur_be->be_mounted ? mntpt:
396 "-"),
397 hdr->cols[3].width, buf,
398 hdr->cols[4].width, cur_be->be_policy_type,
399 hdr->cols[5].width, datetime);
400 }
401 }
402
403 static void
print_be_snapshots(be_node_list_t * be,struct hdr_info * hdr,boolean_t parsable)404 print_be_snapshots(be_node_list_t *be, struct hdr_info *hdr, boolean_t parsable)
405 {
406 char buf[64];
407 char datetime[DT_BUF_LEN];
408 be_snapshot_list_t *snap = NULL;
409
410 for (snap = be->be_node_snapshots; snap != NULL;
411 snap = snap->be_next_snapshot) {
412 char name[ZFS_MAX_DATASET_NAME_LEN + 1];
413 const char *datetime_fmt = "%F %R";
414 const char *be_name = be->be_node_name;
415 const char *root_ds = be->be_root_ds;
416 const char *snap_name = snap->be_snapshot_name;
417 char *pos;
418 uint64_t used = snap->be_snapshot_space_used;
419 time_t creation = snap->be_snapshot_creation;
420 struct tm *tm = localtime(&creation);
421
422 (void) strncpy(name, root_ds, sizeof (name));
423 pos = strstr(name, be_name);
424 (void) strcpy(pos, snap_name);
425
426 (void) strftime(datetime, DT_BUF_LEN, datetime_fmt, tm);
427 nicenum(used, buf, sizeof (buf));
428
429 if (parsable)
430 if (hdr->cols[1].width != 0)
431 (void) printf("%s;%s;%s;%s;%llu;%s;%ld\n",
432 be_name,
433 snap_name,
434 "",
435 "",
436 used,
437 be->be_policy_type,
438 creation);
439 else
440 (void) printf("%s;%s;%llu;%s;%ld\n",
441 be_name,
442 snap_name,
443 used,
444 be->be_policy_type,
445 creation);
446 else
447 if (hdr->cols[1].width != 0)
448 (void) printf(" %-*s %-*s %-*s %-*s %-*s "
449 "%-*s\n",
450 hdr->cols[0].width-3, name,
451 hdr->cols[1].width, "-",
452 hdr->cols[2].width, "-",
453 hdr->cols[3].width, buf,
454 hdr->cols[4].width, be->be_policy_type,
455 hdr->cols[5].width, datetime);
456 else
457 (void) printf(" %-*s %-*s %-*s %-*s\n",
458 hdr->cols[0].width-3, snap_name,
459 hdr->cols[3].width, buf,
460 hdr->cols[4].width, be->be_policy_type,
461 hdr->cols[5].width, datetime);
462 }
463 }
464
465 static void
print_fmt_nodes(const char * be_name,enum be_fmt be_fmt,boolean_t parsable,struct hdr_info * hdr,be_node_list_t * nodes)466 print_fmt_nodes(const char *be_name, enum be_fmt be_fmt, boolean_t parsable,
467 struct hdr_info *hdr, be_node_list_t *nodes)
468 {
469 char buf[64];
470 char datetime[DT_BUF_LEN];
471 be_node_list_t *cur_be;
472
473 for (cur_be = nodes; cur_be != NULL; cur_be = cur_be->be_next_node) {
474 char active[3] = "-\0";
475 int ai = 0;
476 const char *datetime_fmt = "%F %R";
477 const char *name = cur_be->be_node_name;
478 const char *mntpt = cur_be->be_mntpt;
479 uint64_t used = cur_be->be_space_used;
480 time_t creation = cur_be->be_node_creation;
481 struct tm *tm;
482
483 if (be_name != NULL && strcmp(be_name, name) != 0)
484 continue;
485
486 if (!parsable)
487 (void) printf("%-s\n", name);
488 else
489 active[0] = '\0';
490
491 tm = localtime(&creation);
492 (void) strftime(datetime, DT_BUF_LEN, datetime_fmt, tm);
493
494 if (cur_be->be_active)
495 active[ai++] = 'N';
496 if (cur_be->be_active_on_boot)
497 active[ai] = 'R';
498
499 nicenum(used, buf, sizeof (buf));
500 if (be_fmt & BE_FMT_DATASET)
501 if (parsable)
502 (void) printf("%s;%s;%s;%s;%llu;%s;%ld\n",
503 cur_be->be_node_name,
504 cur_be->be_root_ds,
505 active,
506 (cur_be->be_mounted ? mntpt: ""),
507 used,
508 cur_be->be_policy_type,
509 creation);
510 else
511 (void) printf(" %-*s %-*s %-*s %-*s %-*s "
512 "%-*s\n",
513 hdr->cols[0].width-3, cur_be->be_root_ds,
514 hdr->cols[1].width, active,
515 hdr->cols[2].width, (cur_be->be_mounted ?
516 mntpt: "-"),
517 hdr->cols[3].width, buf,
518 hdr->cols[4].width, cur_be->be_policy_type,
519 hdr->cols[5].width, datetime);
520
521 if (be_fmt & BE_FMT_SNAPSHOT)
522 print_be_snapshots(cur_be, hdr, parsable);
523 }
524 }
525
526 static void
print_nodes(const char * be_name,boolean_t dsets,boolean_t snaps,boolean_t parsable,be_node_list_t * be_nodes)527 print_nodes(const char *be_name, boolean_t dsets, boolean_t snaps,
528 boolean_t parsable, be_node_list_t *be_nodes)
529 {
530 struct hdr_info hdr;
531 enum be_fmt be_fmt = BE_FMT_DEFAULT;
532
533 if (dsets)
534 be_fmt |= BE_FMT_DATASET;
535 if (snaps)
536 be_fmt |= BE_FMT_SNAPSHOT;
537
538 if (!parsable) {
539 init_hdr_cols(be_fmt, &hdr);
540 count_widths(be_fmt, &hdr, be_nodes);
541 print_hdr(&hdr);
542 }
543
544 if (be_fmt == BE_FMT_DEFAULT)
545 print_be_nodes(be_name, parsable, &hdr, be_nodes);
546 else
547 print_fmt_nodes(be_name, be_fmt, parsable, &hdr, be_nodes);
548 }
549
550 static boolean_t
confirm_destroy(const char * name)551 confirm_destroy(const char *name)
552 {
553 boolean_t res = B_FALSE;
554 const char *yesre = nl_langinfo(YESEXPR);
555 const char *nore = nl_langinfo(NOEXPR);
556 regex_t yes_re;
557 regex_t no_re;
558 char buf[128];
559 char *answer;
560 int cflags = REG_EXTENDED;
561
562 if (regcomp(&yes_re, yesre, cflags) != 0) {
563 /* should not happen */
564 (void) fprintf(stderr, _("Failed to compile 'yes' regexp\n"));
565 return (res);
566 }
567 if (regcomp(&no_re, nore, cflags) != 0) {
568 /* should not happen */
569 (void) fprintf(stderr, _("Failed to compile 'no' regexp\n"));
570 regfree(&yes_re);
571 return (res);
572 }
573
574 (void) printf(_("Are you sure you want to destroy %s?\n"
575 "This action cannot be undone (y/[n]): "), name);
576
577 answer = fgets(buf, sizeof (buf), stdin);
578 if (answer == NULL || *answer == '\0' || *answer == 10)
579 goto out;
580
581 if (regexec(&yes_re, answer, 0, NULL, 0) == 0) {
582 res = B_TRUE;
583 } else if (regexec(&no_re, answer, 0, NULL, 0) != 0) {
584 (void) fprintf(stderr, _("Invalid response. "
585 "Please enter 'y' or 'n'.\n"));
586 }
587
588 out:
589 regfree(&yes_re);
590 regfree(&no_re);
591 return (res);
592 }
593
594 static int
be_nvl_alloc(nvlist_t ** nvlp)595 be_nvl_alloc(nvlist_t **nvlp)
596 {
597 assert(nvlp != NULL);
598
599 if (nvlist_alloc(nvlp, NV_UNIQUE_NAME, 0) != 0) {
600 (void) perror(_("nvlist_alloc failed.\n"));
601 return (1);
602 }
603
604 return (0);
605 }
606
607 static int
be_nvl_add_string(nvlist_t * nvl,const char * name,const char * val)608 be_nvl_add_string(nvlist_t *nvl, const char *name, const char *val)
609 {
610 assert(nvl != NULL);
611
612 if (nvlist_add_string(nvl, name, val) != 0) {
613 (void) fprintf(stderr, _("nvlist_add_string failed for "
614 "%s (%s).\n"), name, val);
615 return (1);
616 }
617
618 return (0);
619 }
620
621 static int
be_nvl_add_nvlist(nvlist_t * nvl,const char * name,nvlist_t * val)622 be_nvl_add_nvlist(nvlist_t *nvl, const char *name, nvlist_t *val)
623 {
624 assert(nvl != NULL);
625
626 if (nvlist_add_nvlist(nvl, name, val) != 0) {
627 (void) fprintf(stderr, _("nvlist_add_nvlist failed for %s.\n"),
628 name);
629 return (1);
630 }
631
632 return (0);
633 }
634
635 static int
be_nvl_add_uint16(nvlist_t * nvl,const char * name,uint16_t val)636 be_nvl_add_uint16(nvlist_t *nvl, const char *name, uint16_t val)
637 {
638 assert(nvl != NULL);
639
640 if (nvlist_add_uint16(nvl, name, val) != 0) {
641 (void) fprintf(stderr, _("nvlist_add_uint16 failed for "
642 "%s (%hu).\n"), name, val);
643 return (1);
644 }
645
646 return (0);
647 }
648
649 static int
be_do_activate(int argc,char ** argv)650 be_do_activate(int argc, char **argv)
651 {
652 nvlist_t *be_attrs;
653 int err = 1;
654 int c;
655 char *obe_name;
656
657 while ((c = getopt(argc, argv, "v")) != -1) {
658 switch (c) {
659 case 'v':
660 libbe_print_errors(B_TRUE);
661 break;
662 default:
663 usage();
664 return (1);
665 }
666 }
667
668 argc -= optind;
669 argv += optind;
670
671 if (argc != 1) {
672 usage();
673 return (1);
674 }
675
676 obe_name = argv[0];
677
678 if (be_nvl_alloc(&be_attrs) != 0)
679 return (1);
680
681 if (be_nvl_add_string(be_attrs, BE_ATTR_ORIG_BE_NAME, obe_name) != 0)
682 goto out;
683
684 err = be_activate(be_attrs);
685
686 switch (err) {
687 case BE_SUCCESS:
688 (void) printf(_("Activated successfully\n"));
689 break;
690 case BE_ERR_BE_NOENT:
691 (void) fprintf(stderr, _("%s does not exist or appear "
692 "to be a valid BE.\nPlease check that the name of "
693 "the BE provided is correct.\n"), obe_name);
694 break;
695 case BE_ERR_PERM:
696 case BE_ERR_ACCESS:
697 (void) fprintf(stderr, _("Unable to activate %s.\n"), obe_name);
698 (void) fprintf(stderr, _("You have insufficient privileges to "
699 "execute this command.\n"));
700 break;
701 case BE_ERR_ACTIVATE_CURR:
702 default:
703 (void) fprintf(stderr, _("Unable to activate %s.\n"), obe_name);
704 (void) fprintf(stderr, "%s\n", be_err_to_str(err));
705 }
706
707 out:
708 nvlist_free(be_attrs);
709 return (err);
710 }
711
712 static int
be_do_create(int argc,char ** argv)713 be_do_create(int argc, char **argv)
714 {
715 nvlist_t *be_attrs;
716 nvlist_t *zfs_props = NULL;
717 boolean_t activate = B_FALSE;
718 boolean_t is_snap = B_FALSE;
719 int c;
720 int err = 1;
721 char *obe_name = NULL;
722 char *snap_name = NULL;
723 char *nbe_zpool = NULL;
724 char *nbe_name = NULL;
725 char *nbe_desc = NULL;
726 char *propname = NULL;
727 char *propval = NULL;
728 char *strval = NULL;
729
730 while ((c = getopt(argc, argv, "ad:e:io:p:v")) != -1) {
731 switch (c) {
732 case 'a':
733 activate = B_TRUE;
734 break;
735 case 'd':
736 nbe_desc = optarg;
737 break;
738 case 'e':
739 obe_name = optarg;
740 break;
741 case 'o':
742 if (zfs_props == NULL && be_nvl_alloc(&zfs_props) != 0)
743 return (1);
744
745 propname = optarg;
746 if ((propval = strchr(propname, '=')) == NULL) {
747 (void) fprintf(stderr, _("missing "
748 "'=' for -o option\n"));
749 goto out2;
750 }
751 *propval = '\0';
752 propval++;
753 if (nvlist_lookup_string(zfs_props, propname,
754 &strval) == 0) {
755 (void) fprintf(stderr, _("property '%s' "
756 "specified multiple times\n"), propname);
757 goto out2;
758
759 }
760 if (be_nvl_add_string(zfs_props, propname, propval)
761 != 0)
762 goto out2;
763
764 break;
765 case 'p':
766 nbe_zpool = optarg;
767 break;
768 case 'v':
769 libbe_print_errors(B_TRUE);
770 break;
771 default:
772 usage();
773 goto out2;
774 }
775 }
776
777 argc -= optind;
778 argv += optind;
779
780 if (argc != 1) {
781 usage();
782 goto out2;
783 }
784
785 nbe_name = argv[0];
786
787 if ((snap_name = strrchr(nbe_name, '@')) != NULL) {
788 if (snap_name[1] == '\0') {
789 usage();
790 goto out2;
791 }
792
793 snap_name[0] = '\0';
794 snap_name++;
795 is_snap = B_TRUE;
796 }
797
798 if (obe_name) {
799 if (is_snap) {
800 usage();
801 goto out2;
802 }
803
804 /*
805 * Check if obe_name is really a snapshot name.
806 * If so, split it out.
807 */
808 if ((snap_name = strrchr(obe_name, '@')) != NULL) {
809 if (snap_name[1] == '\0') {
810 usage();
811 goto out2;
812 }
813
814 snap_name[0] = '\0';
815 snap_name++;
816 }
817 } else if (is_snap) {
818 obe_name = nbe_name;
819 nbe_name = NULL;
820 }
821
822 if (be_nvl_alloc(&be_attrs) != 0)
823 goto out2;
824
825
826 if (zfs_props != NULL && be_nvl_add_nvlist(be_attrs,
827 BE_ATTR_ORIG_BE_NAME, zfs_props) != 0)
828 goto out;
829
830 if (obe_name != NULL && be_nvl_add_string(be_attrs,
831 BE_ATTR_ORIG_BE_NAME, obe_name) != 0)
832 goto out;
833
834 if (snap_name != NULL && be_nvl_add_string(be_attrs,
835 BE_ATTR_SNAP_NAME, snap_name) != 0)
836 goto out;
837
838 if (nbe_zpool != NULL && be_nvl_add_string(be_attrs,
839 BE_ATTR_NEW_BE_POOL, nbe_zpool) != 0)
840 goto out;
841
842 if (nbe_name != NULL && be_nvl_add_string(be_attrs,
843 BE_ATTR_NEW_BE_NAME, nbe_name) != 0)
844 goto out;
845
846 if (nbe_desc != NULL && be_nvl_add_string(be_attrs,
847 BE_ATTR_NEW_BE_DESC, nbe_desc) != 0)
848 goto out;
849
850 if (is_snap)
851 err = be_create_snapshot(be_attrs);
852 else
853 err = be_copy(be_attrs);
854
855 switch (err) {
856 case BE_SUCCESS:
857 if (!is_snap && !nbe_name) {
858 /*
859 * We requested an auto named BE; find out the
860 * name of the BE that was created for us and
861 * the auto snapshot created from the original BE.
862 */
863 if (nvlist_lookup_string(be_attrs, BE_ATTR_NEW_BE_NAME,
864 &nbe_name) != 0) {
865 (void) fprintf(stderr, _("failed to get %s "
866 "attribute\n"), BE_ATTR_NEW_BE_NAME);
867 break;
868 } else
869 (void) printf(_("Auto named BE: %s\n"),
870 nbe_name);
871
872 if (nvlist_lookup_string(be_attrs, BE_ATTR_SNAP_NAME,
873 &snap_name) != 0) {
874 (void) fprintf(stderr, _("failed to get %s "
875 "attribute\n"), BE_ATTR_SNAP_NAME);
876 break;
877 } else
878 (void) printf(_("Auto named snapshot: %s\n"),
879 snap_name);
880 }
881
882 if (!is_snap && activate) {
883 char *args[] = { "activate", "", NULL };
884 args[1] = nbe_name;
885 optind = 1;
886
887 err = be_do_activate(2, args);
888 goto out;
889 }
890
891 (void) printf(_("Created successfully\n"));
892 break;
893 case BE_ERR_BE_EXISTS:
894 (void) fprintf(stderr, _("BE %s already exists\n."
895 "Please choose a different BE name.\n"), nbe_name);
896 break;
897 case BE_ERR_SS_EXISTS:
898 (void) fprintf(stderr, _("BE %s snapshot %s already exists.\n"
899 "Please choose a different snapshot name.\n"), obe_name,
900 snap_name);
901 break;
902 case BE_ERR_PERM:
903 case BE_ERR_ACCESS:
904 if (is_snap)
905 (void) fprintf(stderr, _("Unable to create snapshot "
906 "%s.\n"), snap_name);
907 else
908 (void) fprintf(stderr, _("Unable to create %s.\n"),
909 nbe_name);
910 (void) fprintf(stderr, _("You have insufficient privileges to "
911 "execute this command.\n"));
912 break;
913 default:
914 if (is_snap)
915 (void) fprintf(stderr, _("Unable to create snapshot "
916 "%s.\n"), snap_name);
917 else
918 (void) fprintf(stderr, _("Unable to create %s.\n"),
919 nbe_name);
920 (void) fprintf(stderr, "%s\n", be_err_to_str(err));
921 }
922
923 out:
924 nvlist_free(be_attrs);
925 out2:
926 nvlist_free(zfs_props);
927
928 return (err);
929 }
930
931 static int
be_do_destroy(int argc,char ** argv)932 be_do_destroy(int argc, char **argv)
933 {
934 nvlist_t *be_attrs;
935 boolean_t is_snap = B_FALSE;
936 boolean_t suppress_prompt = B_FALSE;
937 int err = 1;
938 int c;
939 int destroy_flags = 0;
940 char *snap_name;
941 char *be_name;
942
943 while ((c = getopt(argc, argv, "fFsv")) != -1) {
944 switch (c) {
945 case 'f':
946 destroy_flags |= BE_DESTROY_FLAG_FORCE_UNMOUNT;
947 break;
948 case 's':
949 destroy_flags |= BE_DESTROY_FLAG_SNAPSHOTS;
950 break;
951 case 'v':
952 libbe_print_errors(B_TRUE);
953 break;
954 case 'F':
955 suppress_prompt = B_TRUE;
956 break;
957 default:
958 usage();
959 return (1);
960 }
961 }
962
963 argc -= optind;
964 argv += optind;
965
966 if (argc != 1) {
967 usage();
968 return (1);
969 }
970
971 be_name = argv[0];
972 if (!suppress_prompt && !confirm_destroy(be_name)) {
973 (void) printf(_("%s has not been destroyed.\n"), be_name);
974 return (0);
975 }
976
977 if ((snap_name = strrchr(be_name, '@')) != NULL) {
978 if (snap_name[1] == '\0') {
979 usage();
980 return (1);
981 }
982
983 is_snap = B_TRUE;
984 *snap_name = '\0';
985 snap_name++;
986 }
987
988 if (be_nvl_alloc(&be_attrs) != 0)
989 return (1);
990
991
992 if (be_nvl_add_string(be_attrs, BE_ATTR_ORIG_BE_NAME, be_name) != 0)
993 goto out;
994
995 if (is_snap) {
996 if (be_nvl_add_string(be_attrs, BE_ATTR_SNAP_NAME,
997 snap_name) != 0)
998 goto out;
999
1000 err = be_destroy_snapshot(be_attrs);
1001 } else {
1002 if (be_nvl_add_uint16(be_attrs, BE_ATTR_DESTROY_FLAGS,
1003 destroy_flags) != 0)
1004 goto out;
1005
1006 err = be_destroy(be_attrs);
1007 }
1008
1009 switch (err) {
1010 case BE_SUCCESS:
1011 (void) printf(_("Destroyed successfully\n"));
1012 break;
1013 case BE_ERR_MOUNTED:
1014 (void) fprintf(stderr, _("Unable to destroy %s.\n"), be_name);
1015 (void) fprintf(stderr, _("It is currently mounted and must be "
1016 "unmounted before it can be destroyed.\n" "Use 'beadm "
1017 "unmount %s' to unmount the BE before destroying\nit or "
1018 "'beadm destroy -f %s'.\n"), be_name, be_name);
1019 break;
1020 case BE_ERR_DESTROY_CURR_BE:
1021 (void) fprintf(stderr, _("%s is the currently active BE and "
1022 "cannot be destroyed.\nYou must boot from another BE in "
1023 "order to destroy %s.\n"), be_name, be_name);
1024 break;
1025 case BE_ERR_ZONES_UNMOUNT:
1026 (void) fprintf(stderr, _("Unable to destroy one of " "%s's "
1027 "zone BE's.\nUse 'beadm destroy -f %s' or "
1028 "'zfs -f destroy <dataset>'.\n"), be_name, be_name);
1029 break;
1030 case BE_ERR_SS_NOENT:
1031 (void) fprintf(stderr, _("%s does not exist or appear "
1032 "to be a valid snapshot.\nPlease check that the name of "
1033 "the snapshot provided is correct.\n"), snap_name);
1034 break;
1035 case BE_ERR_PERM:
1036 case BE_ERR_ACCESS:
1037 (void) fprintf(stderr, _("Unable to destroy %s.\n"), be_name);
1038 (void) fprintf(stderr, _("You have insufficient privileges to "
1039 "execute this command.\n"));
1040 break;
1041 case BE_ERR_SS_EXISTS:
1042 (void) fprintf(stderr, _("Unable to destroy %s: "
1043 "BE has snapshots.\nUse 'beadm destroy -s %s' or "
1044 "'zfs -r destroy <dataset>'.\n"), be_name, be_name);
1045 break;
1046 default:
1047 (void) fprintf(stderr, _("Unable to destroy %s.\n"), be_name);
1048 (void) fprintf(stderr, "%s\n", be_err_to_str(err));
1049 }
1050
1051 out:
1052 nvlist_free(be_attrs);
1053 return (err);
1054 }
1055
1056 static int
be_do_list(int argc,char ** argv)1057 be_do_list(int argc, char **argv)
1058 {
1059 be_node_list_t *be_nodes = NULL;
1060 boolean_t all = B_FALSE;
1061 boolean_t dsets = B_FALSE;
1062 boolean_t snaps = B_FALSE;
1063 boolean_t parsable = B_FALSE;
1064 int err = 1;
1065 int c = 0;
1066 char *be_name = NULL;
1067 be_sort_t order = BE_SORT_UNSPECIFIED;
1068
1069 while ((c = getopt(argc, argv, "adk:svHK:")) != -1) {
1070 switch (c) {
1071 case 'a':
1072 all = B_TRUE;
1073 break;
1074 case 'd':
1075 dsets = B_TRUE;
1076 break;
1077 case 'k':
1078 case 'K':
1079 if (order != BE_SORT_UNSPECIFIED) {
1080 (void) fprintf(stderr, _("Sort key can be "
1081 "specified only once.\n"));
1082 usage();
1083 return (1);
1084 }
1085 if (strcmp(optarg, "date") == 0) {
1086 if (c == 'k')
1087 order = BE_SORT_DATE;
1088 else
1089 order = BE_SORT_DATE_REV;
1090 break;
1091 }
1092 if (strcmp(optarg, "name") == 0) {
1093 if (c == 'k')
1094 order = BE_SORT_NAME;
1095 else
1096 order = BE_SORT_NAME_REV;
1097 break;
1098 }
1099 if (strcmp(optarg, "space") == 0) {
1100 if (c == 'k')
1101 order = BE_SORT_SPACE;
1102 else
1103 order = BE_SORT_SPACE_REV;
1104 break;
1105 }
1106 (void) fprintf(stderr, _("Unknown sort key: %s\n"),
1107 optarg);
1108 usage();
1109 return (1);
1110 case 's':
1111 snaps = B_TRUE;
1112 break;
1113 case 'v':
1114 libbe_print_errors(B_TRUE);
1115 break;
1116 case 'H':
1117 parsable = B_TRUE;
1118 break;
1119 default:
1120 usage();
1121 return (1);
1122 }
1123 }
1124
1125 if (all) {
1126 if (dsets) {
1127 (void) fprintf(stderr, _("Invalid options: -a and %s "
1128 "are mutually exclusive.\n"), "-d");
1129 usage();
1130 return (1);
1131 }
1132 if (snaps) {
1133 (void) fprintf(stderr, _("Invalid options: -a and %s "
1134 "are mutually exclusive.\n"), "-s");
1135 usage();
1136 return (1);
1137 }
1138
1139 dsets = B_TRUE;
1140 snaps = B_TRUE;
1141 }
1142
1143 argc -= optind;
1144 argv += optind;
1145
1146
1147 if (argc == 1)
1148 be_name = argv[0];
1149
1150 err = be_list(be_name, &be_nodes,
1151 snaps ? BE_LIST_SNAPSHOTS : BE_LIST_DEFAULT);
1152
1153 switch (err) {
1154 case BE_SUCCESS:
1155 /* the default sort is ascending date, no need to sort twice */
1156 if (order == BE_SORT_UNSPECIFIED)
1157 order = BE_SORT_DATE;
1158
1159 if (order != BE_SORT_DATE) {
1160 err = be_sort(&be_nodes, order);
1161 if (err != BE_SUCCESS) {
1162 (void) fprintf(stderr, _("Unable to sort Boot "
1163 "Environment\n"));
1164 (void) fprintf(stderr, "%s\n",
1165 be_err_to_str(err));
1166 break;
1167 }
1168 }
1169
1170 print_nodes(be_name, dsets, snaps, parsable, be_nodes);
1171 break;
1172 case BE_ERR_BE_NOENT:
1173 if (be_name == NULL)
1174 (void) fprintf(stderr, _("No boot environments found "
1175 "on this system.\n"));
1176 else {
1177 (void) fprintf(stderr, _("%s does not exist or appear "
1178 "to be a valid BE.\nPlease check that the name of "
1179 "the BE provided is correct.\n"), be_name);
1180 }
1181 break;
1182 default:
1183 (void) fprintf(stderr, _("Unable to display Boot "
1184 "Environment\n"));
1185 (void) fprintf(stderr, "%s\n", be_err_to_str(err));
1186 }
1187
1188 if (be_nodes != NULL)
1189 be_free_list(be_nodes);
1190 return (err);
1191 }
1192
1193 static int
be_do_mount(int argc,char ** argv)1194 be_do_mount(int argc, char **argv)
1195 {
1196 nvlist_t *be_attrs;
1197 boolean_t shared_fs = B_FALSE;
1198 int err = 1;
1199 int c;
1200 int mount_flags = 0;
1201 char *obe_name;
1202 char *mountpoint;
1203 char *tmp_mp = NULL;
1204
1205 while ((c = getopt(argc, argv, "s:v")) != -1) {
1206 switch (c) {
1207 case 's':
1208 shared_fs = B_TRUE;
1209
1210 mount_flags |= BE_MOUNT_FLAG_SHARED_FS;
1211
1212 if (strcmp(optarg, "rw") == 0) {
1213 mount_flags |= BE_MOUNT_FLAG_SHARED_RW;
1214 } else if (strcmp(optarg, "ro") != 0) {
1215 (void) fprintf(stderr, _("The -s flag "
1216 "requires an argument [ rw | ro ]\n"));
1217 usage();
1218 return (1);
1219 }
1220
1221 break;
1222 case 'v':
1223 libbe_print_errors(B_TRUE);
1224 break;
1225 default:
1226 usage();
1227 return (1);
1228 }
1229 }
1230
1231 argc -= optind;
1232 argv += optind;
1233
1234 if (argc < 1 || argc > 2) {
1235 usage();
1236 return (1);
1237 }
1238
1239 obe_name = argv[0];
1240
1241 if (argc == 2) {
1242 mountpoint = argv[1];
1243 if (mountpoint[0] != '/') {
1244 (void) fprintf(stderr, _("Invalid mount point %s. "
1245 "Mount point must start with a /.\n"), mountpoint);
1246 return (1);
1247 }
1248 } else {
1249 const char *tmpdir = getenv("TMPDIR");
1250 const char *tmpname = "tmp.XXXXXX";
1251 int sz;
1252
1253 if (tmpdir == NULL)
1254 tmpdir = "/tmp";
1255
1256 sz = asprintf(&tmp_mp, "%s/%s", tmpdir, tmpname);
1257 if (sz < 0) {
1258 (void) fprintf(stderr, _("internal error: "
1259 "out of memory\n"));
1260 return (1);
1261 }
1262
1263 mountpoint = mkdtemp(tmp_mp);
1264 }
1265
1266 if (be_nvl_alloc(&be_attrs) != 0)
1267 return (1);
1268
1269 if (be_nvl_add_string(be_attrs, BE_ATTR_ORIG_BE_NAME, obe_name) != 0)
1270 goto out;
1271
1272 if (be_nvl_add_string(be_attrs, BE_ATTR_MOUNTPOINT, mountpoint) != 0)
1273 goto out;
1274
1275 if (shared_fs && be_nvl_add_uint16(be_attrs, BE_ATTR_MOUNT_FLAGS,
1276 mount_flags) != 0)
1277 goto out;
1278
1279 err = be_mount(be_attrs);
1280
1281 switch (err) {
1282 case BE_SUCCESS:
1283 (void) printf(_("Mounted successfully on: '%s'\n"), mountpoint);
1284 break;
1285 case BE_ERR_BE_NOENT:
1286 (void) fprintf(stderr, _("%s does not exist or appear "
1287 "to be a valid BE.\nPlease check that the name of "
1288 "the BE provided is correct.\n"), obe_name);
1289 break;
1290 case BE_ERR_MOUNTED:
1291 (void) fprintf(stderr, _("%s is already mounted.\n"
1292 "Please unmount the BE before mounting it again.\n"),
1293 obe_name);
1294 break;
1295 case BE_ERR_PERM:
1296 case BE_ERR_ACCESS:
1297 (void) fprintf(stderr, _("Unable to mount %s.\n"), obe_name);
1298 (void) fprintf(stderr, _("You have insufficient privileges to "
1299 "execute this command.\n"));
1300 break;
1301 case BE_ERR_NO_MOUNTED_ZONE:
1302 (void) fprintf(stderr, _("Mounted on '%s'.\nUnable to mount "
1303 "one of %s's zone BE's.\n"), mountpoint, obe_name);
1304 break;
1305 default:
1306 (void) fprintf(stderr, _("Unable to mount %s.\n"), obe_name);
1307 (void) fprintf(stderr, "%s\n", be_err_to_str(err));
1308 }
1309
1310 out:
1311 if (tmp_mp != NULL)
1312 free(tmp_mp);
1313 nvlist_free(be_attrs);
1314 return (err);
1315 }
1316
1317 static int
be_do_unmount(int argc,char ** argv)1318 be_do_unmount(int argc, char **argv)
1319 {
1320 nvlist_t *be_attrs;
1321 char *obe_name;
1322 int err = 1;
1323 int c;
1324 int unmount_flags = 0;
1325
1326 while ((c = getopt(argc, argv, "fv")) != -1) {
1327 switch (c) {
1328 case 'f':
1329 unmount_flags |= BE_UNMOUNT_FLAG_FORCE;
1330 break;
1331 case 'v':
1332 libbe_print_errors(B_TRUE);
1333 break;
1334 default:
1335 usage();
1336 return (1);
1337 }
1338 }
1339
1340 argc -= optind;
1341 argv += optind;
1342
1343 if (argc != 1) {
1344 usage();
1345 return (1);
1346 }
1347
1348 obe_name = argv[0];
1349
1350 if (be_nvl_alloc(&be_attrs) != 0)
1351 return (1);
1352
1353
1354 if (be_nvl_add_string(be_attrs, BE_ATTR_ORIG_BE_NAME, obe_name) != 0)
1355 goto out;
1356
1357 if (be_nvl_add_uint16(be_attrs, BE_ATTR_UNMOUNT_FLAGS,
1358 unmount_flags) != 0)
1359 goto out;
1360
1361 err = be_unmount(be_attrs);
1362
1363 switch (err) {
1364 case BE_SUCCESS:
1365 (void) printf(_("Unmounted successfully\n"));
1366 break;
1367 case BE_ERR_BE_NOENT:
1368 (void) fprintf(stderr, _("%s does not exist or appear "
1369 "to be a valid BE.\nPlease check that the name of "
1370 "the BE provided is correct.\n"), obe_name);
1371 break;
1372 case BE_ERR_UMOUNT_CURR_BE:
1373 (void) fprintf(stderr, _("%s is the currently active BE.\n"
1374 "It cannot be unmounted unless another BE is the "
1375 "currently active BE.\n"), obe_name);
1376 break;
1377 case BE_ERR_UMOUNT_SHARED:
1378 (void) fprintf(stderr, _("%s is a shared file system and it "
1379 "cannot be unmounted.\n"), obe_name);
1380 break;
1381 case BE_ERR_PERM:
1382 case BE_ERR_ACCESS:
1383 (void) fprintf(stderr, _("Unable to unmount %s.\n"), obe_name);
1384 (void) fprintf(stderr, _("You have insufficient privileges to "
1385 "execute this command.\n"));
1386 break;
1387 default:
1388 (void) fprintf(stderr, _("Unable to unmount %s.\n"), obe_name);
1389 (void) fprintf(stderr, "%s\n", be_err_to_str(err));
1390 }
1391
1392 out:
1393 nvlist_free(be_attrs);
1394 return (err);
1395 }
1396
1397 static int
be_do_rename(int argc,char ** argv)1398 be_do_rename(int argc, char **argv)
1399 {
1400 nvlist_t *be_attrs;
1401 char *obe_name;
1402 char *nbe_name;
1403 int err = 1;
1404 int c;
1405
1406 while ((c = getopt(argc, argv, "v")) != -1) {
1407 switch (c) {
1408 case 'v':
1409 libbe_print_errors(B_TRUE);
1410 break;
1411 default:
1412 usage();
1413 return (1);
1414 }
1415 }
1416
1417 argc -= optind;
1418 argv += optind;
1419
1420 if (argc != 2) {
1421 usage();
1422 return (1);
1423 }
1424
1425 obe_name = argv[0];
1426 nbe_name = argv[1];
1427
1428 if (be_nvl_alloc(&be_attrs) != 0)
1429 return (1);
1430
1431 if (be_nvl_add_string(be_attrs, BE_ATTR_ORIG_BE_NAME, obe_name) != 0)
1432 goto out;
1433
1434 if (be_nvl_add_string(be_attrs, BE_ATTR_NEW_BE_NAME, nbe_name) != 0)
1435 goto out;
1436
1437 err = be_rename(be_attrs);
1438
1439 switch (err) {
1440 case BE_SUCCESS:
1441 (void) printf(_("Renamed successfully\n"));
1442 break;
1443 case BE_ERR_BE_NOENT:
1444 (void) fprintf(stderr, _("%s does not exist or appear "
1445 "to be a valid BE.\nPlease check that the name of "
1446 "the BE provided is correct.\n"), obe_name);
1447 break;
1448 case BE_ERR_PERM:
1449 case BE_ERR_ACCESS:
1450 (void) fprintf(stderr, _("Rename of BE %s failed.\n"),
1451 obe_name);
1452 (void) fprintf(stderr, _("You have insufficient privileges to "
1453 "execute this command.\n"));
1454 break;
1455 default:
1456 (void) fprintf(stderr, _("Rename of BE %s failed.\n"),
1457 obe_name);
1458 (void) fprintf(stderr, "%s\n", be_err_to_str(err));
1459 }
1460
1461 out:
1462 nvlist_free(be_attrs);
1463 return (err);
1464 }
1465
1466 static int
be_do_rollback(int argc,char ** argv)1467 be_do_rollback(int argc, char **argv)
1468 {
1469 nvlist_t *be_attrs;
1470 char *obe_name;
1471 char *snap_name;
1472 int err = 1;
1473 int c;
1474
1475 while ((c = getopt(argc, argv, "v")) != -1) {
1476 switch (c) {
1477 case 'v':
1478 libbe_print_errors(B_TRUE);
1479 break;
1480 default:
1481 usage();
1482 return (1);
1483 }
1484 }
1485
1486 argc -= optind;
1487 argv += optind;
1488
1489 if (argc < 1 || argc > 2) {
1490 usage();
1491 return (1);
1492 }
1493
1494 obe_name = argv[0];
1495 if (argc == 2)
1496 snap_name = argv[1];
1497 else { /* argc == 1 */
1498 if ((snap_name = strrchr(obe_name, '@')) != NULL) {
1499 if (snap_name[1] == '\0') {
1500 usage();
1501 return (1);
1502 }
1503
1504 snap_name[0] = '\0';
1505 snap_name++;
1506 } else {
1507 usage();
1508 return (1);
1509 }
1510 }
1511
1512 if (be_nvl_alloc(&be_attrs) != 0)
1513 return (1);
1514
1515 if (be_nvl_add_string(be_attrs, BE_ATTR_ORIG_BE_NAME, obe_name) != 0)
1516 goto out;
1517
1518 if (be_nvl_add_string(be_attrs, BE_ATTR_SNAP_NAME, snap_name) != 0)
1519 goto out;
1520
1521 err = be_rollback(be_attrs);
1522
1523 switch (err) {
1524 case BE_SUCCESS:
1525 (void) printf(_("Rolled back successfully\n"));
1526 break;
1527 case BE_ERR_BE_NOENT:
1528 (void) fprintf(stderr, _("%s does not exist or appear "
1529 "to be a valid BE.\nPlease check that the name of "
1530 "the BE provided is correct.\n"), obe_name);
1531 break;
1532 case BE_ERR_SS_NOENT:
1533 (void) fprintf(stderr, _("%s does not exist or appear "
1534 "to be a valid snapshot.\nPlease check that the name of "
1535 "the snapshot provided is correct.\n"), snap_name);
1536 break;
1537 case BE_ERR_PERM:
1538 case BE_ERR_ACCESS:
1539 (void) fprintf(stderr, _("Rollback of BE %s snapshot %s "
1540 "failed.\n"), obe_name, snap_name);
1541 (void) fprintf(stderr, _("You have insufficient privileges to "
1542 "execute this command.\n"));
1543 break;
1544 default:
1545 (void) fprintf(stderr, _("Rollback of BE %s snapshot %s "
1546 "failed.\n"), obe_name, snap_name);
1547 (void) fprintf(stderr, "%s\n", be_err_to_str(err));
1548 }
1549
1550 out:
1551 nvlist_free(be_attrs);
1552 return (err);
1553 }
1554