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