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