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