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 */
30
31 #include <assert.h>
32 #include <libintl.h>
33 #include <libnvpair.h>
34 #include <libzfs.h>
35 #include <stdio.h>
36 #include <stdlib.h>
37 #include <string.h>
38 #include <strings.h>
39 #include <sys/types.h>
40 #include <sys/stat.h>
41 #include <unistd.h>
42 #include <errno.h>
43
44 #include <libbe.h>
45 #include <libbe_priv.h>
46
47 /*
48 * Callback data used for zfs_iter calls.
50 typedef struct list_callback_data {
51 char *zpool_name;
52 char *be_name;
53 be_node_list_t *be_nodes_head;
54 be_node_list_t *be_nodes;
55 char current_be[MAXPATHLEN];
56 } list_callback_data_t;
57
58 /*
59 * Private function prototypes
60 */
61 static int be_add_children_callback(zfs_handle_t *zhp, void *data);
62 static int be_get_list_callback(zpool_handle_t *, void *);
63 static int be_get_node_data(zfs_handle_t *, be_node_list_t *, char *,
64 const char *, char *, char *);
65 static int be_get_zone_node_data(be_node_list_t *, char *);
66 static int be_get_ds_data(zfs_handle_t *, char *, be_dataset_list_t *,
67 be_node_list_t *);
68 static int be_get_ss_data(zfs_handle_t *, char *, be_snapshot_list_t *,
69 be_node_list_t *);
70 static void be_sort_list(be_node_list_t **,
71 int (*)(const void *, const void *));
72 static int be_qsort_compare_BEs_name(const void *, const void *);
73 static int be_qsort_compare_BEs_name_rev(const void *, const void *);
74 static int be_qsort_compare_BEs_date(const void *, const void *);
75 static int be_qsort_compare_BEs_date_rev(const void *, const void *);
76 static int be_qsort_compare_BEs_space(const void *, const void *);
77 static int be_qsort_compare_BEs_space_rev(const void *, const void *);
78 static int be_qsort_compare_snapshots(const void *x, const void *y);
79 static int be_qsort_compare_datasets(const void *x, const void *y);
80 static void *be_list_alloc(int *, size_t);
81
82 /*
83 * Private data.
84 */
85 static char be_container_ds[MAXPATHLEN];
86 static boolean_t zone_be = B_FALSE;
87
88 /* ******************************************************************** */
89 /* Public Functions */
90 /* ******************************************************************** */
126 if (!be_valid_be_name(be_name)) {
127 be_print_err(gettext("be_list: "
128 "invalid BE name %s\n"), be_name);
129 return (BE_ERR_INVAL);
130 }
131 }
132
133 ret = _be_list(be_name, be_nodes);
134
135 be_zfs_fini();
136
137 return (ret);
138 }
139
140 /*
141 * Function: be_sort
142 * Description: Sort BE node list
143 * Parameters:
144 * pointer to address of list head
145 * sort order type
146 * Returns:
147 * nothing
148 * Side effect:
149 * node list sorted by name
150 * Scope:
151 * Public
152 */
153 void
154 be_sort(be_node_list_t **be_nodes, int order)
155 {
156 int (*compar)(const void *, const void *) = be_qsort_compare_BEs_date;
157
158 if (be_nodes == NULL)
159 return;
160
161 switch (order) {
162 case BE_SORT_UNSPECIFIED:
163 case BE_SORT_DATE:
164 compar = be_qsort_compare_BEs_date;
165 break;
166 case BE_SORT_DATE_REV:
167 compar = be_qsort_compare_BEs_date_rev;
168 break;
169 case BE_SORT_NAME:
170 compar = be_qsort_compare_BEs_name;
171 break;
172 case BE_SORT_NAME_REV:
173 compar = be_qsort_compare_BEs_name_rev;
174 break;
175 case BE_SORT_SPACE:
176 compar = be_qsort_compare_BEs_space;
177 break;
178 case BE_SORT_SPACE_REV:
179 compar = be_qsort_compare_BEs_space_rev;
180 break;
181 default:
182 be_print_err(gettext("be_sort: invalid sort order %d\n"),
183 order);
184 return;
185 }
186
187 be_sort_list(be_nodes, compar);
188 }
189
190 /* ******************************************************************** */
191 /* Semi-Private Functions */
192 /* ******************************************************************** */
193
194 /*
195 * Function: _be_list
196 * Description: This does the actual work described in be_list.
197 * Parameters:
198 * be_name - The name of the BE to look up.
199 * If NULL a list of all BEs will be returned.
200 * be_nodes - A reference pointer to the list of BEs. The list
201 * structure will be allocated here and must
202 * be freed by a call to be_free_list. If there are no
203 * BEs found on the system this reference will be
204 * set to NULL.
205 * Return:
206 * BE_SUCCESS - Success
207 * be_errno_t - Failure
208 * Scope:
209 * Semi-private (library wide use only)
210 */
211 int
212 _be_list(char *be_name, be_node_list_t **be_nodes)
213 {
214 list_callback_data_t cb = { 0 };
215 be_transaction_data_t bt = { 0 };
216 int ret = BE_SUCCESS;
217 zpool_handle_t *zphp;
218 char *rpool = NULL;
219 struct be_defaults be_defaults;
220
221 if (be_nodes == NULL)
222 return (BE_ERR_INVAL);
223
224 be_get_defaults(&be_defaults);
225
226 if (be_find_current_be(&bt) != BE_SUCCESS) {
227 /*
228 * We were unable to find a currently booted BE which
229 * probably means that we're not booted in a BE envoronment.
230 * None of the BE's will be marked as the active BE.
231 */
232 (void) strcpy(cb.current_be, "-");
233 } else {
234 (void) strncpy(cb.current_be, bt.obe_name,
235 sizeof (cb.current_be));
236 rpool = bt.obe_zpool;
260 cb.be_nodes_head = NULL;
261 cb.be_nodes = NULL;
262 }
263 ret = BE_ERR_BE_NOENT;
264 }
265 }
266
267 if (cb.be_nodes_head == NULL) {
268 if (be_name != NULL)
269 be_print_err(gettext("be_list: BE (%s) does not "
270 "exist\n"), be_name);
271 else
272 be_print_err(gettext("be_list: No BE's found\n"));
273 ret = BE_ERR_BE_NOENT;
274 }
275
276 *be_nodes = cb.be_nodes_head;
277
278 free(cb.be_name);
279
280 be_sort(be_nodes, BE_SORT_DATE);
281
282 return (ret);
283 }
284
285 /*
286 * Function: be_free_list
287 * Description: Frees up all the data allocated for the list of BEs,
288 * datasets and snapshots returned by be_list.
289 * Parameters:
290 * be_node - be_nodes_t structure returned from call to be_list.
291 * Returns:
292 * none
293 * Scope:
294 * Semi-private (library wide use only)
295 */
296 void
297 be_free_list(be_node_list_t *be_nodes)
298 {
299 be_node_list_t *temp_node = NULL;
300 be_node_list_t *list = be_nodes;
301
302 while (list != NULL) {
667 return (ret);
668 }
669 }
670 ret = zfs_iter_children(zhp, be_add_children_callback, cb);
671 if (ret != 0) {
672 be_print_err(gettext("be_add_children_callback: "
673 "encountered error: %s\n"),
674 libzfs_error_description(g_zfs));
675 ret = zfs_err_to_be_err(g_zfs);
676 }
677 ZFS_CLOSE(zhp);
678 return (ret);
679 }
680
681 /*
682 * Function: be_sort_list
683 * Description: Sort BE node list
684 * Parameters:
685 * pointer to address of list head
686 * compare function
687 * Returns:
688 * nothing
689 * Side effect:
690 * node list sorted by name
691 * Scope:
692 * Private
693 */
694 static void
695 be_sort_list(be_node_list_t **pstart, int (*compar)(const void *, const void *))
696 {
697 size_t ibe, nbe;
698 be_node_list_t *p = NULL;
699 be_node_list_t **ptrlist = NULL;
700
701 if (pstart == NULL)
702 return;
703 /* build array of linked list BE struct pointers */
704 for (p = *pstart, nbe = 0; p != NULL; nbe++, p = p->be_next_node) {
705 ptrlist = realloc(ptrlist,
706 sizeof (be_node_list_t *) * (nbe + 2));
707 ptrlist[nbe] = p;
708 }
709 if (nbe == 0)
710 return;
711 /* in-place list quicksort using qsort(3C) */
712 if (nbe > 1) /* no sort if less than 2 BEs */
713 qsort(ptrlist, nbe, sizeof (be_node_list_t *), compar);
714
715 ptrlist[nbe] = NULL; /* add linked list terminator */
716 *pstart = ptrlist[0]; /* set new linked list header */
717 /* for each BE in list */
718 for (ibe = 0; ibe < nbe; ibe++) {
719 size_t k, ns; /* subordinate index, count */
720
721 /* rewrite list pointer chain, including terminator */
722 ptrlist[ibe]->be_next_node = ptrlist[ibe + 1];
723 /* sort subordinate snapshots */
724 if (ptrlist[ibe]->be_node_num_snapshots > 1) {
725 const size_t nmax = ptrlist[ibe]->be_node_num_snapshots;
726 be_snapshot_list_t ** const slist =
727 malloc(sizeof (be_snapshot_list_t *) * (nmax + 1));
728 be_snapshot_list_t *p;
729
730 if (slist == NULL)
731 continue;
732 /* build array of linked list snapshot struct ptrs */
733 for (ns = 0, p = ptrlist[ibe]->be_node_snapshots;
734 ns < nmax && p != NULL;
735 ns++, p = p->be_next_snapshot) {
736 slist[ns] = p;
737 }
738 if (ns < 2)
739 goto end_snapshot;
740 slist[ns] = NULL; /* add terminator */
741 /* in-place list quicksort using qsort(3C) */
742 qsort(slist, ns, sizeof (be_snapshot_list_t *),
743 be_qsort_compare_snapshots);
744 /* rewrite list pointer chain, including terminator */
745 ptrlist[ibe]->be_node_snapshots = slist[0];
746 for (k = 0; k < ns; k++)
747 slist[k]->be_next_snapshot = slist[k + 1];
748 end_snapshot:
749 free(slist);
750 }
751 /* sort subordinate datasets */
752 if (ptrlist[ibe]->be_node_num_datasets > 1) {
753 const size_t nmax = ptrlist[ibe]->be_node_num_datasets;
754 be_dataset_list_t ** const slist =
755 malloc(sizeof (be_dataset_list_t *) * (nmax + 1));
756 be_dataset_list_t *p;
757
758 if (slist == NULL)
759 continue;
760 /* build array of linked list dataset struct ptrs */
761 for (ns = 0, p = ptrlist[ibe]->be_node_datasets;
762 ns < nmax && p != NULL;
763 ns++, p = p->be_next_dataset) {
764 slist[ns] = p;
765 }
766 if (ns < 2) /* subordinate datasets < 2 - no sort */
767 goto end_dataset;
768 slist[ns] = NULL; /* add terminator */
769 /* in-place list quicksort using qsort(3C) */
770 qsort(slist, ns, sizeof (be_dataset_list_t *),
771 be_qsort_compare_datasets);
772 /* rewrite list pointer chain, including terminator */
773 ptrlist[ibe]->be_node_datasets = slist[0];
774 for (k = 0; k < ns; k++)
775 slist[k]->be_next_dataset = slist[k + 1];
776 end_dataset:
777 free(slist);
778 }
779 }
780 free:
781 free(ptrlist);
782 }
783
784 /*
785 * Function: be_qsort_compare_BEs_date
786 * Description: compare BE creation times for qsort(3C)
787 * will sort BE list from oldest to most recent
788 * Parameters:
789 * x,y - BEs with names to compare
790 * Returns:
791 * positive if x>y, negative if y>x, 0 if equal
792 * Scope:
793 * Private
794 */
795 static int
796 be_qsort_compare_BEs_date(const void *x, const void *y)
797 {
798 be_node_list_t *p = *(be_node_list_t **)x;
799 be_node_list_t *q = *(be_node_list_t **)y;
800
801 assert(p != NULL);
|
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.
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 /* ******************************************************************** */
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
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
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;
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
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) {
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
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
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);
|