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