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) 2008, 2010, Oracle and/or its affiliates. All rights reserved.
24 */
25
26 /*
27 * Copyright 2013 Nexenta Systems, Inc. All rights reserved.
28 * Copyright 2015 Toomas Soome <tsoome@me.com>
29 * Copyright 2015 Gary Mills
30 */
31
32 #include <assert.h>
33 #include <libintl.h>
34 #include <libnvpair.h>
35 #include <libzfs.h>
36 #include <stdio.h>
37 #include <stdlib.h>
38 #include <string.h>
39 #include <strings.h>
40 #include <sys/types.h>
41 #include <sys/stat.h>
42 #include <unistd.h>
43 #include <errno.h>
44
45 #include <libbe.h>
46 #include <libbe_priv.h>
47
48 /*
49 * Callback data used for zfs_iter calls.
50 */
51 typedef struct list_callback_data {
52 char *zpool_name;
53 char *be_name;
54 be_node_list_t *be_nodes_head;
55 be_node_list_t *be_nodes;
56 char current_be[MAXPATHLEN];
57 } list_callback_data_t;
58
59 /*
60 * Private function prototypes
61 */
62 static int be_add_children_callback(zfs_handle_t *zhp, void *data);
63 static int be_get_list_callback(zpool_handle_t *, void *);
64 static int be_get_node_data(zfs_handle_t *, be_node_list_t *, char *,
65 const char *, char *, char *);
66 static int be_get_zone_node_data(be_node_list_t *, char *);
67 static int be_get_ds_data(zfs_handle_t *, char *, be_dataset_list_t *,
68 be_node_list_t *);
69 static int be_get_ss_data(zfs_handle_t *, char *, be_snapshot_list_t *,
70 be_node_list_t *);
71 static int be_sort_list(be_node_list_t **,
72 int (*)(const void *, const void *));
73 static int be_qsort_compare_BEs_name(const void *, const void *);
74 static int be_qsort_compare_BEs_name_rev(const void *, const void *);
75 static int be_qsort_compare_BEs_date(const void *, const void *);
76 static int be_qsort_compare_BEs_date_rev(const void *, const void *);
77 static int be_qsort_compare_BEs_space(const void *, const void *);
78 static int be_qsort_compare_BEs_space_rev(const void *, const void *);
79 static int be_qsort_compare_snapshots(const void *x, const void *y);
80 static int be_qsort_compare_datasets(const void *x, const void *y);
81 static void *be_list_alloc(int *, size_t);
82
83 /*
84 * Private data.
85 */
86 static char be_container_ds[MAXPATHLEN];
87 static boolean_t zone_be = B_FALSE;
88
89 /* ******************************************************************** */
90 /* Public Functions */
91 /* ******************************************************************** */
92
93 /*
94 * Function: be_list
95 * Description: Calls _be_list which finds all the BEs on the system and
96 * returns the datasets and snapshots belonging to each BE.
97 * Also data, such as dataset and snapshot properties,
98 * for each BE and their snapshots and datasets is
99 * returned. The data returned is as described in the
100 * be_dataset_list_t, be_snapshot_list_t and be_node_list_t
101 * structures.
102 * Parameters:
103 * be_name - The name of the BE to look up.
104 * If NULL a list of all BEs will be returned.
105 * be_nodes - A reference pointer to the list of BEs. The list
106 * structure will be allocated by _be_list and must
107 * be freed by a call to be_free_list. If there are no
108 * BEs found on the system this reference will be
109 * set to NULL.
110 * Return:
111 * BE_SUCCESS - Success
112 * be_errno_t - Failure
113 * Scope:
114 * Public
115 */
116 int
be_list(char * be_name,be_node_list_t ** be_nodes)117 be_list(char *be_name, be_node_list_t **be_nodes)
118 {
119 int ret = BE_SUCCESS;
120
121 /* Initialize libzfs handle */
122 if (!be_zfs_init())
123 return (BE_ERR_INIT);
124
125 /* Validate be_name if its not NULL */
126 if (be_name != NULL) {
127 if (!be_valid_be_name(be_name)) {
128 be_print_err(gettext("be_list: "
129 "invalid BE name %s\n"), be_name);
130 return (BE_ERR_INVAL);
131 }
132 }
133
134 ret = _be_list(be_name, be_nodes);
135
136 be_zfs_fini();
137
138 return (ret);
139 }
140
141 /*
142 * Function: be_sort
143 * Description: Sort BE node list
144 * Parameters:
145 * pointer to address of list head
146 * sort order type
147 * Return:
148 * BE_SUCCESS - Success
149 * be_errno_t - Failure
150 * Side effect:
151 * node list sorted by name
152 * Scope:
153 * Public
154 */
155 int
be_sort(be_node_list_t ** be_nodes,int order)156 be_sort(be_node_list_t **be_nodes, int order)
157 {
158 int (*compar)(const void *, const void *) = be_qsort_compare_BEs_date;
159
160 if (be_nodes == NULL)
161 return (BE_ERR_INVAL);
162
163 switch (order) {
164 case BE_SORT_UNSPECIFIED:
165 case BE_SORT_DATE:
166 compar = be_qsort_compare_BEs_date;
167 break;
168 case BE_SORT_DATE_REV:
169 compar = be_qsort_compare_BEs_date_rev;
170 break;
171 case BE_SORT_NAME:
172 compar = be_qsort_compare_BEs_name;
173 break;
174 case BE_SORT_NAME_REV:
175 compar = be_qsort_compare_BEs_name_rev;
176 break;
177 case BE_SORT_SPACE:
178 compar = be_qsort_compare_BEs_space;
179 break;
180 case BE_SORT_SPACE_REV:
181 compar = be_qsort_compare_BEs_space_rev;
182 break;
183 default:
184 be_print_err(gettext("be_sort: invalid sort order %d\n"),
185 order);
186 return (BE_ERR_INVAL);
187 }
188
189 return (be_sort_list(be_nodes, compar));
190 }
191
192 /* ******************************************************************** */
193 /* Semi-Private Functions */
194 /* ******************************************************************** */
195
196 /*
197 * Function: _be_list
198 * Description: This does the actual work described in be_list.
199 * Parameters:
200 * be_name - The name of the BE to look up.
201 * If NULL a list of all BEs will be returned.
202 * be_nodes - A reference pointer to the list of BEs. The list
203 * structure will be allocated here and must
204 * be freed by a call to be_free_list. If there are no
205 * BEs found on the system this reference will be
206 * set to NULL.
207 * Return:
208 * BE_SUCCESS - Success
209 * be_errno_t - Failure
210 * Scope:
211 * Semi-private (library wide use only)
212 */
213 int
_be_list(char * be_name,be_node_list_t ** be_nodes)214 _be_list(char *be_name, be_node_list_t **be_nodes)
215 {
216 list_callback_data_t cb = { 0 };
217 be_transaction_data_t bt = { 0 };
218 int ret = BE_SUCCESS;
219 int sret;
220 zpool_handle_t *zphp;
221 char *rpool = NULL;
222 struct be_defaults be_defaults;
223
224 if (be_nodes == NULL)
225 return (BE_ERR_INVAL);
226
227 be_get_defaults(&be_defaults);
228
229 if (be_find_current_be(&bt) != BE_SUCCESS) {
230 /*
231 * We were unable to find a currently booted BE which
232 * probably means that we're not booted in a BE envoronment.
233 * None of the BE's will be marked as the active BE.
234 */
235 (void) strcpy(cb.current_be, "-");
236 } else {
237 (void) strncpy(cb.current_be, bt.obe_name,
238 sizeof (cb.current_be));
239 rpool = bt.obe_zpool;
240 }
241
242 /*
243 * If be_name is NULL we'll look for all BE's on the system.
244 * If not then we will only return data for the specified BE.
245 */
246 if (be_name != NULL)
247 cb.be_name = strdup(be_name);
248
249 if (be_defaults.be_deflt_rpool_container && rpool != NULL) {
250 if ((zphp = zpool_open(g_zfs, rpool)) == NULL) {
251 be_print_err(gettext("be_list: failed to "
252 "open rpool (%s): %s\n"), rpool,
253 libzfs_error_description(g_zfs));
254 free(cb.be_name);
255 return (zfs_err_to_be_err(g_zfs));
256 }
257
258 ret = be_get_list_callback(zphp, &cb);
259 } else {
260 if ((zpool_iter(g_zfs, be_get_list_callback, &cb)) != 0) {
261 if (cb.be_nodes_head != NULL) {
262 be_free_list(cb.be_nodes_head);
263 cb.be_nodes_head = NULL;
264 cb.be_nodes = NULL;
265 }
266 ret = BE_ERR_BE_NOENT;
267 }
268 }
269
270 if (cb.be_nodes_head == NULL) {
271 if (be_name != NULL)
272 be_print_err(gettext("be_list: BE (%s) does not "
273 "exist\n"), be_name);
274 else
275 be_print_err(gettext("be_list: No BE's found\n"));
276 ret = BE_ERR_BE_NOENT;
277 }
278
279 *be_nodes = cb.be_nodes_head;
280
281 free(cb.be_name);
282
283 sret = be_sort(be_nodes, BE_SORT_DATE);
284
285 return ((ret == BE_SUCCESS) ? sret : ret);
286 }
287
288 /*
289 * Function: be_free_list
290 * Description: Frees up all the data allocated for the list of BEs,
291 * datasets and snapshots returned by be_list.
292 * Parameters:
293 * be_node - be_nodes_t structure returned from call to be_list.
294 * Returns:
295 * none
296 * Scope:
297 * Semi-private (library wide use only)
298 */
299 void
be_free_list(be_node_list_t * be_nodes)300 be_free_list(be_node_list_t *be_nodes)
301 {
302 be_node_list_t *temp_node = NULL;
303 be_node_list_t *list = be_nodes;
304
305 while (list != NULL) {
306 be_dataset_list_t *datasets = list->be_node_datasets;
307 be_snapshot_list_t *snapshots = list->be_node_snapshots;
308
309 while (datasets != NULL) {
310 be_dataset_list_t *temp_ds = datasets;
311 datasets = datasets->be_next_dataset;
312 free(temp_ds->be_dataset_name);
313 free(temp_ds->be_ds_mntpt);
314 free(temp_ds->be_ds_plcy_type);
315 free(temp_ds);
316 }
317
318 while (snapshots != NULL) {
319 be_snapshot_list_t *temp_ss = snapshots;
320 snapshots = snapshots->be_next_snapshot;
321 free(temp_ss->be_snapshot_name);
322 free(temp_ss->be_snapshot_type);
323 free(temp_ss);
324 }
325
326 temp_node = list;
327 list = list->be_next_node;
328 free(temp_node->be_node_name);
329 free(temp_node->be_root_ds);
330 free(temp_node->be_rpool);
331 free(temp_node->be_mntpt);
332 free(temp_node->be_policy_type);
333 free(temp_node->be_uuid_str);
334 free(temp_node);
335 }
336 }
337
338 /*
339 * Function: be_get_zone_be_list
340 * Description: Finds all the BEs for this zone on the system.
341 * Parameters:
342 * zone_be_name - The name of the BE to look up.
343 * zone_be_container_ds - The dataset for the zone.
344 * zbe_nodes - A reference pointer to the list of BEs. The list
345 * structure will be allocated here and must
346 * be freed by a call to be_free_list. If there are no
347 * BEs found on the system this reference will be
348 * set to NULL.
349 * Return:
350 * BE_SUCCESS - Success
351 * be_errno_t - Failure
352 * Scope:
353 * Semi-private (library wide use only)
354 */
355 int
be_get_zone_be_list(char * zone_be_name,char * zone_be_container_ds,be_node_list_t ** zbe_nodes)356 be_get_zone_be_list(
357 /* LINTED */
358 char *zone_be_name,
359 char *zone_be_container_ds,
360 be_node_list_t **zbe_nodes)
361 {
362 zfs_handle_t *zhp = NULL;
363 list_callback_data_t cb = { 0 };
364 int ret = BE_SUCCESS;
365
366 if (zbe_nodes == NULL)
367 return (BE_ERR_INVAL);
368
369 if (!zfs_dataset_exists(g_zfs, zone_be_container_ds,
370 ZFS_TYPE_FILESYSTEM)) {
371 return (BE_ERR_BE_NOENT);
372 }
373
374 zone_be = B_TRUE;
375
376 if ((zhp = zfs_open(g_zfs, zone_be_container_ds,
377 ZFS_TYPE_FILESYSTEM)) == NULL) {
378 be_print_err(gettext("be_get_zone_be_list: failed to open "
379 "the zone BE dataset %s: %s\n"), zone_be_container_ds,
380 libzfs_error_description(g_zfs));
381 ret = zfs_err_to_be_err(g_zfs);
382 goto cleanup;
383 }
384
385 (void) strcpy(be_container_ds, zone_be_container_ds);
386
387 if (cb.be_nodes_head == NULL) {
388 if ((cb.be_nodes_head = be_list_alloc(&ret,
389 sizeof (be_node_list_t))) == NULL) {
390 ZFS_CLOSE(zhp);
391 goto cleanup;
392 }
393 cb.be_nodes = cb.be_nodes_head;
394 }
395 if (ret == 0)
396 ret = zfs_iter_filesystems(zhp, be_add_children_callback, &cb);
397 ZFS_CLOSE(zhp);
398
399 *zbe_nodes = cb.be_nodes_head;
400
401 cleanup:
402 zone_be = B_FALSE;
403
404 return (ret);
405 }
406
407 /* ******************************************************************** */
408 /* Private Functions */
409 /* ******************************************************************** */
410
411 /*
412 * Function: be_get_list_callback
413 * Description: Callback function used by zfs_iter to look through all
414 * the pools on the system looking for BEs. If a BE name was
415 * specified only that BE's information will be collected and
416 * returned.
417 * Parameters:
418 * zlp - handle to the first zfs dataset. (provided by the
419 * zfs_iter_* call)
420 * data - pointer to the callback data and where we'll pass
421 * the BE information back.
422 * Returns:
423 * 0 - Success
424 * be_errno_t - Failure
425 * Scope:
426 * Private
427 */
428 static int
be_get_list_callback(zpool_handle_t * zlp,void * data)429 be_get_list_callback(zpool_handle_t *zlp, void *data)
430 {
431 list_callback_data_t *cb = (list_callback_data_t *)data;
432 char be_ds[MAXPATHLEN];
433 char *open_ds = NULL;
434 char *rpool = NULL;
435 zfs_handle_t *zhp = NULL;
436 int ret = 0;
437
438 cb->zpool_name = rpool = (char *)zpool_get_name(zlp);
439
440 /*
441 * Generate string for the BE container dataset
442 */
443 be_make_container_ds(rpool, be_container_ds,
444 sizeof (be_container_ds));
445
446 /*
447 * If a BE name was specified we use it's root dataset in place of
448 * the container dataset. This is because we only want to collect
449 * the information for the specified BE.
450 */
451 if (cb->be_name != NULL) {
452 if (!be_valid_be_name(cb->be_name))
453 return (BE_ERR_INVAL);
454 /*
455 * Generate string for the BE root dataset
456 */
457 be_make_root_ds(rpool, cb->be_name, be_ds, sizeof (be_ds));
458 open_ds = be_ds;
459 } else {
460 open_ds = be_container_ds;
461 }
462
463 /*
464 * Check if the dataset exists
465 */
466 if (!zfs_dataset_exists(g_zfs, open_ds,
467 ZFS_TYPE_FILESYSTEM)) {
468 /*
469 * The specified dataset does not exist in this pool or
470 * there are no valid BE's in this pool. Try the next zpool.
471 */
472 zpool_close(zlp);
473 return (0);
474 }
475
476 if ((zhp = zfs_open(g_zfs, open_ds, ZFS_TYPE_FILESYSTEM)) == NULL) {
477 be_print_err(gettext("be_get_list_callback: failed to open "
478 "the BE dataset %s: %s\n"), open_ds,
479 libzfs_error_description(g_zfs));
480 ret = zfs_err_to_be_err(g_zfs);
481 zpool_close(zlp);
482 return (ret);
483 }
484
485 /*
486 * If a BE name was specified we iterate through the datasets
487 * and snapshots for this BE only. Otherwise we will iterate
488 * through the next level of datasets to find all the BE's
489 * within the pool
490 */
491 if (cb->be_name != NULL) {
492 if (cb->be_nodes_head == NULL) {
493 if ((cb->be_nodes_head = be_list_alloc(&ret,
494 sizeof (be_node_list_t))) == NULL) {
495 ZFS_CLOSE(zhp);
496 zpool_close(zlp);
497 return (ret);
498 }
499 cb->be_nodes = cb->be_nodes_head;
500 }
501
502 if ((ret = be_get_node_data(zhp, cb->be_nodes, cb->be_name,
503 rpool, cb->current_be, be_ds)) != BE_SUCCESS) {
504 ZFS_CLOSE(zhp);
505 zpool_close(zlp);
506 return (ret);
507 }
508 ret = zfs_iter_snapshots(zhp, be_add_children_callback, cb);
509 }
510
511 if (ret == 0)
512 ret = zfs_iter_filesystems(zhp, be_add_children_callback, cb);
513 ZFS_CLOSE(zhp);
514
515 zpool_close(zlp);
516 return (ret);
517 }
518
519 /*
520 * Function: be_add_children_callback
521 * Description: Callback function used by zfs_iter to look through all
522 * the datasets and snapshots for each BE and add them to
523 * the lists of information to be passed back.
524 * Parameters:
525 * zhp - handle to the first zfs dataset. (provided by the
526 * zfs_iter_* call)
527 * data - pointer to the callback data and where we'll pass
528 * the BE information back.
529 * Returns:
530 * 0 - Success
531 * be_errno_t - Failure
532 * Scope:
533 * Private
534 */
535 static int
be_add_children_callback(zfs_handle_t * zhp,void * data)536 be_add_children_callback(zfs_handle_t *zhp, void *data)
537 {
538 list_callback_data_t *cb = (list_callback_data_t *)data;
539 char *str = NULL, *ds_path = NULL;
540 int ret = 0;
541 struct be_defaults be_defaults;
542
543 be_get_defaults(&be_defaults);
544
545 ds_path = str = strdup(zfs_get_name(zhp));
546
547 /*
548 * get past the end of the container dataset plus the trailing "/"
549 */
550 str = str + (strlen(be_container_ds) + 1);
551 if (be_defaults.be_deflt_rpool_container) {
552 /* just skip if invalid */
553 if (!be_valid_be_name(str))
554 return (BE_SUCCESS);
555 }
556
557 if (cb->be_nodes_head == NULL) {
558 if ((cb->be_nodes_head = be_list_alloc(&ret,
559 sizeof (be_node_list_t))) == NULL) {
560 ZFS_CLOSE(zhp);
561 return (ret);
562 }
563 cb->be_nodes = cb->be_nodes_head;
564 }
565
566 if (zfs_get_type(zhp) == ZFS_TYPE_SNAPSHOT && !zone_be) {
567 be_snapshot_list_t *snapshots = NULL;
568 if (cb->be_nodes->be_node_snapshots == NULL) {
569 if ((cb->be_nodes->be_node_snapshots =
570 be_list_alloc(&ret, sizeof (be_snapshot_list_t)))
571 == NULL || ret != BE_SUCCESS) {
572 ZFS_CLOSE(zhp);
573 return (ret);
574 }
575 cb->be_nodes->be_node_snapshots->be_next_snapshot =
576 NULL;
577 snapshots = cb->be_nodes->be_node_snapshots;
578 } else {
579 for (snapshots = cb->be_nodes->be_node_snapshots;
580 snapshots != NULL;
581 snapshots = snapshots->be_next_snapshot) {
582 if (snapshots->be_next_snapshot != NULL)
583 continue;
584 /*
585 * We're at the end of the list add the
586 * new snapshot.
587 */
588 if ((snapshots->be_next_snapshot =
589 be_list_alloc(&ret,
590 sizeof (be_snapshot_list_t))) == NULL ||
591 ret != BE_SUCCESS) {
592 ZFS_CLOSE(zhp);
593 return (ret);
594 }
595 snapshots = snapshots->be_next_snapshot;
596 snapshots->be_next_snapshot = NULL;
597 break;
598 }
599 }
600 if ((ret = be_get_ss_data(zhp, str, snapshots,
601 cb->be_nodes)) != BE_SUCCESS) {
602 ZFS_CLOSE(zhp);
603 return (ret);
604 }
605 } else if (strchr(str, '/') == NULL) {
606 if (cb->be_nodes->be_node_name != NULL) {
607 if ((cb->be_nodes->be_next_node =
608 be_list_alloc(&ret, sizeof (be_node_list_t))) ==
609 NULL || ret != BE_SUCCESS) {
610 ZFS_CLOSE(zhp);
611 return (ret);
612 }
613 cb->be_nodes = cb->be_nodes->be_next_node;
614 cb->be_nodes->be_next_node = NULL;
615 }
616
617 /*
618 * If this is a zone root dataset then we only need
619 * the name of the zone BE at this point. We grab that
620 * and return.
621 */
622 if (zone_be) {
623 ret = be_get_zone_node_data(cb->be_nodes, str);
624 ZFS_CLOSE(zhp);
625 return (ret);
626 }
627
628 if ((ret = be_get_node_data(zhp, cb->be_nodes, str,
629 cb->zpool_name, cb->current_be, ds_path)) != BE_SUCCESS) {
630 ZFS_CLOSE(zhp);
631 return (ret);
632 }
633 } else if (strchr(str, '/') != NULL && !zone_be) {
634 be_dataset_list_t *datasets = NULL;
635 if (cb->be_nodes->be_node_datasets == NULL) {
636 if ((cb->be_nodes->be_node_datasets =
637 be_list_alloc(&ret, sizeof (be_dataset_list_t)))
638 == NULL || ret != BE_SUCCESS) {
639 ZFS_CLOSE(zhp);
640 return (ret);
641 }
642 cb->be_nodes->be_node_datasets->be_next_dataset = NULL;
643 datasets = cb->be_nodes->be_node_datasets;
644 } else {
645 for (datasets = cb->be_nodes->be_node_datasets;
646 datasets != NULL;
647 datasets = datasets->be_next_dataset) {
648 if (datasets->be_next_dataset != NULL)
649 continue;
650 /*
651 * We're at the end of the list add
652 * the new dataset.
653 */
654 if ((datasets->be_next_dataset =
655 be_list_alloc(&ret,
656 sizeof (be_dataset_list_t)))
657 == NULL || ret != BE_SUCCESS) {
658 ZFS_CLOSE(zhp);
659 return (ret);
660 }
661 datasets = datasets->be_next_dataset;
662 datasets->be_next_dataset = NULL;
663 break;
664 }
665 }
666
667 if ((ret = be_get_ds_data(zhp, str,
668 datasets, cb->be_nodes)) != BE_SUCCESS) {
669 ZFS_CLOSE(zhp);
670 return (ret);
671 }
672 }
673 ret = zfs_iter_children(zhp, be_add_children_callback, cb);
674 if (ret != 0) {
675 be_print_err(gettext("be_add_children_callback: "
676 "encountered error: %s\n"),
677 libzfs_error_description(g_zfs));
678 ret = zfs_err_to_be_err(g_zfs);
679 }
680 ZFS_CLOSE(zhp);
681 return (ret);
682 }
683
684 /*
685 * Function: be_sort_list
686 * Description: Sort BE node list
687 * Parameters:
688 * pointer to address of list head
689 * compare function
690 * Return:
691 * BE_SUCCESS - Success
692 * be_errno_t - Failure
693 * Side effect:
694 * node list sorted by name
695 * Scope:
696 * Private
697 */
698 static int
be_sort_list(be_node_list_t ** pstart,int (* compar)(const void *,const void *))699 be_sort_list(be_node_list_t **pstart, int (*compar)(const void *, const void *))
700 {
701 int ret = BE_SUCCESS;
702 size_t ibe, nbe;
703 be_node_list_t *p = NULL;
704 be_node_list_t **ptrlist = NULL;
705 be_node_list_t **ptrtmp;
706
707 if (pstart == NULL) /* Nothing to sort */
708 return (BE_SUCCESS);
709 /* build array of linked list BE struct pointers */
710 for (p = *pstart, nbe = 0; p != NULL; nbe++, p = p->be_next_node) {
711 ptrtmp = realloc(ptrlist,
712 sizeof (be_node_list_t *) * (nbe + 2));
713 if (ptrtmp == NULL) { /* out of memory */
714 be_print_err(gettext("be_sort_list: memory "
715 "allocation failed\n"));
716 ret = BE_ERR_NOMEM;
717 goto free;
718 }
719 ptrlist = ptrtmp;
720 ptrlist[nbe] = p;
721 }
722 if (nbe == 0) /* Nothing to sort */
723 return (BE_SUCCESS);
724 /* in-place list quicksort using qsort(3C) */
725 if (nbe > 1) /* no sort if less than 2 BEs */
726 qsort(ptrlist, nbe, sizeof (be_node_list_t *), compar);
727
728 ptrlist[nbe] = NULL; /* add linked list terminator */
729 *pstart = ptrlist[0]; /* set new linked list header */
730 /* for each BE in list */
731 for (ibe = 0; ibe < nbe; ibe++) {
732 size_t k, ns; /* subordinate index, count */
733
734 /* rewrite list pointer chain, including terminator */
735 ptrlist[ibe]->be_next_node = ptrlist[ibe + 1];
736 /* sort subordinate snapshots */
737 if (ptrlist[ibe]->be_node_num_snapshots > 1) {
738 const size_t nmax = ptrlist[ibe]->be_node_num_snapshots;
739 be_snapshot_list_t ** const slist =
740 malloc(sizeof (be_snapshot_list_t *) * (nmax + 1));
741 be_snapshot_list_t *p;
742
743 if (slist == NULL) {
744 ret = BE_ERR_NOMEM;
745 continue;
746 }
747 /* build array of linked list snapshot struct ptrs */
748 for (ns = 0, p = ptrlist[ibe]->be_node_snapshots;
749 ns < nmax && p != NULL;
750 ns++, p = p->be_next_snapshot) {
751 slist[ns] = p;
752 }
753 if (ns < 2)
754 goto end_snapshot;
755 slist[ns] = NULL; /* add terminator */
756 /* in-place list quicksort using qsort(3C) */
757 qsort(slist, ns, sizeof (be_snapshot_list_t *),
758 be_qsort_compare_snapshots);
759 /* rewrite list pointer chain, including terminator */
760 ptrlist[ibe]->be_node_snapshots = slist[0];
761 for (k = 0; k < ns; k++)
762 slist[k]->be_next_snapshot = slist[k + 1];
763 end_snapshot:
764 free(slist);
765 }
766 /* sort subordinate datasets */
767 if (ptrlist[ibe]->be_node_num_datasets > 1) {
768 const size_t nmax = ptrlist[ibe]->be_node_num_datasets;
769 be_dataset_list_t ** const slist =
770 malloc(sizeof (be_dataset_list_t *) * (nmax + 1));
771 be_dataset_list_t *p;
772
773 if (slist == NULL) {
774 ret = BE_ERR_NOMEM;
775 continue;
776 }
777 /* build array of linked list dataset struct ptrs */
778 for (ns = 0, p = ptrlist[ibe]->be_node_datasets;
779 ns < nmax && p != NULL;
780 ns++, p = p->be_next_dataset) {
781 slist[ns] = p;
782 }
783 if (ns < 2) /* subordinate datasets < 2 - no sort */
784 goto end_dataset;
785 slist[ns] = NULL; /* add terminator */
786 /* in-place list quicksort using qsort(3C) */
787 qsort(slist, ns, sizeof (be_dataset_list_t *),
788 be_qsort_compare_datasets);
789 /* rewrite list pointer chain, including terminator */
790 ptrlist[ibe]->be_node_datasets = slist[0];
791 for (k = 0; k < ns; k++)
792 slist[k]->be_next_dataset = slist[k + 1];
793 end_dataset:
794 free(slist);
795 }
796 }
797 free:
798 free(ptrlist);
799 return (ret);
800 }
801
802 /*
803 * Function: be_qsort_compare_BEs_date
804 * Description: compare BE creation times for qsort(3C)
805 * will sort BE list from oldest to most recent
806 * Parameters:
807 * x,y - BEs with names to compare
808 * Returns:
809 * positive if x>y, negative if y>x, 0 if equal
810 * Scope:
811 * Private
812 */
813 static int
be_qsort_compare_BEs_date(const void * x,const void * y)814 be_qsort_compare_BEs_date(const void *x, const void *y)
815 {
816 be_node_list_t *p = *(be_node_list_t **)x;
817 be_node_list_t *q = *(be_node_list_t **)y;
818
819 assert(p != NULL);
820 assert(q != NULL);
821
822 if (p->be_node_creation > q->be_node_creation)
823 return (1);
824 if (p->be_node_creation < q->be_node_creation)
825 return (-1);
826 return (0);
827 }
828
829 /*
830 * Function: be_qsort_compare_BEs_date_rev
831 * Description: compare BE creation times for qsort(3C)
832 * will sort BE list from recent to oldest
833 * Parameters:
834 * x,y - BEs with names to compare
835 * Returns:
836 * positive if y>x, negative if x>y, 0 if equal
837 * Scope:
838 * Private
839 */
840 static int
be_qsort_compare_BEs_date_rev(const void * x,const void * y)841 be_qsort_compare_BEs_date_rev(const void *x, const void *y)
842 {
843 return (be_qsort_compare_BEs_date(y, x));
844 }
845
846 /*
847 * Function: be_qsort_compare_BEs_name
848 * Description: lexical compare of BE names for qsort(3C)
849 * Parameters:
850 * x,y - BEs with names to compare
851 * Returns:
852 * positive if x>y, negative if y>x, 0 if equal
853 * Scope:
854 * Private
855 */
856 static int
be_qsort_compare_BEs_name(const void * x,const void * y)857 be_qsort_compare_BEs_name(const void *x, const void *y)
858 {
859 be_node_list_t *p = *(be_node_list_t **)x;
860 be_node_list_t *q = *(be_node_list_t **)y;
861
862 assert(p != NULL);
863 assert(p->be_node_name != NULL);
864 assert(q != NULL);
865 assert(q->be_node_name != NULL);
866
867 return (strcmp(p->be_node_name, q->be_node_name));
868 }
869
870 /*
871 * Function: be_qsort_compare_BEs_name_rev
872 * Description: reverse lexical compare of BE names for qsort(3C)
873 * Parameters:
874 * x,y - BEs with names to compare
875 * Returns:
876 * positive if y>x, negative if x>y, 0 if equal
877 * Scope:
878 * Private
879 */
880 static int
be_qsort_compare_BEs_name_rev(const void * x,const void * y)881 be_qsort_compare_BEs_name_rev(const void *x, const void *y)
882 {
883 return (be_qsort_compare_BEs_name(y, x));
884 }
885
886 /*
887 * Function: be_qsort_compare_BEs_space
888 * Description: compare BE sizes for qsort(3C)
889 * will sort BE list in growing order
890 * Parameters:
891 * x,y - BEs with names to compare
892 * Returns:
893 * positive if x>y, negative if y>x, 0 if equal
894 * Scope:
895 * Private
896 */
897 static int
be_qsort_compare_BEs_space(const void * x,const void * y)898 be_qsort_compare_BEs_space(const void *x, const void *y)
899 {
900 be_node_list_t *p = *(be_node_list_t **)x;
901 be_node_list_t *q = *(be_node_list_t **)y;
902
903 assert(p != NULL);
904 assert(q != NULL);
905
906 if (p->be_space_used > q->be_space_used)
907 return (1);
908 if (p->be_space_used < q->be_space_used)
909 return (-1);
910 return (0);
911 }
912
913 /*
914 * Function: be_qsort_compare_BEs_space_rev
915 * Description: compare BE sizes for qsort(3C)
916 * will sort BE list in shrinking
917 * Parameters:
918 * x,y - BEs with names to compare
919 * Returns:
920 * positive if y>x, negative if x>y, 0 if equal
921 * Scope:
922 * Private
923 */
924 static int
be_qsort_compare_BEs_space_rev(const void * x,const void * y)925 be_qsort_compare_BEs_space_rev(const void *x, const void *y)
926 {
927 return (be_qsort_compare_BEs_space(y, x));
928 }
929
930 /*
931 * Function: be_qsort_compare_snapshots
932 * Description: lexical compare of BE names for qsort(3C)
933 * Parameters:
934 * x,y - BE snapshots with names to compare
935 * Returns:
936 * positive if y>x, negative if x>y, 0 if equal
937 * Scope:
938 * Private
939 */
940 static int
be_qsort_compare_snapshots(const void * x,const void * y)941 be_qsort_compare_snapshots(const void *x, const void *y)
942 {
943 be_snapshot_list_t *p = *(be_snapshot_list_t **)x;
944 be_snapshot_list_t *q = *(be_snapshot_list_t **)y;
945
946 if (p == NULL || p->be_snapshot_name == NULL)
947 return (1);
948 if (q == NULL || q->be_snapshot_name == NULL)
949 return (-1);
950 return (strcmp(p->be_snapshot_name, q->be_snapshot_name));
951 }
952
953 /*
954 * Function: be_qsort_compare_datasets
955 * Description: lexical compare of dataset names for qsort(3C)
956 * Parameters:
957 * x,y - BE snapshots with names to compare
958 * Returns:
959 * positive if y>x, negative if x>y, 0 if equal
960 * Scope:
961 * Private
962 */
963 static int
be_qsort_compare_datasets(const void * x,const void * y)964 be_qsort_compare_datasets(const void *x, const void *y)
965 {
966 be_dataset_list_t *p = *(be_dataset_list_t **)x;
967 be_dataset_list_t *q = *(be_dataset_list_t **)y;
968
969 if (p == NULL || p->be_dataset_name == NULL)
970 return (1);
971 if (q == NULL || q->be_dataset_name == NULL)
972 return (-1);
973 return (strcmp(p->be_dataset_name, q->be_dataset_name));
974 }
975
976 /*
977 * Function: be_get_node_data
978 * Description: Helper function used to collect all the information to fill
979 * in the be_node_list structure to be returned by be_list.
980 * Parameters:
981 * zhp - Handle to the root dataset for the BE whose information
982 * we're collecting.
983 * be_node - a pointer to the node structure we're filling in.
984 * be_name - The BE name of the node whose information we're
985 * collecting.
986 * current_be - the name of the currently active BE.
987 * be_ds - The dataset name for the BE.
988 *
989 * Returns:
990 * BE_SUCCESS - Success
991 * be_errno_t - Failure
992 * Scope:
993 * Private
994 */
995 static int
be_get_node_data(zfs_handle_t * zhp,be_node_list_t * be_node,char * be_name,const char * rpool,char * current_be,char * be_ds)996 be_get_node_data(
997 zfs_handle_t *zhp,
998 be_node_list_t *be_node,
999 char *be_name,
1000 const char *rpool,
1001 char *current_be,
1002 char *be_ds)
1003 {
1004 char prop_buf[MAXPATHLEN];
1005 nvlist_t *userprops = NULL;
1006 nvlist_t *propval = NULL;
1007 nvlist_t *zone_propval = NULL;
1008 char *prop_str = NULL;
1009 char *zone_prop_str = NULL;
1010 char *grub_default_bootfs = NULL;
1011 zpool_handle_t *zphp = NULL;
1012 int err = 0;
1013
1014 if (be_node == NULL || be_name == NULL || current_be == NULL ||
1015 be_ds == NULL) {
1016 be_print_err(gettext("be_get_node_data: invalid arguments, "
1017 "can not be NULL\n"));
1018 return (BE_ERR_INVAL);
1019 }
1020
1021 errno = 0;
1022
1023 be_node->be_root_ds = strdup(be_ds);
1024 if ((err = errno) != 0 || be_node->be_root_ds == NULL) {
1025 be_print_err(gettext("be_get_node_data: failed to "
1026 "copy root dataset name\n"));
1027 return (errno_to_be_err(err));
1028 }
1029
1030 be_node->be_node_name = strdup(be_name);
1031 if ((err = errno) != 0 || be_node->be_node_name == NULL) {
1032 be_print_err(gettext("be_get_node_data: failed to "
1033 "copy BE name\n"));
1034 return (errno_to_be_err(err));
1035 }
1036 if (strncmp(be_name, current_be, MAXPATHLEN) == 0)
1037 be_node->be_active = B_TRUE;
1038 else
1039 be_node->be_active = B_FALSE;
1040
1041 be_node->be_rpool = strdup(rpool);
1042 if (be_node->be_rpool == NULL || (err = errno) != 0) {
1043 be_print_err(gettext("be_get_node_data: failed to "
1044 "copy root pool name\n"));
1045 return (errno_to_be_err(err));
1046 }
1047
1048 be_node->be_space_used = zfs_prop_get_int(zhp, ZFS_PROP_USED);
1049
1050 if (getzoneid() == GLOBAL_ZONEID) {
1051 if ((zphp = zpool_open(g_zfs, rpool)) == NULL) {
1052 be_print_err(gettext("be_get_node_data: failed to open "
1053 "pool (%s): %s\n"), rpool,
1054 libzfs_error_description(g_zfs));
1055 return (zfs_err_to_be_err(g_zfs));
1056 }
1057
1058 (void) zpool_get_prop(zphp, ZPOOL_PROP_BOOTFS, prop_buf,
1059 ZFS_MAXPROPLEN, NULL, B_FALSE);
1060 if (be_has_grub() && (be_default_grub_bootfs(rpool,
1061 &grub_default_bootfs) == BE_SUCCESS) &&
1062 grub_default_bootfs != NULL)
1063 if (strcmp(grub_default_bootfs, be_ds) == 0)
1064 be_node->be_active_on_boot = B_TRUE;
1065 else
1066 be_node->be_active_on_boot = B_FALSE;
1067 else if (prop_buf != NULL && strcmp(prop_buf, be_ds) == 0)
1068 be_node->be_active_on_boot = B_TRUE;
1069 else
1070 be_node->be_active_on_boot = B_FALSE;
1071
1072 be_node->be_global_active = B_TRUE;
1073
1074 free(grub_default_bootfs);
1075 zpool_close(zphp);
1076 } else {
1077 if (be_zone_compare_uuids(be_node->be_root_ds))
1078 be_node->be_global_active = B_TRUE;
1079 else
1080 be_node->be_global_active = B_FALSE;
1081 }
1082
1083 /*
1084 * If the dataset is mounted use the mount point
1085 * returned from the zfs_is_mounted call. If the
1086 * dataset is not mounted then pull the mount
1087 * point information out of the zfs properties.
1088 */
1089 be_node->be_mounted = zfs_is_mounted(zhp,
1090 &(be_node->be_mntpt));
1091 if (!be_node->be_mounted) {
1092 if (zfs_prop_get(zhp, ZFS_PROP_MOUNTPOINT, prop_buf,
1093 ZFS_MAXPROPLEN, NULL, NULL, 0, B_FALSE) == 0)
1094 be_node->be_mntpt = strdup(prop_buf);
1095 else
1096 return (zfs_err_to_be_err(g_zfs));
1097 }
1098
1099 be_node->be_node_creation = (time_t)zfs_prop_get_int(zhp,
1100 ZFS_PROP_CREATION);
1101
1102 /* Get all user properties used for libbe */
1103 if ((userprops = zfs_get_user_props(zhp)) == NULL) {
1104 be_node->be_policy_type = strdup(be_default_policy());
1105 } else {
1106 if (getzoneid() != GLOBAL_ZONEID) {
1107 if (nvlist_lookup_nvlist(userprops,
1108 BE_ZONE_ACTIVE_PROPERTY, &zone_propval) != 0 ||
1109 zone_propval == NULL) {
1110 be_node->be_active_on_boot = B_FALSE;
1111 } else {
1112 verify(nvlist_lookup_string(zone_propval,
1113 ZPROP_VALUE, &zone_prop_str) == 0);
1114 if (strcmp(zone_prop_str, "on") == 0) {
1115 be_node->be_active_on_boot = B_TRUE;
1116 } else {
1117 be_node->be_active_on_boot = B_FALSE;
1118 }
1119 }
1120 }
1121
1122 if (nvlist_lookup_nvlist(userprops, BE_POLICY_PROPERTY,
1123 &propval) != 0 || propval == NULL) {
1124 be_node->be_policy_type =
1125 strdup(be_default_policy());
1126 } else {
1127 verify(nvlist_lookup_string(propval, ZPROP_VALUE,
1128 &prop_str) == 0);
1129 if (prop_str == NULL || strcmp(prop_str, "-") == 0 ||
1130 strcmp(prop_str, "") == 0)
1131 be_node->be_policy_type =
1132 strdup(be_default_policy());
1133 else
1134 be_node->be_policy_type = strdup(prop_str);
1135 }
1136 if (getzoneid() != GLOBAL_ZONEID) {
1137 if (nvlist_lookup_nvlist(userprops,
1138 BE_ZONE_PARENTBE_PROPERTY, &propval) != 0 &&
1139 nvlist_lookup_string(propval, ZPROP_VALUE,
1140 &prop_str) == 0) {
1141 be_node->be_uuid_str = strdup(prop_str);
1142 }
1143 } else {
1144 if (nvlist_lookup_nvlist(userprops, BE_UUID_PROPERTY,
1145 &propval) == 0 && nvlist_lookup_string(propval,
1146 ZPROP_VALUE, &prop_str) == 0) {
1147 be_node->be_uuid_str = strdup(prop_str);
1148 }
1149 }
1150 }
1151
1152 /*
1153 * Increment the dataset counter to include the root dataset
1154 * of the BE.
1155 */
1156 be_node->be_node_num_datasets++;
1157
1158 return (BE_SUCCESS);
1159 }
1160
1161 /*
1162 * Function: be_get_ds_data
1163 * Description: Helper function used by be_add_children_callback to collect
1164 * the dataset related information that will be returned by
1165 * be_list.
1166 * Parameters:
1167 * zhp - Handle to the zfs dataset whose information we're
1168 * collecting.
1169 * name - The name of the dataset we're processing.
1170 * dataset - A pointer to the be_dataset_list structure
1171 * we're filling in.
1172 * node - The node structure that this dataset belongs to.
1173 * Return:
1174 * BE_SUCCESS - Success
1175 * be_errno_t - Failure
1176 * Scope:
1177 * Private
1178 */
1179 static int
be_get_ds_data(zfs_handle_t * zfshp,char * name,be_dataset_list_t * dataset,be_node_list_t * node)1180 be_get_ds_data(
1181 zfs_handle_t *zfshp,
1182 char *name,
1183 be_dataset_list_t *dataset,
1184 be_node_list_t *node)
1185 {
1186 char prop_buf[ZFS_MAXPROPLEN];
1187 nvlist_t *propval = NULL;
1188 nvlist_t *userprops = NULL;
1189 char *prop_str = NULL;
1190 int err = 0;
1191
1192 if (zfshp == NULL || name == NULL || dataset == NULL || node == NULL) {
1193 be_print_err(gettext("be_get_ds_data: invalid arguments, "
1194 "can not be NULL\n"));
1195 return (BE_ERR_INVAL);
1196 }
1197
1198 errno = 0;
1199
1200 dataset->be_dataset_name = strdup(name);
1201 if ((err = errno) != 0) {
1202 be_print_err(gettext("be_get_ds_data: failed to copy "
1203 "dataset name\n"));
1204 return (errno_to_be_err(err));
1205 }
1206
1207 dataset->be_ds_space_used = zfs_prop_get_int(zfshp, ZFS_PROP_USED);
1208
1209 /*
1210 * If the dataset is mounted use the mount point
1211 * returned from the zfs_is_mounted call. If the
1212 * dataset is not mounted then pull the mount
1213 * point information out of the zfs properties.
1214 */
1215 if (!(dataset->be_ds_mounted = zfs_is_mounted(zfshp,
1216 &(dataset->be_ds_mntpt)))) {
1217 if (zfs_prop_get(zfshp, ZFS_PROP_MOUNTPOINT,
1218 prop_buf, ZFS_MAXPROPLEN, NULL, NULL, 0,
1219 B_FALSE) == 0)
1220 dataset->be_ds_mntpt = strdup(prop_buf);
1221 else
1222 return (zfs_err_to_be_err(g_zfs));
1223 }
1224 dataset->be_ds_creation =
1225 (time_t)zfs_prop_get_int(zfshp, ZFS_PROP_CREATION);
1226
1227 /*
1228 * Get the user property used for the libbe
1229 * cleaup policy
1230 */
1231 if ((userprops = zfs_get_user_props(zfshp)) == NULL) {
1232 dataset->be_ds_plcy_type =
1233 strdup(node->be_policy_type);
1234 } else {
1235 if (nvlist_lookup_nvlist(userprops,
1236 BE_POLICY_PROPERTY, &propval) != 0 ||
1237 propval == NULL) {
1238 dataset->be_ds_plcy_type =
1239 strdup(node->be_policy_type);
1240 } else {
1241 verify(nvlist_lookup_string(propval,
1242 ZPROP_VALUE, &prop_str) == 0);
1243 if (prop_str == NULL ||
1244 strcmp(prop_str, "-") == 0 ||
1245 strcmp(prop_str, "") == 0)
1246 dataset->be_ds_plcy_type
1247 = strdup(node->be_policy_type);
1248 else
1249 dataset->be_ds_plcy_type = strdup(prop_str);
1250 }
1251 }
1252
1253 node->be_node_num_datasets++;
1254 return (BE_SUCCESS);
1255 }
1256
1257 /*
1258 * Function: be_get_ss_data
1259 * Description: Helper function used by be_add_children_callback to collect
1260 * the dataset related information that will be returned by
1261 * be_list.
1262 * Parameters:
1263 * zhp - Handle to the zfs snapshot whose information we're
1264 * collecting.
1265 * name - The name of the snapshot we're processing.
1266 * shapshot - A pointer to the be_snapshot_list structure
1267 * we're filling in.
1268 * node - The node structure that this snapshot belongs to.
1269 * Returns:
1270 * BE_SUCCESS - Success
1271 * be_errno_t - Failure
1272 * Scope:
1273 * Private
1274 */
1275 static int
be_get_ss_data(zfs_handle_t * zfshp,char * name,be_snapshot_list_t * snapshot,be_node_list_t * node)1276 be_get_ss_data(
1277 zfs_handle_t *zfshp,
1278 char *name,
1279 be_snapshot_list_t *snapshot,
1280 be_node_list_t *node)
1281 {
1282 nvlist_t *propval = NULL;
1283 nvlist_t *userprops = NULL;
1284 char *prop_str = NULL;
1285 int err = 0;
1286
1287 if (zfshp == NULL || name == NULL || snapshot == NULL || node == NULL) {
1288 be_print_err(gettext("be_get_ss_data: invalid arguments, "
1289 "can not be NULL\n"));
1290 return (BE_ERR_INVAL);
1291 }
1292
1293 errno = 0;
1294
1295 snapshot->be_snapshot_name = strdup(name);
1296 if ((err = errno) != 0) {
1297 be_print_err(gettext("be_get_ss_data: failed to copy name\n"));
1298 return (errno_to_be_err(err));
1299 }
1300
1301 snapshot->be_snapshot_creation = (time_t)zfs_prop_get_int(zfshp,
1302 ZFS_PROP_CREATION);
1303
1304 /*
1305 * Try to get this snapshot's cleanup policy from its
1306 * user properties first. If not there, use default
1307 * cleanup policy.
1308 */
1309 if ((userprops = zfs_get_user_props(zfshp)) != NULL &&
1310 nvlist_lookup_nvlist(userprops, BE_POLICY_PROPERTY,
1311 &propval) == 0 && nvlist_lookup_string(propval,
1312 ZPROP_VALUE, &prop_str) == 0) {
1313 snapshot->be_snapshot_type =
1314 strdup(prop_str);
1315 } else {
1316 snapshot->be_snapshot_type =
1317 strdup(be_default_policy());
1318 }
1319
1320 snapshot->be_snapshot_space_used = zfs_prop_get_int(zfshp,
1321 ZFS_PROP_USED);
1322
1323 node->be_node_num_snapshots++;
1324 return (BE_SUCCESS);
1325 }
1326
1327 /*
1328 * Function: be_list_alloc
1329 * Description: Helper function used to allocate memory for the various
1330 * sructures that make up a BE node.
1331 * Parameters:
1332 * err - Used to return any errors encountered.
1333 * BE_SUCCESS - Success
1334 * BE_ERR_NOMEM - Allocation failure
1335 * size - The size of memory to allocate.
1336 * Returns:
1337 * Success - A pointer to the allocated memory
1338 * Failure - NULL
1339 * Scope:
1340 * Private
1341 */
1342 static void*
be_list_alloc(int * err,size_t size)1343 be_list_alloc(int *err, size_t size)
1344 {
1345 void *bep = NULL;
1346
1347 bep = calloc(1, size);
1348 if (bep == NULL) {
1349 be_print_err(gettext("be_list_alloc: memory "
1350 "allocation failed\n"));
1351 *err = BE_ERR_NOMEM;
1352 }
1353 *err = BE_SUCCESS;
1354 return (bep);
1355 }
1356
1357 /*
1358 * Function: be_get_zone_node_data
1359 * Description: Helper function used to collect all the information to
1360 * fill in the be_node_list structure to be returned by
1361 * be_get_zone_list.
1362 * Parameters:
1363 * be_node - a pointer to the node structure we're filling in.
1364 * be_name - The BE name of the node whose information we're
1365 * Returns:
1366 * BE_SUCCESS - Success
1367 * be_errno_t - Failure
1368 * Scope:
1369 * Private
1370 *
1371 * NOTE: This function currently only collects the zone BE name but when
1372 * support for beadm/libbe in a zone is provided it will need to fill
1373 * in the rest of the information needed for a zone BE.
1374 */
1375 static int
be_get_zone_node_data(be_node_list_t * be_node,char * be_name)1376 be_get_zone_node_data(be_node_list_t *be_node, char *be_name)
1377 {
1378 if ((be_node->be_node_name = strdup(be_name)) != NULL)
1379 return (BE_SUCCESS);
1380 return (BE_ERR_NOMEM);
1381 }
1382